MCP server

MCP server

Pulse speaks the Model Context Protocol, so an AI assistant can read your analytics directly. Ask “which source made me the most money this month?” and it calls Pulse for the answer.

Connect#

  1. Create an API key

    Settings, API & MCP. The same pk_… key works for the REST API and MCP. It can read every site on your account, so keep it private.

  2. Add the server to your client

    The endpoint is https://stats.shedi.app/api/mcp, using Streamable HTTP with your key as a bearer token.

    claude mcp add --transport http pulse https://stats.shedi.app/api/mcp --header "Authorization: Bearer pk_YOUR_KEY"
  3. Ask something

    Restart the client if needed, then try one of the prompts below.

Tools#

ToolArgumentsReturns
list_sites–The sites on the account: id, name, domain, time zone, source.
get_statssite, periodVisitors, pageviews, visits, bounce rate, sales and revenue (net of tax) with the previous period, top sources, channels, pages, countries, devices, and a daily series. Same as /api/v1/stats.
get_revenue_by_sourcesite, periodRevenue, orders, visitors, conversion and revenue per visitor by first-visit source, channel, campaign, landing page, country, device and post, plus the revenue mix (new, renewals, refunds, MRR) and lifetime value by source. In USD. Same as /api/v1/revenue.
get_top_pagessite, periodTop pages by visitors, with the revenue each landing page led to.
get_revenue_by_postsite, periodRevenue and visitors by the exact post or URL that sent them (referring URL or utm_content).
compare_periodssite, periodThis period against the one before: each number with its change and percent change.
get_funnelsite, steps, window, periodOne site tracked by the Pulse script. Steps are {type:"path"|"event", value}; the last may be {type:"payment", value:"paid"}. See Funnels.
get_livesitePer site: active visitors in the last 5 minutes, current pages, sources, and the ten visitors most likely to buy with their reasons.
  • site is a site id, a domain, or all (the default).
  • period is a number of days (1 to 365) or a range YYYY-MM-DD..YYYY-MM-DD. The default is 30. A value that is neither returns a JSON-RPC error (-32602) instead of silently using 30.
  • Channel names are the readable labels (Organic social) in every tool, with the stable id (organicSocial) alongside.
  • Money is US dollars, net of tax. Visitor-written text (page paths, referrers, campaign and event names) is cleaned, and the tool descriptions tell the assistant to treat it as untrusted data.

Example prompts#

  • “Which source made me the most money in the last 30 days?”
  • “Compare visitors and revenue this week with last week, and tell me what changed.”
  • “Which landing pages bring paying customers, not just visitors?”
  • “Who is on my site right now, and is anyone likely to buy?”
  • “Between 2026-09-01 and 2026-09-30, how much revenue came from social channels?”
  • “Write me a three-line Monday summary of how example.com is doing.”

For the curious: the protocol#

The endpoint is stateless: it accepts POST with JSON-RPC 2.0 (one message, or a batch of up to 10) and answers with plain JSON, never a stream. GET returns 405. It supports protocol versions 2025-06-18, 2025-03-26 and 2024-11-05, and the methods initialize, ping, tools/list and tools/call.

bash
curl -X POST https://stats.shedi.app/api/mcp \
  -H "Authorization: Bearer pk_YOUR_KEY" \
  -H "content-type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_stats","arguments":{"site":"all","period":"30"}}}'

Limits: 60 calls a minute per account, and a batch of N counts as N calls (429 with a JSON-RPC error and a Retry-After header); a request body over 64 KB is refused (413); an empty batch is an invalid request (-32600); 401 without a valid key, and 429 after 60 invalid keys a minute from one address.

Common issues#

The client says unauthorized (401)
Check the header reads Authorization: Bearer pk_… and that the key was not revoked.
The client wants OAuth or a login
Pulse authenticates with the bearer key only. Use a client or bridge that lets you set a header, as in the examples.
The assistant says it cannot find the tools
Restart the client after adding the server, and check it lists pulse as connected.
Answers look empty
Check list_sites first. A new site shows zeros until the script reports its first visit.