SendsetsDocs

MCP server

Connect an external agent to SendSets' focused, policy-controlled tool surface.

SendSets exposes the same service-layer tools over MCP and REST. An internal LLM provider is not required. The endpoint uses streamable HTTP at /v1/mcp and accepts OAuth 2.1 access tokens or static ssk_ API keys.

claude mcp add --transport http sendsets http://localhost:8080/v1/mcp

Or configure a static key:

{
  "mcpServers": {
    "sendsets": {
      "type": "http",
      "url": "http://localhost:8080/v1/mcp",
      "headers": { "Authorization": "Bearer ssk_..." }
    }
  }
}

Hosted endpoint and packaged installs

On SendSets Cloud the endpoint is https://api.sendsetsapi.com/v1/mcp:

claude mcp add --transport http sendsets https://api.sendsetsapi.com/v1/mcp

The same server is published in the official MCP Registry as io.github.AddisonHoff/sendsets, so registry-backed clients and catalogs can find it by name. github.com/AddisonHoff/sendsets packages it with the SendSets skills for clients that install bundles:

ClientCommand
Claude Code/plugin marketplace add AddisonHoff/sendsets, then /plugin install sendsets@sendsets
Codexcodex plugin marketplace add AddisonHoff/sendsets, then codex plugin add sendsets@sendsets
Gemini CLIgemini extensions install https://github.com/AddisonHoff/sendsets
Any agent with the skills CLInpx skills add AddisonHoff/sendsets (skills only)

The skills are send-cold-email (send a sequence to a lead list), sendsets (propose and run product-led campaigns) and sendsets-cli (the full CLI reference).

Send tools

Every tool in tools/list carries a title and MCP annotations: read tools are readOnlyHint, send tools and every write that modifies or removes data are destructiveHint (only purely additive create_* and add_* tools are not), and tools that reach outside the workspace (mail, the web, DNS, webhook receivers) are openWorldHint. The endpoint accepts POST only; a GET answers 405 because the server does not open an event stream.

Send-class tools are present in tools/list. Scopes decide whether the caller can see and call a tool; a credential-bound policy independently decides whether the action may execute autonomously.

ToolScopeCapability
create_runWRITE_RUNSnone for draft; campaign.launch for autonomous launch
get_run, list_runsREAD_RUNS—
cancel_runWRITE_RUNS—
start_campaignEXECUTE_RUNScampaign.launch
stop_campaignWRITE_RUNS—
compose_emailSEND_DIRECT_EMAILemail.compose
send_replySEND_INBOX_REPLYinbox.reply

The successful result is always structured:

{
  "result": "executed | awaiting_approval | blocked",
  "reasons": ["policy does not grant email.compose"],
  "approval_url": "http://localhost:5173/app/approvals/..."
}

awaiting_approval means a JWT-authenticated human can review the request for 30 minutes. Approval tools are intentionally absent from MCP and REST tool discovery. A structurally unsafe request is blocked; approval cannot override missing opt-out, suppression, mailbox health, or deliverability checks.

The registry also exposes focused read/write tools for campaigns, sequences, leads, mailboxes, warmup, inbox, analytics, suppressions, and webhooks. CRM, forms, automations, advisor, and other legacy engines are absent unless the instance operator explicitly sets SENDSETS_ENABLE_EXTENDED_SURFACES=true.

Query your data with SQL

Four read-only tools let an agent answer any question about the workspace by writing its own SQL, instead of being limited to the reports a tool happens to offer:

ToolWhat it does
sql_schemaLists the tables, or describes one table's columns, types, and meaning
sql_examples26 worked queries for common outbound questions, to adapt rather than write from scratch
sql_estimatePlans a query without running it: estimated cost and rows, and whether it fits the ceiling
sql_queryRuns one query and returns typed columns and rows as JSON

The tables are views over this workspace's data, named directly with no schema prefix:

AreaTables
Campaignscampaigns, campaign_steps, ab_variants, campaign_leads, campaign_logs
Sends and outcomesemail_sends (one row per email step, with opens, clicks, reply class, bounces), send_ledger (the mailbox and A/B arm behind each send), link_clicks
Contactscontacts (with job title, seniority, department, company domain, and outreach status), categories, contact_categories, segments, suppressions
Infrastructuremailboxes, mailbox_errors, warmup_daily, warmup_health
Outcomesmeetings, product_events, goals, conversions, people, attribution_credits, deals, deal_stages

Mailbox credentials, message bodies, and anything encrypted are not in any table.

What keeps a query inside its workspace, and harmless:

  • One read. Only a single SELECT (or WITH ... SELECT) is accepted. Writes, data-modifying WITH, SELECT INTO, settings, server files, advisory locks, large objects, and SQL run from a string are refused before anything runs, with the reason.
  • Its own rows only. Each query gets fresh views with the workspace id written into them, and runs as a database role that can read nothing else: not the underlying tables, not another workspace's views, not other connections. The views are security barriers, so even an error message cannot carry another workspace's row.
  • Nothing persists. The transaction is always rolled back.
  • Bounded. 30 seconds per query, a planner-cost ceiling (sql_estimate shows where a query sits), at most 10,000 rows (200 by default) and 4 MB per result, and a few queries at a time per server.

The tools need both READ_ANALYTICS and READ_CONTACTS (view_analytics and view_contacts for a signed-in member).

{"tool": "sql_query", "arguments": {"sql": "SELECT m.email, count(*) AS sent, round(100.0 * count(*) FILTER (WHERE s.bounced_at IS NOT NULL) / count(*), 1) AS bounce_pct FROM send_ledger l JOIN email_sends s USING (campaign_id, contact_id, step_id) JOIN mailboxes m ON m.id = l.mailbox_id WHERE l.confirmed_at >= now() - interval '7 days' GROUP BY m.email ORDER BY bounce_pct DESC LIMIT 5"}}

SQL only reads. To change data, an agent uses the typed tools listed in Reading and changing each table, which validate, audit, and keep the dashboard live. sql_bulk_contacts lets a query choose the contacts and a typed action change them, with a dry run first.

The dashboard's Ask Claude buttons, on the Acquisition Outbound and Copy tabs, on Mailboxes, and in the Lead database, copy a ready question for that screen with instructions to answer it through these tools. Paste it into Claude once this server is connected.

OAuth discovery

Unauthenticated requests return the standard protected-resource challenge. Clients discover authorization metadata from:

  • /.well-known/oauth-protected-resource
  • /.well-known/oauth-authorization-server

OAuth credentials use sscid_, sscs_, ssat_, ssrt_, and ssac_ prefixes. Old credential formats are not accepted.

On this page