Selda MCP Server
The Selda MCP server lets external AI tools (Claude Desktop, Claude Code, ChatGPT, or any Model Context Protocol client) drive a user’s Selda workspace: list projects, inspect leads and campaigns, read threads, and run the GTM pipeline. It is a paid/Scale-tier feature, gated behind an API key.
The Selda web app is at https://app.selda.ai.
Two parts
There are two distinct pieces:
-
The Node MCP server,
mcp-server/index.ts. A small stdio MCP server that exposes the Selda tools to the AI client and forwards each call over HTTP to the Convex backend. Runs locally (e.g. spawned by Claude Desktop vianpx tsx). -
The Convex HTTP endpoints it calls, defined in
convex/mcpApi.tsand routed inconvex/http.ts:Endpoint Method Purpose /mcp/queryPOSTRead operations (queries) /mcp/mutatePOSTWrite operations (mutations) /mcp/runPOSTActions (pipeline / engine) Each also has an
OPTIONSroute for CORS preflight. The base URL is the deployment’s.convex.sitehost (prod default:https://brave-buzzard-349.eu-west-1.convex.site, overridable viaSELDA_API_URL/VITE_CONVEX_SITE_URL).The HTTP body is always
{ fn, args }, wherefnis a registry key (e.g.projects.list) and the handler returns{ value }on success or{ error }with a non-200 status on failure.
Authentication & scoping
- API key format:
sk_live_…(prefix + 40 random alphanumeric chars). - Transport: sent as a Bearer token:
Authorization: Bearer sk_live_…. The Node server reads it from theSELDA_API_KEYenv var. - Creation: keys are minted via
apiKeys.createKey(called from the app UI: Settings → Apps → API Key). The full plaintext key is returned once at creation and never stored or shown again. - Storage: only a SHA-256 hash of the key (
keyHash) plus a displaykeyPrefix(first 16 chars +...) are persisted in theapiKeystable. The plaintext key is never written to the database. - Validation: every HTTP call runs
apiKeys.validateKeyover the request’s hashed token. A key is rejected if it is missing/expired, revoked (revokedAt), the owning user is deleted/disabled, or the owning org no longer exists. On success it returns the key’sorgId,userId, andscopes. - Revocation:
apiKeys.revokeKey(UI) setsrevokedAt; the key stops validating immediately.
Scopes
| Scope | Grants | Self-grantable |
|---|---|---|
read | /mcp/query (and required by all read calls) | Yes |
write | /mcp/mutate | Yes |
pipeline | /mcp/run (engine / pipeline actions) | Yes |
admin | cross-org admin queries (all users/orgs/projects/stats) | No |
Default scopes for a newly created key are ["read", "write", "pipeline"].
The admin scope exists for internal cross-org tooling and is not granted
through normal self-service key creation (security-hardened, see
the internal security notes).
Org isolation
Each HTTP handler:
- checks the required scope for that endpoint (e.g.
/mcp/queryrequiresread), returning403if missing; - injects the key’s
orgId(and, where relevant,userId) server-side into the called function’s args.
Because the org id comes from the validated key, never from the request body,
a key can only ever reach data belonging to its own organization. Every
underlying mcpQueries.* function re-verifies org ownership (e.g. a lead is only
returned if its project’s orgId matches the key’s org). One org’s key cannot
read or mutate another org’s projects, leads, campaigns, or messages.
Tools
The Node server exposes 13 tools (TOOLS in mcp-server/index.ts). Each maps to
one or more { fn, args } calls against the Convex HTTP API.
| Tool | Purpose | Key args |
|---|---|---|
selda_list_projects | List your Selda projects (name, website, status, id). Returns the projectId needed by other tools. | none |
selda_get_project | Project detail: business context, market analysis, ICP, settings. | projectId |
selda_list_leads | List leads for a project (contact, company, fit score, status). | projectId, limit? (default 50) |
selda_get_lead | Full lead detail: contact, company research, fit, why-good-lead, outreach angle, notes. | leadId |
selda_update_lead | Update a lead’s status (new→contacted→responded→qualified/unqualified) and/or notes. | leadId, status?, notes? |
selda_list_campaigns | List a project’s campaigns (status, type, channels). | projectId |
selda_get_campaign | Campaign detail: status, channels, stats, settings, lead count. | campaignId |
selda_campaign_stats | Campaign performance: sent / delivered / opened / clicked / replied / bounced. | campaignId |
selda_list_messages | List sent/received messages for a project (direction, recipient, subject, status). | projectId |
selda_get_thread | Full email thread with one lead, all sent and received messages. | leadId |
selda_run_pipeline | Run the full GTM pipeline: find leads → research → write personalized messages. The core engine. | projectId, idea, targetLeadCount? (default 5) |
selda_lookup | General Selda lookup verb (resolve/inspect an entity from a reference). | reference / query args |
selda_credits | Check credit balance: daily free credits, lead credits, usage, plan. | none |
The live MCP server may also expose an
selda_add_leadtool for adding known contacts directly (backed by theleads.addmutation inconvex/mcpQueries.ts).
Usage guidance (from the MCP server instructions)
- The app is at
https://app.selda.ai, never useselda.cityor other domains. - Always call
selda_list_projectsfirst to obtain aprojectIdbefore any other operation. - When a user shares a URL or webpage with specific companies/people, add them
directly (e.g.
selda_add_lead), do not pass URLs toselda_run_pipeline. - Use
selda_run_pipelineonly for open-ended searches like “find SaaS founders in Finland”. selda_run_pipelineruns the engine and costs credits; results (leads + drafted messages) appear after a few minutes, poll withselda_list_leads.
Connecting a client
-
In the Selda app go to Settings → Apps → API Key and create a key. Copy the
sk_live_…value (shown once). -
Point your MCP client at the Node server, passing the key as
SELDA_API_KEY. Example Claude Desktop config:{ "mcpServers": { "selda": { "command": "npx", "args": ["tsx", "/path/to/mcp-server/index.ts"], "env": { "SELDA_API_KEY": "sk_live_..." } } } }Or run the guided setup:
npx tsx mcp-server/setup.ts. -
Every call is automatically scoped to the org that owns the key. Pipeline runs consume credits, so check
selda_creditsif runs start failing.
Source files
| File | Role |
|---|---|
mcp-server/index.ts | Node stdio MCP server, tool definitions, HTTP client |
mcp-server/handlers.ts | Extra tool handlers (analysis, discussions, channels, drafts) |
mcp-server/setup.ts | Interactive client configuration |
convex/mcpApi.ts | HTTP handlers for /mcp/query, /mcp/mutate, /mcp/run; auth + scope + org injection |
convex/mcpQueries.ts | Org-scoped internal queries/mutations/actions the HTTP layer calls |
convex/apiKeys.ts | API key creation, validation, revocation (SHA-256 hashed storage) |
convex/http.ts | Routes the MCP endpoints |