Superkabe's MCP (Model Context Protocol) server exposes 16 tools over stdio so Claude, Cursor, and other MCP-aware agents can query campaign state, pause mailboxes, and inspect validation results directly. Authenticates via a workspace API key in the connection config.
MCP Server v1.0.0
Connect Claude Desktop or any Model Context Protocol (MCP) client to your Superkabe organization. Drives the full v1 API surface — 16 tools covering leads, campaigns, validation, replies, and infrastructure — through a single Node.js subprocess over stdio.
superkabestdio@modelcontextprotocol/sdk1. What is MCP?
The Model Context Protocol is an open standard for connecting AI clients (like Claude Desktop, Claude Code, Cursor, and third-party agents) to external tools, data sources, and actions through a uniform JSON-RPC contract. An MCP server exposes a set of tools, resources, and prompts that the client can discover and invoke on behalf of the model.
The Superkabe MCP server is a thin translation layer: it receives tool invocations from the client over stdio, turns them into authenticated HTTPS calls against /api/v1, and returns the structured JSON response back to the model.
2. Why use it?
- Chat with your platform. Ask Claude Desktop "which of my mailboxes have bounced in the last 24h?" and let it answer from live Superkabe data.
- Agentic workflows. Build agents in Claude Code or Cursor that plan outbound campaigns, inspect engagement, draft replies, or audit deliverability — all without hand-rolling the REST client.
- Zero glue code. Input/output schemas are declared with Zod and auto-discovered by every MCP client. You do not write client bindings.
- Least-privilege security. The key you hand the MCP server carries exactly the scopes you grant — nothing more. Revoke the key to revoke the agent.
3. Installation
Prerequisites
- Node.js 20 or newer
- A Superkabe account and an API key generated from Dashboard → API & MCP
- An MCP-compatible client — Claude Desktop, Claude Code, Cursor, Continue, or any custom runtime
Option A — install from source (recommended during staging)
git clone https://github.com/Superkabereal/Superkabe.git superkabe cd superkabe/mcp-server npm install npm run build # compiles TypeScript to dist/index.js
Option B — npx (once published)
# No install step — npx fetches and runs on demand SUPERKABE_API_KEY=sk_live_... npx -y @superkabe/mcp-server
Sanity-check the server
Run it directly and confirm it prints the connection line to stderr:
SUPERKABE_API_KEY=sk_live_abc123 \ SUPERKABE_API_URL=https://api.superkabe.com \ node dist/index.js # stderr: # Superkabe MCP Server v1.0.0 connected (https://api.superkabe.com)
The process will sit idle waiting for JSON-RPC on stdin. Ctrl-C to exit. MCP clients spawn this process automatically — you do not run it manually in normal use.
4. Client configuration
4.1 Claude Desktop
Edit your Claude Desktop config file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"superkabe": {
"command": "node",
"args": ["/absolute/path/to/superkabe/mcp-server/dist/index.js"],
"env": {
"SUPERKABE_API_KEY": "sk_live_abc123...",
"SUPERKABE_API_URL": "https://api.superkabe.com"
}
}
}
}Restart Claude Desktop. A new tools icon should appear in the chat — clicking it lists all 16 Superkabe tools.
4.2 Claude Code
Two equivalent options. Same JSON shape as Claude Desktop:
- Global: add to
~/.claude/settings.jsonunder anmcpServerskey. - Per-project: create
.mcp.jsonat the project root.
// .mcp.json (project root) or under mcpServers in ~/.claude/settings.json
{
"mcpServers": {
"superkabe": {
"command": "npx",
"args": ["-y", "@superkabe/mcp-server"],
"env": {
"SUPERKABE_API_KEY": "sk_live_abc123...",
"SUPERKABE_API_URL": "https://api.superkabe.com"
}
}
}
}Restart the Claude Code session. /mcp in the CLI lists registered servers; the Superkabe tools should appear with no further setup.
4.3 Cursor
Cursor reads MCP config from one of two locations:
- Global:
~/.cursor/mcp.json - Per-project:
<project>/.cursor/mcp.json
// ~/.cursor/mcp.json
{
"mcpServers": {
"superkabe": {
"command": "npx",
"args": ["-y", "@superkabe/mcp-server"],
"env": {
"SUPERKABE_API_KEY": "sk_live_abc123...",
"SUPERKABE_API_URL": "https://api.superkabe.com"
}
}
}
}Open Cursor Settings → MCP to see the server status (green dot = connected). Composer agents pick up the tools automatically on next prompt.
4.4 Continue
Continue reads <project>/.continue/config.json. Add an mcpServers entry alongside your existing config:
// .continue/config.json
{
"models": [ /* your models */ ],
"mcpServers": {
"superkabe": {
"command": "npx",
"args": ["-y", "@superkabe/mcp-server"],
"env": {
"SUPERKABE_API_KEY": "sk_live_abc123...",
"SUPERKABE_API_URL": "https://api.superkabe.com"
}
}
}
}4.5 Auto-configure (any client)
If you cloned the repo, run the bundled setup script — it detects which clients you have, prompts for your API key + URL, and writes the right JSON to the right path:
cd superkabe/mcp-server ./setup.sh
Re-run any time to update credentials or add another client.
4.6 Built from source instead of npx
If you cloned the repo and ran npm run build, swap command/args for an absolute path to the compiled entry:
"command": "node", "args": ["/absolute/path/to/superkabe/mcp-server/dist/index.js"],
4.7 Environment variables
| Variable | Required | Default | Notes |
|---|---|---|---|
| SUPERKABE_API_KEY | yes | — | Bearer token. Server crashes at startup if missing. |
| SUPERKABE_API_URL | no | http://localhost:4000 | Override for staging / production. Trailing slash is stripped. |
Never put the API key in args[]
Always pass SUPERKABE_API_KEY through the env block. Keys placed in args show up in ps aux and system process lists; env vars do not.
4.8 Scope matrix — which scopes do I need?
Each MCP tool is gated by a single API-key scope. Pick the scopes that match the tools you actually want the agent to call. The agent will receive a Missing required scope error for anything you didn't grant.
| Tool | Risk | Required scope |
|---|---|---|
| get_account | low | account:read |
| list_leads | low | leads:read |
| get_lead | low | leads:read |
| import_leads | medium | leads:write |
| validate_leads | medium | validation:trigger |
| get_validation_results | low | validation:read |
| list_campaigns | low | campaigns:read |
| get_campaign | low | campaigns:read |
| create_campaign | high | campaigns:write |
| update_campaign | high | campaigns:write |
| launch_campaign | high | campaigns:write |
| pause_campaign | medium | campaigns:write |
| get_campaign_report | low | reports:read |
| get_campaign_replies | low | replies:read |
| send_reply | high | replies:send |
| list_mailboxes | low | mailboxes:read |
| list_domains | low | domains:read |
Recommended scope bundles
- Read-only analyst (11/16 tools, zero writes):
account:read leads:read validation:read campaigns:read reports:read replies:read mailboxes:read domains:read - Lead ops (read-only + import + validate, no campaign sends): the read-only set plus
leads:write validation:trigger - Full agent (all 16 tools incl. real sends): every scope above plus
campaigns:write replies:send
Use a separate key per risk tier
If you need both a read-only daily-brief agent and a full-send campaign agent, issue two separate API keys with the relevant scopes and configure them as two different MCP servers (superkabe-read, superkabe-write). Lets you revoke send capability in one click without breaking your reporting flow.
5. Tool call lifecycle
- User asks Claude a question that requires live data.
- Claude chooses a registered tool and emits
tool_usewith JSON arguments. - The MCP client serializes the call as JSON-RPC and writes it to the server's stdin.
- The server validates the arguments against the Zod schema, makes an HTTPS call to the Superkabe v1 API with
Authorization: Bearer $SUPERKABE_API_KEY. - The v1 controller enforces the relevant scope, runs the Postgres query, returns
{ success, data }. - The server wraps the response as a
textcontent block (JSON-stringified) and returns it over stdio. - Claude receives the
tool_result, incorporates it into its next response.
6. Security model
- No ambient credentials. The server reads exactly one env var (
SUPERKABE_API_KEY). It does not read~/.aws/credentials,gcloud, or any other system state. - Scoped keys. The tools the server attempts are defined at build time. The tools the server is allowed to execute are determined by the scopes on the API key you hand it. Grant the minimum.
- Organization scoping. Every API call is automatically scoped to the key's organization by
orgContext. The MCP server cannot leak across tenants. - Rate limits apply. MCP traffic is rate-limited per API key like any other client (§6 of the API documentation).
- Stdio not sockets. The server opens no listening ports; compromise requires local process access.
- No persistent state. The server holds only transient request context. Killing the process forgets everything.
High-risk tool warning
Tools marked risk: high below can mutate production state or send real emails (launch_campaign, update_campaign, pause_campaign, create_campaign, send_reply). Only grant the matching scope when you actively want the agent to take those actions, and prefer a dedicated key per risk tier so you can revoke narrowly.
7. Tool reference
Every tool exposed by the Superkabe MCP server, in the order it appears in mcp-server/src/index.ts. Each tool maps 1:1 to a v1 API endpoint — see the API documentation for response shapes.
Tool index
get_account
— Get Account Inforisk: lowscope: account:readReturns organization name, subscription tier, status, usage counters, and plan limits. Claude usually calls this first to understand what the user can and cannot do.
Returns
Object with id, name, slug, tier, status, usage{leads,domains,mailboxes}, limits{leads,domains,mailboxes,monthly_sends,validation_credits}.
import_leads
— Import Leadsrisk: mediumscope: leads:writeImport up to 5,000 leads in a single call. Duplicates by email are detected and skipped. New leads enter with status `held` and must go through validation before they can be routed.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| leads | array | yes | Array of lead objects. Each must have `email` (required). Optional fields: `persona`, `source`, `lead_score` (0-100, default 50). |
Returns
Object with total, created, duplicates, errors, and per-row results[{email,id,status,error?}].
list_leads
— List Leadsrisk: lowscope: leads:readPaginated list of leads with filters. Use this after import to inspect validation_status or emails_sent / emails_replied stats.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| page | number | no | Page number (default 1). |
| limit | number | no | Results per page, 1-100, default 50. |
| status | string | no | held · active · paused · blocked |
| validation_status | string | no | valid · risky · invalid · unknown · pending |
| search | string | no | Case-insensitive email substring match. |
Returns
Object with data[] and meta{total,page,limit,totalPages}.
get_lead
— Get Lead Detailsrisk: lowscope: leads:readFull Lead row by ID, including validation score, catch-all / disposable flags, and engagement counters.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| lead_id | string | yes | Lead ID. |
Returns
Full Lead object.
validate_leads
— Validate Lead Emailsrisk: mediumscope: validation:triggerQueues validation on existing leads. Asynchronous — poll `list_leads` to see the updated `validation_status`. Consumes validation credits (one per unique non-cached domain).
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| lead_ids | string[] | no | Lead IDs to validate (either this or emails). |
| emails | string[] | no | Emails to validate — must already exist in Superkabe. |
Returns
Object with queued count, lead_ids, and a polling hint.
get_validation_results
— Get Validation Analyticsrisk: lowscope: validation:readOrganization-wide validation rollup: total validated leads, breakdown by status.
Returns
Object with total_validated and status_breakdown{valid,risky,invalid,unknown}.
create_campaign
— Create Campaignrisk: highscope: campaigns:writeCreates a native-sequencer campaign in `draft` status with sequence steps, optional A/B variants, and optional initial leads. Assigned leads pass through the health gate — RED leads are excluded, YELLOW enter as paused, GREEN as active.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| name | string | yes | Campaign name. |
| steps | array | yes | Sequence steps. Each has subject, body_html, optional body_text, delay_days, delay_hours, and variants[]. |
| lead_ids | string[] | no | Lead IDs to assign. Runs through the health gate. |
| schedule | object | no | timezone (IANA), start_time, end_time, days[], daily_limit, send_gap_minutes. |
Returns
Object with id, name, status, steps_count, leads_assigned, leads_blocked.
list_campaigns
— List Campaignsrisk: lowscope: campaigns:readLists every native-sequencer campaign in the org with status, lead/step counts, and schedule metadata.
Returns
Array of campaign summaries.
get_campaign
— Get Campaign Detailsrisk: lowscope: campaigns:readFull campaign with every sequence step (and variants) plus the first 100 assigned leads.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| campaign_id | string | yes | Campaign ID. |
Returns
Campaign object with steps[].variants[] and leads[].
update_campaign
— Update Campaignrisk: highscope: campaigns:writeUpdates name, daily_limit, send_gap_minutes, or schedule fields. Returns 400 if the campaign is currently `active` — pause first, update, then launch again.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| campaign_id | string | yes | Campaign ID. |
| name | string | no | New name. |
| daily_limit | number | no | New per-mailbox daily send limit. |
| schedule_timezone | string | no | IANA TZ. |
| schedule_start_time | string | no | HH:MM, e.g. 09:00. |
| schedule_end_time | string | no | HH:MM, e.g. 17:00. |
| schedule_days | string[] | no | e.g. ["mon","tue","wed","thu","fri"]. |
Returns
Object with id, name, status.
launch_campaign
— Launch Campaignrisk: highscope: campaigns:writeFlips status to `active` and stamps `launched_at`. Requires at least 1 step and 1 assigned lead. The send-queue dispatcher picks up the campaign on its next 60s tick.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| campaign_id | string | yes | Campaign ID to launch. |
Returns
Object with id, status, leads, steps.
pause_campaign
— Pause Campaignrisk: highscope: campaigns:writeFlips status to `paused`. Safe to call repeatedly; returns 400 if the campaign is not currently `active`.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| campaign_id | string | yes | Campaign ID to pause. |
Returns
Object with id and status.
get_campaign_report
— Get Campaign Reportrisk: lowscope: reports:readAggregate performance metrics: total leads, lead_status_breakdown, emails_sent, replies, and reply_rate.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| campaign_id | string | yes | Campaign ID. |
Returns
Report object.
get_campaign_replies
— Get Campaign Repliesrisk: lowscope: replies:readUp to the 100 most recently replied-on threads. Each thread carries the latest inbound message (subject, body_text, received_at). Returned `thread_id` is the handle for `send_reply`.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| campaign_id | string | yes | Campaign ID. |
Returns
Object with total_replies and replies[].
send_reply
— Send Replyrisk: highscope: replies:sendSends an outbound message on an existing thread through the mailbox that originally received it. Requires the mailbox to have `connection_status = active`. This sends a real email — get explicit user confirmation first.
Inputs
| Name | Type | Req? | Description |
|---|---|---|---|
| thread_id | string | yes | Thread to reply to (from get_campaign_replies). |
| body_html | string | no | HTML body. |
| body_text | string | no | Plain-text fallback (used if body_html omitted). |
Returns
Object with message_id, thread_id, from, to, status.
list_mailboxes
— List Mailboxesrisk: lowscope: mailboxes:readEvery connected sending account with health status, send counters, bounce counters, warmup reputation, and recovery phase. Useful for infrastructure audits.
Returns
Array of mailbox summaries.
list_domains
— List Domainsrisk: lowscope: domains:readEvery sending domain with lifetime engagement totals, bounce-rate trend, warning_count, resilience_score, and recovery phase.
Returns
Array of domain summaries.
8. Error handling
When the v1 API returns a non-2xx status, the MCP server converts the error into a text content block and sets isError: true on the tool result. Example:
// Server returns to Claude:
{
"content": [{ "type": "text", "text": "Error: Missing required scope: campaigns:write" }],
"isError": true
}Common failure modes and how Claude should recover:
| Message starts with | Root cause | Recovery |
|---|---|---|
Missing required scope | API key lacks the scope the tool needs | Grant scope in dashboard or reissue key |
API returned 401 | Key revoked or malformed | Re-issue key, update client config |
API returned 404 | Resource ID does not belong to org | Re-read relevant list_* tool, use correct ID |
API returned 429 | Rate limit exceeded | Wait, retry with backoff |
API returned 400 | Invalid input (e.g. launching a campaign with 0 leads) | Fix the input, do not retry blindly |
fetch failed | Network error / API unreachable | Retry once; if persistent, report to user |
9. Example sessions
9.1 Daily deliverability brief
User: "Give me a deliverability brief for today — which mailboxes are healing, which domains had bounces, what should I look at first?"
Claude calls, in order:
get_account— confirm tier/limitslist_mailboxes— filter client-side torecovery_phase !== nulllist_domains— sort byaggregated_bounce_rate_trend DESC- Formats a markdown brief with the three domains most at risk and the healing mailboxes' phases.
9.2 Launching a net-new campaign
User: "Import these 200 VP-Engineering leads and launch them into a 3-step sequence targeted at technical founders. Use my Q2 template."
import_leadswith the CSV contentsvalidate_leadson the returned lead IDs- Wait ~10s, then
list_leadsto checkvalidation_status create_campaignwith the 3 steps and the valid lead IDs- Pause for user confirmation before calling
launch_campaign(it triggers real sends)
9.3 Reply triage
User: "Any hot replies on the April campaign? Draft responses for the ones that look positive."
list_campaignsto find the April campaign IDget_campaign_repliesto pull the last 100 threads- Claude classifies sentiment client-side, drafts replies, and presents them to the user
- On approval, calls
send_replyper thread (requiresreplies:sendscope)
10. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Tools icon does not appear in Claude Desktop | Config path wrong or JSON invalid | Validate JSON with jq . claude_desktop_config.json; quit & relaunch Claude Desktop |
FATAL: SUPERKABE_API_KEY is required | Env var not passed through to subprocess | Put the key under the env block, not args |
Every tool call returns API returned 401 | Key revoked or wrong env | Re-issue key; confirm SUPERKABE_API_URL matches the key's environment |
Some tools work, others return Missing required scope | Key lacks those scopes | Edit key in dashboard (or issue a broader key) |
ECONNREFUSED 127.0.0.1:4000 | Default API URL used, but backend is not running locally | Set SUPERKABE_API_URL=https://api.superkabe.com |
| Slow tool calls (> 2s for list endpoints) | Large organization data + cold DB | Add filters to list_leads (page, status); report if persistent |
Enable debug logging
The server logs to stderr so MCP client logs capture it:
# macOS Claude Desktop logs tail -f "~/Library/Logs/Claude/mcp-server-superkabe.log" # Run manually with verbose Node logs NODE_DEBUG=http,https SUPERKABE_API_KEY=... node dist/index.js
11. Updating
When new tools are added to the Superkabe MCP server you simply update the package and restart your MCP client — schemas are auto-advertised over the protocol. No client code changes.
cd superkabe/mcp-server git pull npm install npm run build # Restart Claude Desktop / Cursor / your client
12. Protocol compatibility
- Implements MCP server capability
toolsonly — noresources,prompts, orsamplingyet. - Tested against
@modelcontextprotocol/sdk1.12.x on the server side; any conformant MCP client should interoperate. - Transport is
StdioServerTransport. HTTP/SSE transport is on the roadmap; open an issue if you need it.
Next steps
- Read the API documentation for the exact shape of every tool's response.
- Generate a scoped API key in Dashboard → API & MCP.
- Copy the Claude Desktop config snippet above and restart the app.
- Try "list my campaigns" as your first prompt.
Frequently Asked Questions
Which agents support the Superkabe MCP server?
+
Any MCP-compatible client: Claude Desktop, Claude Code, Cursor, Zed, Continue, and the Anthropic MCP SDK. The server speaks standard MCP over stdio — no special client-side code required.
Can the agent modify sending state?
+
Yes. Tools are scoped by API key permissions — read-only keys expose only inspection tools; write-capable keys additionally expose pause, resume, and rotation controls.
How do I install it?
+
npm install -g @superkabe/mcp-server, then add a server entry to your MCP client's config pointing at `superkabe-mcp` with SUPERKABE_API_KEY in env.