MCP server

Connect Claude, Cursor, or any MCP-capable agent to OakData and let it read real user behaviour as first-class tools.

OakData ships a remote Model Context Protocol server at https://oakdata.co/api/mcp. Point an MCP-capable agent — Claude Code, Claude Desktop, Cursor, or your own — at it with a secret key, and the agent gets first-class tools for reading the project's real user behaviour: traffic overviews, individual visitor journeys, funnels and drop-off, who's live right now, raw events, and session replays. The agent can investigate a bug, watch how users actually behave, and fix it — without leaving the editor.

Why this matters

The REST API is for code you write. The MCP server is for the agent itself: it can decide to call get_journey to find where users drop off, then get_visitor to see one person end to end — all in the flow of a conversation.

How it works

The server is a stateless JSON-RPC 2.0 endpoint over the MCP Streamable HTTP transport (protocol version 2025-06-18). Every request is authenticated with a secret key as a bearer token and scoped to exactly one project, so a key for project A can never read project B. It speaks the standard initialize, tools/list, tools/call, and ping methods — any compliant MCP client works.

Connecting

Claude Code

Add the server with the CLI:

Terminal
bash
claude mcp add --transport http oakdata https://oakdata.co/api/mcp \
  --header "Authorization: Bearer oak_sec_xxxxxxxxxxxxxxxxxxxxxxxx"

Cursor & JSON-configured clients

Most clients (Cursor, Claude Desktop, Windsurf, …) take an mcpServers JSON block. Add OakData as an HTTP server with an Authorization header:

{
  "mcpServers": {
    "oakdata": {
      "url": "https://oakdata.co/api/mcp",
      "headers": {
        "Authorization": "Bearer oak_sec_xxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

Use a secret key

The MCP server requires a secret key (oak_sec_…). Public keys are rejected. Treat the key like a password — store it in your client's secret config, not in a committed file.

Tools

The server exposes nine read tools. They map one-to-one onto the REST API, so the response shapes are the same.

ToolTypeDescription
get_overviewrange?, exclude_bots?Headline traffic & conversion for a window — visitors, pageviews, sessions, bounce, duration, and top pages/referrers/sources/campaigns/countries/browsers/devices. Start here.
list_sessionsrange?, limit?Recent sessions with visitor, entry page, duration, device, and location. limit 1–200, default 50.
get_sessionsession_idThe full ordered event timeline for one session id — every pageview, click, and custom event with properties.
get_visitordistinct_idOne visitor's full profile by distinct id or anonymous id: user id, traits, groups, first/last seen, lifetime events, recent sessions — including pre-signup activity.
get_journeyrange?The aggregated path/funnel tree for a window: common routes and where people drop off. Answers 'where are we losing people?'
live_nowSessions active in the last 5 minutes, with their ids and last-seen timestamps. A real-time pulse.
list_eventsoffset?, limit?The raw event firehose, newest first, paginated. limit 1–500, default 100. For debugging tracking or inspecting custom properties.
list_replayslimit?Recorded replays, newest first, with visitor, entry url, duration, device, and whether the session hit errors. limit 1–200, default 100.
get_replayreplay_idOne replay by its recording id: metadata plus short-lived signed URLs for each rrweb chunk a player can fetch and replay.

For range, valid values are 24h, 7d, 30d, and 90d (default 7d). Tool results are returned as JSON text content; tool- execution errors are reported in-band (with isError) so the agent can recover and try a different call.

Try it

Once connected, ask your agent things like:

prompts
text
"Use OakData — where are visitors dropping off in the signup funnel this week?"

"Pull up the last 10 sessions that hit an error and summarize what they were doing."

"Who's on the site right now, and what pages are they on?"

"Look up visitor user_8f3a and tell me their whole history."

Stateless & batchable

The server keeps no session state — each POST is authorized on its own. It accepts a single JSON-RPC message or a batch array, and only answers POST(there's no server→client SSE stream).