MCP Server

Custom Clients

The rest of this section assumes an off-the-shelf client like Claude Code, Claude Desktop, or Dust, which handle the protocol and the OAuth flow for you. This page is for connecting your own application.

MCP is JSON-RPC 2.0 over Streamable HTTP. Nothing requires the client to be an AI agent — any program that can make HTTP requests and hold a bearer token can call the tools. Official SDKs exist for Python (mcp) and TypeScript (@modelcontextprotocol/sdk), and both handle registration, the token exchange, and the transport.

Server URL:

https://mcp.splattr.ai/mcp

Standard flow: initialize, then tools/list to discover, then tools/call to invoke.

Responses are prose, not JSON

This is the thing most likely to surprise you.

Tool results come back as text content formatted for readability, not as structured objects. get_prospect returns a Markdown block containing the prospect's name, title, company, score, contact details, reasoning, strengths, and uncertainties. It is not a JSON payload with those as fields.

If you're passing results to an LLM, this is what you want and you should hand the text straight through. If you're parsing deterministically, write the extraction defensively and pin the behavior with tests, because formatting may be refined over time. Don't build a strict schema parser against these strings.

If structured output would materially help your integration, tell us. It's a change we're considering, and customer demand sets the priority.

What the tools return

Splattr returns the output of its analysis: scores, the reasoning behind them, strengths and uncertainties, outreach guidance, and contact data.

The tools do not return the raw research records underneath — no structured signal arrays, no per-signal source URLs or timestamps. Some of that data is licensed from providers under terms that don't permit redistribution, and the rest is the input to the analysis rather than the analysis itself.

The practical implication for your integration: treat a claim in a prospect's reasoning as already verified. It came out of Splattr's research and scoring pipeline, and recency is already weighed into the score. Re-checking those claims against the open web tends to produce worse results, because a signal that a general web search can't immediately re-find is usually still true, just not indexed where you looked.

Asynchronous operations

Five tools spend credits and run asynchronously, returning a task instead of a result:

  • run_campaign
  • enrich_email, enrich_phone, retry_enrichment
  • generate_report

The pattern is: call the tool, poll get_task_status until it completes, then read the outcome with get_prospect (enrichment) or get_report (reports).

Enrichment usually finishes in seconds. Campaign runs take longer depending on batch size. preview_campaign_cost returns the credit cost of a batch without charging anything, if you need to check before committing.

A typical sequence

create_campaign(name)
  → train_campaign(campaign_id, description)         derives and saves filters
  → preview_campaign_cost(campaign_id, batch_size)   optional, free
  → run_campaign(campaign_id, batch_size)            async, poll get_task_status
  → list_prospects(campaign_id, min_score=85)
  → get_prospect(campaign_id, profile_id)            full detail
  → enrich_email / enrich_phone                      async, poll, then get_prospect

To review filters before committing them, call preview_campaign_filters and then apply_campaign_filters rather than train_campaign. Filters can only be derived from a description; there is no way to supply filter JSON directly.

Authentication

The SDKs handle Dynamic Client Registration and the token exchange. Sign in once in a browser as the Splattr account the integration should act as, persist the refresh token, and refresh unattended from then on. Access tokens last one hour. Refresh tokens do not expire on their own.

There is no client_credentials grant, so the initial login has to happen interactively. Everything after it does not.

Two details worth knowing before you build:

Register your own client_id. Refresh tokens carry a generation counter keyed to the client_id. Any new authorization flow for that client_id invalidates every refresh token previously issued for it. That's correct when one client re-authenticates as a different user, but it means two integrations sharing a client_id will knock each other offline, and the failure surfaces days later as "it randomly stopped working."

Refresh tokens rotate. Each refresh issues a new refresh token and invalidates the one you presented. Persist the new value every time, or your client will work exactly once.

Machine-readable tool metadata

The full tool list, with descriptions, JSON Schema for arguments, categories, and async flags:

GET https://mcp.splattr.ai/docs
{
  "tools": [
    { "name": "...", "description": "...", "parameters": { }, "category": "...", "async": false }
  ],
  "categories": [ { "label": "...", "slug": "...", "description": "..." } ]
}

This is the same source the Tools Reference is generated from. Fetching it at build time is more reliable than hardcoding a snapshot.

Troubleshooting

Empty tool result — Treat this as a failure, never as an empty dataset. Every tool returns a non-empty string on success, so an empty response means the call did not execute. Retry rather than proceeding as though there were no results.

train_campaign wiped my context — It replaces the entire training description rather than merging. Calling it again to adjust filters discards the original product and case study context. There is currently no scoped filter-edit tool; re-submit the full description including your changes.

apply_campaign_filters says the preview expired — It commits a server-side preview and must run within 10 minutes of preview_campaign_filters. Re-run the preview.

invalid_grant on refresh — The refresh token was rotated out, or a new authorization flow ran against the same client_id and reset the generation. Re-run the interactive login and store the new token.

unsupported_grant_type — You attempted client_credentials. Use authorization_code to bootstrap and refresh_token after that.

"No authenticated user in context" — The access token expired or was revoked. Refresh it, and re-authenticate if the refresh also fails.