Funkel AIDevelopersDashboard ↗

DEVELOPER GUIDE

MCP server

Connect an AI client to your products, leads, campaigns, inbox, and Operator tools.

Connection methods

Connect to https://api.funkel.ai/mcp with a client that supports Streamable HTTP.

Use OAuth with PKCE, or send a personal access token through an Authorization: Bearer header.

Funkel AI publishes OAuth discovery and dynamic client registration. The authorization page asks for your personal access token.

OAuth access tokens last one hour. Reconnect when they expire. The server does not issue refresh tokens.

Revocation can take up to 60 seconds to affect cached MCP authentication.

Configure Cursor

Add this configuration to ~/.cursor/mcp.json. Set FUNKEL_API_TOKEN in the environment available to Cursor.

Enable the server in Cursor. Start with a read request, such as a summary of your selected product.

This configuration follows Cursor's documented remote-server format. Client availability depends on your client and workspace settings.

json
{
  "mcpServers": {
    "funkel": {
      "url": "https://api.funkel.ai/mcp",
      "headers": {
        "Authorization": "Bearer ${env:FUNKEL_API_TOKEN}"
      }
    }
  }
}

Configure an OAuth client

Add https://api.funkel.ai/mcp as a remote connector in your client's settings.

Open the authorization page and enter your personal access token. Complete the return to your client.

The server supports authorization_code with PKCE S256. Its OAuth scope is mcp.

Use HTTPS callback URLs, or HTTP loopback URLs for local clients. Authorization codes expire after five minutes.

Never paste your token into an ordinary chat message.

Select your product

Every tool call resolves a product. With one product, Funkel AI selects it automatically.

With multiple products, include app_id in the tool arguments. Use the product ID from GET /api/apps.

Without app_id, the error lists your products for selection. This also applies to list_apps.

app_id is a transport argument. The server accepts it even when the published tool schema omits it.

Create a product in the app before using tools if your account has none.

Make a read call

This cURL request demonstrates the wire format. Replace the product placeholder with an owned product ID.

bash
curl --fail-with-body https://api.funkel.ai/mcp \
  -H "Authorization: Bearer $FUNKEL_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_product_context","arguments":{"app_id":"<PRODUCT_ID>"}}}'

Approve writes in the browser

Every non-read tool requires separate browser approval. This includes paid searches and tools that save drafts or lists.

The tool returns pending_approval, a preview, an approval_url, and expires_in_seconds.

Open the approval URL in your own signed-in Funkel AI session. Review the product and exact action before approval.

Approval expires after ten minutes. Request a new action if the approval expires.

The client's approval button cannot replace this browser step. Never pass confirmation_token through MCP, even if a schema includes it.

Read the final action result before another attempt. Do not repeat an action when its result is unknown.

Example prompts

Start with a read. Then request a specific change with enough detail for review.

  • Summarize campaigns and sender health for product <PRODUCT_ID>.
  • Show the latest inbox conversations for product <PRODUCT_ID>.
  • Prepare a reply to conversation <CONVERSATION_ID> in product <PRODUCT_ID> for my review.
  • Prepare a pause for campaign <CAMPAIGN_ID> in product <PRODUCT_ID>.
  • Find matching saved leads in product <PRODUCT_ID> and explain the selection.

Tool behavior

The catalog below comes from the server's actual tools/list response. It includes input schemas, costs, and approval requirements.

Read each schema for required fields, allowed values, and limits. Availability also depends on connected accounts and product state.

The send_message cold outreach tool is unavailable through MCP. The send_conversation_reply tool can send an approved conversation reply.

Demo workspaces permit only reads with no credit or external effects.

Protocol and errors

The server advertises protocol version 2025-06-18. It supports initialize, notifications/initialized, ping, tools/list, and tools/call.

initialize and tools/list permit unauthenticated discovery. tools/call requires authentication. GET does not provide an SSE stream.

Requests use JSON-RPC 2.0. Tool errors can return HTTP 200 with result.isError set to true.

Read result.content text for details. Handler errors can include error_code and user_message.

Malformed JSON returns -32700. Invalid requests return -32600. Unknown methods return -32601. Invalid parameters return -32602.

Correct invalid_args, not_found, or product-scope errors before retrying. Check account limits after quota errors.

The JSON-RPC request body limit is 1 MiB. OAuth registration and form bodies have a 64 KiB limit.

Available tools

Inspect each tool’s input schema before you call it. Availability can depend on your plan and connected providers.

Include app_id when you have multiple products. Never send confirmation_token through MCP. Use browser approval.

51 of 51 tools

list_appsRead

List the products/apps owned by the request scope's user. Returns a summary (count, brief one-liner, and a list of {id, name, description, url}) with no timestamps or internal flags. Use this for product inventory or explicit product-switch/disambiguation questions. A normal product-scoped request already carries an app_id in Scope; do not call this just to discover which product to use for product-aware actions.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {},
  "type": "object"
}
get_product_contextRead

Read the selected product's name, site, description, ICP summary, language, Product Brain availability, and dashboard link. No provider credentials or raw unbounded configuration are returned.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {},
  "type": "object"
}
list_listsRead

List unarchived lead lists in the selected product. Returns exact total and bounded pages. A list's cached lead count is not used for the total.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "limit": {
      "description": "Page size (default 20; max 50)",
      "maximum": 50,
      "minimum": 1,
      "type": "integer"
    },
    "offset": {
      "description": "Page offset (default 0)",
      "maximum": 10000,
      "type": "integer"
    }
  },
  "type": "object"
}
get_listRead

Read one unarchived list in the selected product and its exact member count. Does not return contacts; use list_list_contacts.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "list_id": {
      "description": "List id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    }
  },
  "required": [
    "list_id"
  ],
  "type": "object"
}
list_list_contactsRead

List contacts in one unarchived list in the selected product. Returns exact total and bounded pages. Does not expose email or provider identifiers.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "limit": {
      "description": "Page size (default 20; max 50)",
      "maximum": 50,
      "minimum": 1,
      "type": "integer"
    },
    "list_id": {
      "description": "List id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "offset": {
      "description": "Page offset (default 0)",
      "maximum": 10000,
      "type": "integer"
    }
  },
  "required": [
    "list_id"
  ],
  "type": "object"
}
get_scheduleRead

List pending, approved, or failed scheduled actions in the selected product, optionally for one campaign. Returns one bounded page and its exact total. Completed actions are not included.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "campaign_id": {
      "description": "Optional campaign id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "limit": {
      "description": "Page size (default 20; max 50)",
      "maximum": 50,
      "minimum": 1,
      "type": "integer"
    },
    "offset": {
      "description": "Page offset (default 0)",
      "maximum": 10000,
      "type": "integer"
    }
  },
  "type": "object"
}
get_scheduled_actionRead

Read one action in the selected product: campaign, lead, type, state, scheduled and executed timestamps. Does not return provider metadata or a message body.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "action_id": {
      "description": "Scheduled action id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    }
  },
  "required": [
    "action_id"
  ],
  "type": "object"
}
list_remindersRead

List open or done lead reminders in the selected product with exact total and bounded pages. Default is open. This read does not complete a reminder.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "limit": {
      "description": "Page size (default 20; max 50)",
      "maximum": 50,
      "minimum": 1,
      "type": "integer"
    },
    "offset": {
      "description": "Page offset (default 0)",
      "maximum": 10000,
      "type": "integer"
    },
    "status": {
      "description": "Reminder state",
      "enum": [
        "open",
        "done"
      ],
      "type": "string"
    }
  },
  "type": "object"
}
list_insightsRead

List account-scoped and selected-product-scoped open insights. Each item labels its actual scope; account insights are not product-only. Exact total and bounded pages.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "limit": {
      "description": "Page size (default 20; max 50)",
      "maximum": 50,
      "minimum": 1,
      "type": "integer"
    },
    "offset": {
      "description": "Page offset (default 0)",
      "maximum": 10000,
      "type": "integer"
    }
  },
  "type": "object"
}
get_insightRead

Read one insight and its evidence for the selected product, or an explicitly account-scoped insight. Read-only; proposed changes never run here.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "insight_id": {
      "description": "Insight id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    }
  },
  "required": [
    "insight_id"
  ],
  "type": "object"
}
list_operator_tasksRead

List durable Operator tasks in the selected product. Returns bounded pages, exact total, task status, version, and links. Read-only.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "limit": {
      "description": "Page size (default 20; max 50)",
      "maximum": 50,
      "minimum": 1,
      "type": "integer"
    },
    "offset": {
      "description": "Page offset (default 0)",
      "maximum": 10000,
      "type": "integer"
    }
  },
  "type": "object"
}
get_operator_taskRead

Read one durable Operator task in the selected product with its step states, action states, safe summaries, version, and progress. Does not return executable arguments or raw provider errors.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "task_id": {
      "description": "Task id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    }
  },
  "required": [
    "task_id"
  ],
  "type": "object"
}
get_accessRead

Read current account access for Operator and campaign actions in the selected product. Operator requires active paid or lifetime entitlement; campaign actions also accept active beta. Feature flags are account-wide. This snapshot is not an action authorization or credit quote.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {},
  "type": "object"
}
create_noteBrowser approval

Create a scoped note or reminder after an explicit confirmation of the exact lead, body, and due date. One request_key can be applied only once; a changed intent with the same key fails.

Availability
Requires an owned lead
Cost
No product credits
Credits
none
External effects
none

Input schema

{
  "properties": {
    "body": {
      "description": "Note or reminder text (max 5000 chars)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "One-use approval token; omit on first call",
      "type": "string"
    },
    "lead_id": {
      "description": "Lead id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "reminder_at": {
      "description": "Optional RFC3339 reminder due date",
      "type": "string"
    },
    "reminder_body": {
      "description": "Required when reminder_at is set",
      "type": "string"
    },
    "request_key": {
      "description": "Stable unique request identity (8-128 chars)",
      "type": "string"
    }
  },
  "required": [
    "lead_id",
    "request_key",
    "body"
  ],
  "type": "object"
}
create_reminderBrowser approval

Create a scoped note or reminder after an explicit confirmation of the exact lead, body, and due date. One request_key can be applied only once; a changed intent with the same key fails.

Availability
Requires an owned lead
Cost
No product credits
Credits
none
External effects
none

Input schema

{
  "properties": {
    "body": {
      "description": "Note or reminder text (max 5000 chars)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "One-use approval token; omit on first call",
      "type": "string"
    },
    "lead_id": {
      "description": "Lead id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "reminder_at": {
      "description": "Required RFC3339 reminder due date",
      "type": "string"
    },
    "request_key": {
      "description": "Stable unique request identity (8-128 chars)",
      "type": "string"
    }
  },
  "required": [
    "lead_id",
    "request_key",
    "body",
    "reminder_at"
  ],
  "type": "object"
}
save_preferenceBrowser approval

Save one selected-product Operator preference after explicit approval. The value is bounded JSON data, not a system instruction. Existing keys update. No provider credentials or tokens are accepted.

Availability
Requires an owned product
Cost
No product credits
Credits
none
External effects
none

Input schema

{
  "properties": {
    "confirmation_token": {
      "description": "Approval token; omit on first call",
      "type": "string"
    },
    "key": {
      "description": "Preference key (1-100 chars; no secret names)",
      "type": "string"
    },
    "reason": {
      "description": "Why this preference should be saved",
      "type": "string"
    },
    "value": {
      "description": "JSON value (max 600 bytes)",
      "type": "string"
    }
  },
  "required": [
    "key",
    "value"
  ],
  "type": "object"
}
rename_listBrowser approval

Rename one unarchived list in the selected product after explicit approval. Supply its current name to reject stale changes; include the full new description.

Availability
Requires an owned list
Cost
No product credits
Credits
none
External effects
none

Input schema

{
  "properties": {
    "confirmation_token": {
      "description": "Approval token; omit on first call",
      "type": "string"
    },
    "description": {
      "description": "New full description",
      "type": "string"
    },
    "expected_name": {
      "description": "Current list name",
      "type": "string"
    },
    "list_id": {
      "description": "List id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "name": {
      "description": "New name (1-100 chars)",
      "type": "string"
    }
  },
  "required": [
    "list_id",
    "expected_name",
    "name",
    "description"
  ],
  "type": "object"
}
control_operator_taskBrowser approval

Pause, resume, cancel, or retry a durable Operator task after exact approval. Supply its current version. Retry also requires one failed idempotent local-read step; completed effects cannot replay. A pause may not stop an already executing provider call.

Availability
Requires a current task version
Cost
Future steps may have provider costs
Credits
none at tool call; future actions may have costs
External effects
may resume a queued action

Input schema

{
  "properties": {
    "confirmation_token": {
      "description": "One-use approval token; omit on first call",
      "type": "string"
    },
    "expected_version": {
      "description": "Current task version",
      "maximum": 2147483647,
      "minimum": 1,
      "type": "integer"
    },
    "operation": {
      "description": "Task transition",
      "enum": [
        "pause",
        "resume",
        "cancel",
        "retry"
      ],
      "type": "string"
    },
    "step_id": {
      "description": "Required failed step id for retry (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "task_id": {
      "description": "Task id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    }
  },
  "required": [
    "task_id",
    "operation",
    "expected_version"
  ],
  "type": "object"
}
list_agentsRead

List the specialist agents in the product/app the request is scoped to. Returns a summary (count, brief one-liner, and a list of {id, name, status, type, role, one-line icp_summary}). Internal agent types are mapped to product-facing roles such as lead_finder. Full ICP filters / config are collapsed to a one-liner — call get_agent (later) to load full detail. Use this to ground questions like 'how many specialist agents do I have?' or 'which Lead Finder agents are active?'.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {},
  "type": "object"
}
get_agent_sourcesRead

Read X and Hacker News listening settings for one owned agent, including sources not configured yet. Use list_agents to identify the agent. If configured is false, use configure_agent_source to propose exact searches and enable listening after approval. If configured is true and searches exist, use set_agent_source_listening to toggle without changing searches. A draft or paused agent does not collect until activated. LinkedIn signal groups are separate.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "agent_id": {
      "description": "Owned agent ID (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "app_id": {
      "description": "Product ID; required for MCP accounts with multiple products (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    }
  },
  "required": [
    "agent_id"
  ],
  "type": "object"
}
set_agent_source_listeningBrowser approval

Pause or resume only an existing X or Hacker News source on an agent. First read get_agent_sources. If configured is false or searches are empty, use configure_agent_source instead. The first call shows exact approval; a second user-approved call commits. Saved searches, budgets, LinkedIn resolution and other sources stay unchanged. A draft or paused agent does not collect until activated.

Availability
Requires a configured X or Hacker News source
Cost
Future source polling may use provider resources
Credits
none
External effects
source discovery

Input schema

{
  "properties": {
    "agent_id": {
      "description": "Owned agent ID (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "app_id": {
      "description": "Product ID; required for MCP accounts with multiple products (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "One-use approval token, omit before approval",
      "type": "string"
    },
    "enabled": {
      "type": "boolean"
    },
    "expected_updated_at": {
      "description": "Version from get_agent_sources; optional on first call",
      "type": "string"
    },
    "source": {
      "description": "One source",
      "enum": [
        "x",
        "hackernews"
      ],
      "type": "string"
    }
  },
  "required": [
    "agent_id",
    "source",
    "enabled"
  ],
  "type": "object"
}
configure_agent_sourceBrowser approval

Configure X or Hacker News searches for one owned agent and set source listening. First call get_agent_sources. If no source exists, propose 1-10 precise searches from the user's request and saved ICP; do not invent a broad search without showing it. If a source exists, show its current searches and only replace them when the user asks to change them. This tool previews the exact searches, enabled state, and LinkedIn resolution choice, then requires explicit approval. It does not activate a draft or paused agent. For an already configured source whose searches need no change, use set_agent_source_listening instead. X needs a connected X account for collection. Hacker News uses its public search provider.

Availability
Requires an owned agent and 1-10 searches; a draft agent must be activated separately
Cost
Future source polling may use provider resources
Credits
none
External effects
source discovery

Input schema

{
  "properties": {
    "agent_id": {
      "description": "Owned agent ID (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "app_id": {
      "description": "Product ID; required for MCP accounts with multiple products (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "auto_resolve_linkedin": {
      "description": "Hacker News only; automatically resolve high-confidence leads through LinkedIn, which may use credits",
      "type": "boolean"
    },
    "confirmation_token": {
      "description": "One-use approval token; omit before approval",
      "type": "string"
    },
    "enabled": {
      "description": "Whether source listening should be enabled after approval",
      "type": "boolean"
    },
    "expected_updated_at": {
      "description": "Version from get_agent_sources; optional on first call",
      "type": "string"
    },
    "queries": {
      "description": "Exact search phrases to save, 1-10",
      "items": {
        "type": "string"
      },
      "type": "array"
    },
    "source": {
      "description": "Source to configure",
      "enum": [
        "x",
        "hackernews"
      ],
      "type": "string"
    }
  },
  "required": [
    "agent_id",
    "source",
    "queries",
    "enabled"
  ],
  "type": "object"
}
list_campaignsRead

List the campaigns in the app the request is scoped to (excludes archived). Returns a summary (count, brief one-liner, and a list of {id, name, status, agent_id, list_id}). Settings JSON is intentionally omitted; call get_campaign for current workflow, sender, and action detail. Status values: 'draft', 'active', 'paused'.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {},
  "type": "object"
}
get_campaignRead

Read one campaign in the selected product. Returns updated_at for exact approved settings changes, plus workflow, sender assignments, schedule, review mode, observed action state, and readiness blockers. Empty templates are not claimed as generated messages. No sending or activation occurs.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "campaign_id": {
      "description": "Campaign id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    }
  },
  "required": [
    "campaign_id"
  ],
  "type": "object"
}
update_campaign_settingsBrowser approval

Change a campaign's manual review, send window, or sender assignments in the selected product. Read get_campaign first and copy its updated_at as expected_updated_at. Omitted settings remain unchanged. Explicit null sender clears one platform. First call returns an exact approval preview; approved execution saves all changes atomically. It never activates, enrolls, or sends.

Availability
Requires an owned campaign and valid sender
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "account_assignments": {
      "description": "Only supplied platforms change",
      "properties": {
        "email": {
          "description": "Owned sender UUID, or null to clear this platform",
          "type": [
            "string",
            "null"
          ]
        },
        "linkedin": {
          "description": "Owned sender UUID, or null to clear this platform",
          "type": [
            "string",
            "null"
          ]
        },
        "reddit": {
          "description": "Owned sender UUID, or null to clear this platform",
          "type": [
            "string",
            "null"
          ]
        },
        "x": {
          "description": "Owned sender UUID, or null to clear this platform",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "type": "object"
    },
    "campaign_id": {
      "description": "Owned campaign id from get_campaign (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "One-use approval token; omit on first call",
      "type": "string"
    },
    "expected_updated_at": {
      "description": "Exact updated_at from get_campaign; may be omitted for a server-filled first preview",
      "type": "string"
    },
    "review_mode": {
      "description": "Require manual review before outreach",
      "type": "boolean"
    },
    "schedule": {
      "description": "Full send window; all fields required when supplied",
      "properties": {
        "days": {
          "description": "Unique weekdays",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "end_hour": {
          "description": "Exclusive local hour",
          "maximum": 24,
          "minimum": 1,
          "type": "integer"
        },
        "start_hour": {
          "description": "Inclusive local hour",
          "maximum": 23,
          "type": "integer"
        },
        "timezone": {
          "description": "IANA timezone, such as Europe/Berlin",
          "type": "string"
        }
      },
      "required": [
        "timezone",
        "days",
        "start_hour",
        "end_hour"
      ],
      "type": "object"
    }
  },
  "required": [
    "campaign_id"
  ],
  "type": "object"
}
get_daily_prioritiesRead

Rank up to four live operational starting points with source IDs and links. Connected senders and insights count across the account; leads, actions, campaigns, and unread messages count within the selected product. Read only.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {},
  "type": "object"
}
get_sender_healthRead

Show account-wide connected sender health and separate readiness for campaign assignments in the selected product. An account-wide connection does not prove a campaign has a usable sender.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {},
  "type": "object"
}
get_analyticsRead

Return product- or campaign-scoped activity in a UTC lookback interval. Completed actions and invitations use executed_at; connections and recorded replies use lead event timestamps. These are separate event counts, not one conversion cohort. Default 7 days, max 90.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "campaign_id": {
      "description": "Campaign id (required when scope='campaign') (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "days_back": {
      "description": "Lookback window in days (default 7)",
      "maximum": 90,
      "minimum": 1,
      "type": "integer"
    },
    "scope": {
      "description": "Aggregation level. Default 'app'.",
      "enum": [
        "campaign",
        "app"
      ],
      "type": "string"
    }
  },
  "type": "object"
}
find_leadsRead

Search leads in the app the request is scoped to. Returns bounded named summaries and IDs, never full rows. Use get_lead to load full detail for a specific id. Default source is 'discovered' (agent-found, awaiting approval); pass source='approved' to search leads already in campaigns. Optional 'search' keyword runs an ILIKE across name/company/headline; optional 'status' narrows by lead status. If results are thin, surface the count and ASK the user before broadening the filters — do not silently relax constraints.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "limit": {
      "description": "Max number of leads to return (1..50)",
      "maximum": 50,
      "minimum": 1,
      "type": "integer"
    },
    "search": {
      "description": "Optional keyword (matches name, company, or headline)",
      "type": "string"
    },
    "source": {
      "description": "Lead source. Default 'discovered'.",
      "enum": [
        "discovered",
        "approved"
      ],
      "type": "string"
    },
    "status": {
      "description": "Optional status filter (e.g. 'pending', 'approved', 'rejected')",
      "type": "string"
    }
  },
  "required": [
    "limit"
  ],
  "type": "object"
}
get_leadRead

Return full detail for a single lead by id, INCLUDING the derived reply_state and opt_out flags. Always call this before drafting or sending a message — a lead whose reply_state is 'replied', 'rejected', or 'opted_out', or whose opt_out is true, must NEVER be drafted to or messaged. Use source='approved' for leads in active campaigns; default 'discovered' is for agent-found leads awaiting approval.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "lead_id": {
      "description": "Lead id (from a prior find_leads result) (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "source": {
      "description": "Lead source. Default 'discovered'.",
      "enum": [
        "discovered",
        "approved"
      ],
      "type": "string"
    }
  },
  "required": [
    "lead_id"
  ],
  "type": "object"
}
get_conversation_contextRead

Return bounded conversation context for one lead or conversation in the request scope: lead profile, product/campaign context, last real messages, recent notes, open reminders, and Reply Assistant follow-up suggestions. Use this before meeting prep, reply planning, or questions about what happened with a lead. Read-only; does not draft or send messages.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "conversation_id": {
      "description": "Conversation id from inbox/follow-up context (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "lead_id": {
      "description": "Lead id from find_leads/get_lead or a follow-up result (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "limit": {
      "description": "Number of recent messages to return (default 12, max 20)",
      "maximum": 20,
      "minimum": 1,
      "type": "integer"
    }
  },
  "type": "object"
}
get_inbox_queueRead

List reply-needed conversations or due follow-ups in the selected product. One predicate determines both the total and page. AI drafts are not counted as sent replies. Limit 50; use offset for later pages.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "limit": {
      "description": "Maximum rows (default 20, max 50)",
      "maximum": 50,
      "minimum": 1,
      "type": "integer"
    },
    "mode": {
      "description": "Queue type",
      "enum": [
        "reply_needed",
        "due_follow_up"
      ],
      "type": "string"
    },
    "offset": {
      "description": "Pagination offset (default 0)",
      "maximum": 10000,
      "type": "integer"
    }
  },
  "required": [
    "mode"
  ],
  "type": "object"
}
list_operator_filesRead

List up to 20 files uploaded to any of your Operator threads in the selected product. Returns file IDs and metadata only, never bytes or extracted text. A file can be used for a same-product LinkedIn reply, not another product or email reply.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {},
  "type": "object"
}
prepare_conversation_replyRead

Prepare one exact local inbound reply. Returns recipient, sender, channel, inbound revision, final signed body, and optional owned file identity. Never sends. Files are available only for supported connected LinkedIn conversations in the selected product.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "attachment_id": {
      "description": "Optional file ID from list_operator_files. LinkedIn replies only (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "body": {
      "description": "Full proposed body. A configured booking link is tracked in the final preview",
      "type": "string"
    },
    "conversation_id": {
      "description": "Local conversation id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    }
  },
  "required": [
    "conversation_id",
    "body"
  ],
  "type": "object"
}
send_conversation_replyBrowser approval

Send one exact prepared reply to the latest inbound message after explicit human approval. Provide the complete prepare_conversation_reply result, its attachment_id when present, and a stable request_key. A timeout is uncertain and cannot be retried automatically. LinkedIn files are supported; email files are unavailable.

Availability
Requires a connected sender and current inbound message
Cost
Provider usage may apply
Credits
none at tool call; provider usage may apply
External effects
outbound message

Input schema

{
  "properties": {
    "attachment_id": {
      "description": "Exact prepared file ID when present (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "One-use approval token; omit on first call",
      "type": "string"
    },
    "prepared": {
      "description": "Exact prepare_conversation_reply result; all fields required by server validation",
      "type": "object"
    },
    "request_key": {
      "description": "Stable unique request identity, 8-128 chars",
      "type": "string"
    }
  },
  "required": [
    "prepared",
    "request_key"
  ],
  "type": "object"
}
get_reply_attemptRead

Read one reply attempt by its stable request_key in the selected product. Returns actual delivery evidence and next_action. Uncertain delivery requires manual provider review unless an exact outgoing provider message is confirmed. Never retries or sends.

Availability
Requires an owned reply attempt; provider evidence is optional
Cost
Provider history read may incur usage
Credits
none
External effects
none

Input schema

{
  "properties": {
    "request_key": {
      "description": "Stable request identity from send_conversation_reply, 8-128 characters",
      "type": "string"
    }
  },
  "required": [
    "request_key"
  ],
  "type": "object"
}
list_preferencesRead

List up to 20 saved Operator preferences for the user and product in the request scope. Values are bounded, labeled customer data, and never override user instructions or system rules. Returns key, value, and source only. No provider credentials or tokens are returned.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {},
  "type": "object"
}
search_external_leadsBrowser approval

Search LinkedIn for fresh people leads from the request user's connected account. Use this when the user describes leads to find by words, roles, companies, or market terms, rather than asking to search existing saved leads. Returns a server-owned session_id and up to 10 lead previews. To import the results, call import_search_leads_to_list with that session_id after the user asks to import all or selected leads.

Availability
Requires a connected LinkedIn account and available provider
Cost
LinkedIn provider request
Credits
none at tool call; interactive turn billing is separate
External effects
LinkedIn search request, no outreach

Input schema

{
  "properties": {
    "limit": {
      "description": "Max results to return (1..10). Default 10.",
      "maximum": 10,
      "minimum": 1,
      "type": "integer"
    },
    "query": {
      "description": "Free-text people search, e.g. 'YC founders building AI devtools'",
      "type": "string"
    },
    "role": {
      "description": "Optional job-title filter, e.g. 'Founder OR CEO'",
      "type": "string"
    }
  },
  "required": [
    "query"
  ],
  "type": "object"
}
import_search_leads_to_listBrowser approval

Import lead rows from a prior search_external_leads session into a lead list. Two-phase: first call returns a confirmation token + preview; the user reviews an inline card and confirms; second call with confirmation_token commits. provider_ids omitted means import every lead in the search session. Supply list_id for an existing list, or list_name to create a new list during the confirmed commit. After a committed result returns list_id, use that exact list_id when creating a campaign from the imported search leads.

Availability
Requires a valid search session
Cost
No product credits at import
Credits
none
External effects
none

Input schema

{
  "properties": {
    "confirmation_token": {
      "description": "Phase-2 token (omit on phase-1)",
      "type": "string"
    },
    "list_id": {
      "description": "Existing lead list id to import into (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "list_name": {
      "description": "Name for a new list to create during the confirmed import when list_id is omitted",
      "type": "string"
    },
    "provider_ids": {
      "description": "Optional selected provider ids from the search result. Omit to import all search results.",
      "items": {
        "description": "Provider id from the search result",
        "type": "string"
      },
      "type": "array"
    },
    "session_id": {
      "description": "Lead search session id returned by search_external_leads (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    }
  },
  "required": [
    "session_id"
  ],
  "type": "object"
}
create_campaign_draftBrowser approval

Create a draft campaign in the selected product. First show the exact campaign, agent, destination list, and any agent retargeting for approval. With agent_id and no list_id, use the agent's destination list; if absent, assign the product default list to both. An explicit different list retargets a draft agent only after approval. Never activate, discover, enroll, or send. If workflow_steps are omitted, create the standard 4-step flow. For custom steps ask about type, delay, message mode, template, and final step. In message_template use only {FirstName}, {LastName}, and {Company}.

Availability
Requires product quota
Cost
No product credits at draft creation
Credits
none
External effects
none

Input schema

{
  "properties": {
    "agent_id": {
      "description": "Optional agent id (from a prior list_agents) that supplies leads to this campaign (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "app_name": {
      "description": "App name (used in the confirm preview)",
      "type": "string"
    },
    "cold_outreach_mode": {
      "description": "Cold outreach mode (default 'invite')",
      "enum": [
        "invite",
        "inmail",
        "email"
      ],
      "type": "string"
    },
    "confirmation_token": {
      "description": "Phase-2 token (omit on phase-1)",
      "type": "string"
    },
    "list_id": {
      "description": "Optional owned lead list id. With an agent, omitted means its destination list. Otherwise the product default list is used or created. (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "name": {
      "description": "Campaign name (1-100 chars)",
      "type": "string"
    },
    "workflow_steps": {
      "description": "Optional custom workflow steps",
      "items": {
        "properties": {
          "delay_unit": {
            "description": "Delay unit",
            "enum": [
              "hours",
              "days"
            ],
            "type": "string"
          },
          "delay_value": {
            "description": "Delay before this step",
            "maximum": 365,
            "type": "integer"
          },
          "is_final": {
            "description": "Whether this is the final workflow step",
            "type": "boolean"
          },
          "message_mode": {
            "description": "Message mode",
            "enum": [
              "manual",
              "ai_personalized"
            ],
            "type": "string"
          },
          "message_template": {
            "description": "Optional message template. Supported personalization variables: {FirstName}, {LastName}, {Company}.",
            "type": "string"
          },
          "step_type": {
            "description": "Step type",
            "enum": [
              "invite",
              "message",
              "follow_up",
              "inmail",
              "email"
            ],
            "type": "string"
          }
        },
        "required": [
          "step_type"
        ],
        "type": "object"
      },
      "type": "array"
    }
  },
  "required": [
    "name"
  ],
  "type": "object"
}
update_campaign_workflowBrowser approval

Update message content on existing steps in a draft or paused campaign. Prefer one-based message_order, which counts only message-bearing steps and automatically skips invite/follow steps: message_order 1, 2, 3 targets the first, second, and third messages even when raw workflow step 1 is an invite. step_order remains available only when an exact raw workflow order is already known. Provide exactly one selector plus the exact message_template for every item. In message_template use only {FirstName}, {LastName}, and {Company} personalization variables. This is a two-phase confirmed action: first call without confirmation_token returns a confirmation card; approved execution applies the exact stored workflow_messages through the campaign service. It never launches or sends. Always include campaign_name and app_name for a human-readable preview.

Availability
Requires an owned campaign
Cost
No product credits at update
Credits
none
External effects
none

Input schema

{
  "properties": {
    "app_name": {
      "description": "App name used in the confirmation preview",
      "type": "string"
    },
    "campaign_id": {
      "description": "Campaign id from a prior list_campaigns result (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "campaign_name": {
      "description": "Campaign name used in the confirmation preview",
      "type": "string"
    },
    "confirmation_token": {
      "description": "Phase-2 token (omit on phase-1)",
      "type": "string"
    },
    "workflow_messages": {
      "description": "Exact message content to persist; prefer message_order 1..N for ordinary campaign copy",
      "items": {
        "properties": {
          "message_order": {
            "description": "Preferred one-based position among message-bearing steps; skips invite/follow steps",
            "maximum": 100,
            "minimum": 1,
            "type": "integer"
          },
          "message_template": {
            "description": "Non-empty message template to persist. Supported personalization variables: {FirstName}, {LastName}, {Company}.",
            "type": "string"
          },
          "step_order": {
            "description": "Advanced fallback: exact one-based raw workflow step order",
            "maximum": 100,
            "minimum": 1,
            "type": "integer"
          }
        },
        "required": [
          "message_template"
        ],
        "type": "object"
      },
      "type": "array"
    }
  },
  "required": [
    "campaign_id",
    "campaign_name",
    "app_name",
    "workflow_messages"
  ],
  "type": "object"
}
enable_campaignBrowser approval

Enable (resume) a paused or draft campaign. The campaign engine starts scheduling actions per the campaign's workflow. Two-phase: first call returns a confirmation token + preview; the user reviews and confirms; second call (with confirmation_token) commits. Activation pre-conditions (workflow steps, connected accounts) are validated by the underlying campaign service — the tool surfaces any failure as a structured error.

Availability
Requires sender and workflow readiness
Cost
Future outreach may use provider resources
Credits
none at tool call; future actions may have costs
External effects
future outbound actions

Input schema

{
  "properties": {
    "app_name": {
      "description": "App name (used in the confirm preview)",
      "type": "string"
    },
    "campaign_id": {
      "description": "Campaign id (from a prior list_campaigns) (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "campaign_name": {
      "description": "Campaign name (used in the confirm preview)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "Phase-2 token (omit on phase-1)",
      "type": "string"
    }
  },
  "required": [
    "campaign_id",
    "campaign_name",
    "app_name"
  ],
  "type": "object"
}
draft_messageBrowser approval

Generate a personalised draft for one lead. Reads the lead's profile (industry, role, headline, optional reference hook) and returns a single message body. Does NOT send. After the user reviews and approves, call send_message to actually deliver. ALWAYS call get_lead first to inspect reply_state — refuse to draft for opted-out / replied / rejected leads.

Availability
Requires an eligible lead and available AI provider
Cost
AI provider usage
Credits
none at tool call; interactive turn billing is separate
External effects
AI provider request, no outreach

Input schema

{
  "properties": {
    "lead_id": {
      "description": "Lead id (from a prior find_leads / get_lead) (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "reference": {
      "description": "Optional specific hook (recent post, role transition, milestone) the user wants referenced",
      "type": "string"
    },
    "tone": {
      "description": "Voice register",
      "enum": [
        "warm",
        "professional",
        "direct"
      ],
      "type": "string"
    }
  },
  "required": [
    "lead_id"
  ],
  "type": "object"
}
create_listBrowser approval

Create a new lead list scoped to the request's app. Use this when the user wants to organise leads into a named bucket (e.g. 'Q4 Targets', 'Hot Founders'). The new list starts empty; populate it later via approve_leads with action='approve' and the new list_id, or by editing the list manually.

Availability
Requires an owned product
Cost
No product credits
Credits
none
External effects
none

Input schema

{
  "properties": {
    "description": {
      "description": "Optional one-sentence description of what the list is for",
      "type": "string"
    },
    "name": {
      "description": "Display name for the list (1-100 chars)",
      "type": "string"
    }
  },
  "required": [
    "name"
  ],
  "type": "object"
}
draft_icp_editRead

Stage a proposed ICP edit for one agent. Returns a diff envelope (current vs proposed, fields_changed) so the user can review the change inline before applying it. Does NOT write — to actually apply the edit, call update_icp (confirm-tier) with the same agent_id and proposed fields. Use this when the user describes a change in plain language ('target Series A founders in EU' etc.); never call update_icp directly without first staging here so the user sees the before/after.

Availability
Requires an authenticated account and any requested owned record
Cost
No additional provider cost
Credits
none
External effects
none

Input schema

{
  "properties": {
    "agent_id": {
      "description": "Agent id (from a prior list_agents) (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "proposed_icp_description": {
      "description": "Free-text description of the new ICP",
      "type": "string"
    },
    "proposed_icp_filters": {
      "description": "Optional structured filters JSON (job_titles, industries, regions, etc.)",
      "type": "string"
    }
  },
  "required": [
    "agent_id"
  ],
  "type": "object"
}
pause_campaignBrowser approval

Pause an active campaign. The campaign engine stops scheduling actions. Two-phase: first call returns a confirmation token + preview; the user reviews an inline card and confirms or cancels; second call (with confirmation_token) commits the pause. Always include campaign_name + app_name so the preview is human-readable.

Availability
Requires an active campaign
Cost
No product credits
Credits
none
External effects
stops future outbound actions

Input schema

{
  "properties": {
    "app_name": {
      "description": "App name (used in the confirm preview)",
      "type": "string"
    },
    "campaign_id": {
      "description": "Campaign id (from a prior list_campaigns) (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "campaign_name": {
      "description": "Campaign name (used in the confirm preview)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "Phase-2 token (omit on phase-1)",
      "type": "string"
    }
  },
  "required": [
    "campaign_id",
    "campaign_name",
    "app_name"
  ],
  "type": "object"
}
enable_agentBrowser approval

Enable (activate) a paused or draft agent so it begins discovering leads on its schedule. Two-phase: first call returns a confirmation token + preview; the user reviews and confirms; second call (with confirmation_token) commits.

Availability
Requires an owned agent
Cost
Future discovery may use provider resources
Credits
none at tool call; future actions may have costs
External effects
future provider searches

Input schema

{
  "properties": {
    "agent_id": {
      "description": "Agent id (from a prior list_agents) (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "agent_name": {
      "description": "Agent name (used in the confirm preview)",
      "type": "string"
    },
    "app_name": {
      "description": "App name (used in the confirm preview)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "Phase-2 token (omit on phase-1)",
      "type": "string"
    }
  },
  "required": [
    "agent_id",
    "agent_name",
    "app_name"
  ],
  "type": "object"
}
pause_agentBrowser approval

Pause an active agent so it stops discovering new leads. The agent's existing leads remain in the list. Two-phase: first call returns a confirmation token + preview; the user reviews an inline card and confirms or cancels; second call (with confirmation_token) commits the pause. Always include agent_name + app_name so the preview is human-readable.

Availability
Requires an active agent
Cost
No product credits
Credits
none
External effects
stops future provider searches

Input schema

{
  "properties": {
    "agent_id": {
      "description": "Agent id (from a prior list_agents) (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "agent_name": {
      "description": "Agent name (used in the confirm preview)",
      "type": "string"
    },
    "app_name": {
      "description": "App name (used in the confirm preview)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "Phase-2 token (omit on phase-1)",
      "type": "string"
    }
  },
  "required": [
    "agent_id",
    "agent_name",
    "app_name"
  ],
  "type": "object"
}
approve_leadsBrowser approval

Approve or reject one or more discovered leads. Two-phase: first call returns a confirmation token + preview; the user reviews an inline card and confirms; second call (with confirmation_token) commits the status flip. action='approve' requires campaign_id (the campaign the leads will be associated with); action='reject' does not. The tool stamps each lead's status + reviewed_at + campaign_id; downstream campaign-engine pipelines ingest approved leads through their normal path.

Availability
Requires owned leads and a valid campaign for approval
Cost
Future outreach may use provider resources
Credits
none at tool call; future actions may have costs
External effects
may schedule future outreach

Input schema

{
  "properties": {
    "action": {
      "description": "Decision applied to every lead in lead_ids",
      "enum": [
        "approve",
        "reject"
      ],
      "type": "string"
    },
    "campaign_id": {
      "description": "Required for action=approve; omitted for action=reject (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "campaign_name": {
      "description": "Campaign name (used in the confirm preview)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "Phase-2 token (omit on phase-1)",
      "type": "string"
    },
    "count": {
      "description": "Number of leads in the batch (used in the confirm preview; mirrors len(lead_ids))",
      "type": "integer"
    },
    "lead_ids": {
      "description": "Discovered lead ids (from a prior find_leads result)",
      "items": {
        "description": "Lead id (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
        "type": "string"
      },
      "type": "array"
    }
  },
  "required": [
    "action",
    "lead_ids"
  ],
  "type": "object"
}
update_icpBrowser approval

Apply an ICP edit (description and/or filters JSON) to one agent. Two-phase: first call returns a confirmation token + preview; the user reviews the diff inline and confirms; second call (with confirmation_token) commits. ALWAYS call draft_icp_edit first so the user sees a before/after; never call update_icp directly without staging a diff. Pre-populate agent_name in the schema args so the preview is human-readable.

Availability
Requires an owned agent
Cost
No product credits
Credits
none
External effects
none

Input schema

{
  "properties": {
    "agent_id": {
      "description": "Agent id (from a prior list_agents) (UUID format, e.g. 550e8400-e29b-41d4-a716-446655440000)",
      "type": "string"
    },
    "agent_name": {
      "description": "Agent name (used in the confirm preview)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "Phase-2 token (omit on phase-1)",
      "type": "string"
    },
    "icp_description": {
      "description": "New free-text ICP description (omit to leave unchanged)",
      "type": "string"
    },
    "icp_filters": {
      "description": "New structured filters object. Use company_sizes and exclude_service_providers. excluded_companies accepts exact employer names or LinkedIn company URLs. URLs become slug names and remain separately in competitor_urls. Ask the user to verify the employer name. Omit to leave unchanged.",
      "type": "object"
    }
  },
  "required": [
    "agent_id"
  ],
  "type": "object"
}
create_agentBrowser approval

Create a new draft agent under the request's scoped app. Two-phase: first call previews every setting; second call after user confirmation creates it. The agent's ICP starts from the app's saved ICP; icp_filters keys you supply override only those keys, every other saved field (job_titles, mandatory_keywords, excluded_companies, company_sizes, ...) is kept as-is. Do not restate the full ICP from memory for a vague request like "set it up" — omit icp_filters entirely to inherit the saved ICP untouched, and only pass the specific keys the user actually asked to change. To deliberately clear a list field, pass it as an empty array. excluded_companies stores exact current employer names. If supplied a LinkedIn company URL, Operator saves its slug name there and retains the URL separately for competitor signals; ask the user to verify the name in the approval. Supply signals only when the user selects exact agent discovery signals; each signal must include its supported platform, category, key, label, enabled state, and config. An explicit empty signals array creates no signals. Without signals, defaults seed from the merged ICP filters. A requested keyword such as product launch can be a keyword_tracking_product_launch signal with config.keyword='product launch'. Ask for missing signal details; never claim a requested setting was saved if this schema cannot represent it.

Availability
Requires product quota
Cost
No product credits at creation
Credits
none
External effects
none

Input schema

{
  "properties": {
    "app_name": {
      "description": "App name (used in the confirm preview)",
      "type": "string"
    },
    "confirmation_token": {
      "description": "Phase-2 token (omit on phase-1)",
      "type": "string"
    },
    "icp_description": {
      "description": "Free-text ICP description for the new agent",
      "type": "string"
    },
    "icp_filters": {
      "description": "Optional structured ICP filters. Use job_titles, industries, regions, company_sizes, excluded_keywords, and exclude_service_providers. excluded_companies accepts exact employer names or LinkedIn company URLs. URLs become slug names and remain separately in competitor_urls. Ask the user to verify the employer name. Do not use unsupported excluded_industries.",
      "type": "object"
    },
    "max_signals": {
      "description": "Cap on enabled signals (default 15)",
      "maximum": 50,
      "minimum": 1,
      "type": "integer"
    },
    "name": {
      "description": "Display name for the new agent (1-100 chars)",
      "type": "string"
    },
    "signals": {
      "description": "Exact agent discovery signals. Omit to seed from ICP; use [] for none.",
      "items": {
        "properties": {
          "config": {
            "description": "Exact signal configuration, such as keyword or job_titles",
            "type": "object"
          },
          "description": {
            "description": "Optional signal description",
            "type": "string"
          },
          "enabled": {
            "description": "Whether the signal is selected",
            "type": "boolean"
          },
          "label": {
            "description": "User-visible signal name",
            "type": "string"
          },
          "platform": {
            "description": "Discovery platform",
            "enum": [
              "linkedin"
            ],
            "type": "string"
          },
          "signal_category": {
            "description": "Agent signal category",
            "enum": [
              "your_company",
              "engagement_interest",
              "linkedin_profiles",
              "change_trigger_events",
              "competitors_engagement",
              "job_activity"
            ],
            "type": "string"
          },
          "signal_key": {
            "description": "Exact signal key, such as keyword_tracking_hiring",
            "type": "string"
          }
        },
        "required": [
          "platform",
          "signal_category",
          "signal_key",
          "label",
          "enabled"
        ],
        "type": "object"
      },
      "type": "array"
    },
    "type": {
      "description": "Agent type (default 'signal')",
      "enum": [
        "signal",
        "lookalike"
      ],
      "type": "string"
    }
  },
  "required": [
    "name"
  ],
  "type": "object"
}