MCP server

Ask your analytics from Claude, Codex, Cursor or any MCP client. ClickClacks runs a read-only, remote MCP server with twelve tools, scoped by a key, and every answer says where its numbers came from.

Updated

Want to see it first? The MCP feature page shows a conversation. This page covers setup and every detail. Sending events in, rather than reading them out? That’s the server API.

Endpoint

http
POST https://app.clickclacks.io/api/v1/mcp
Authorization: Bearer cka_live_…
Content-Type: application/json
  • Streamable HTTP, stateless and tools-only. Clients send JSON-RPC with POST. There are no sessions and no Mcp-Session-Id.
  • GET and SSE streaming aren’t supported: a GET with a valid key gets 405.
  • Supports the initialize, ping, tools/list and tools/call methods, and protocol versions from 2024-11-05 to 2025-11-25.
  • Every tool is read-only. Nothing a client does can change your data.

Keys

MCP uses MCP & analytics keys (cka_live_…). Create one in Settings › API access: give it a name such as “Reporting agent”, and copy the secret, which is shown once. Settings › MCP shows the server URL, whether you have an active key, and the setup snippets.

  • The key decides the project. Tool arguments never take an organization or project ID; a call that includes one is refused.
  • Read-only, with the single scope analytics:read.
  • Revoke a key in Settings › API access to disconnect every client that uses it. Missing, invalid or revoked keys get HTTP 401.
  • Creating and revoking keys needs permission to manage API credentials in your organization.

Connect a client

Pick your client. Every configuration needs the same two things: the URL and the Authorization header.

terminal
claude mcp add --transport http clickclacks https://app.clickclacks.io/api/v1/mcp --header "Authorization: Bearer cka_..."

The command Settings › MCP shows. Replace cka_... with your key.

To check it worked, ask the client to list its ClickClacks tools, or ask “Which ClickClacks sources are sending events?”, which calls list_sources.

Tools

Nine read-only tools for reports, and three more for companies. Every one also takes optional start and end dates. Schemas are strict: an argument that isn’t listed is refused.

ToolArguments besides datesReturns
overviewReport filters.Overview KPIs and the visitors series.
list_funnelsDates only.Saved funnels: steps, ordering, count mode and window, with summary metrics when available.
funnel_resultsfunnelId (required); breakdown, an event property.One saved funnel run in its saved ordered or unordered, people or events mode, optionally split by the property.
retentionReport filters; interval: daily, weekly (default) or monthly.The saved retention definition and its cohort grid.
list_eventsReport filters; search, an exact event name; cursor, for the next page.Event rows, a page at a time: pass the returned cursor for the next page.
event_breakdownsReport filters; dimension: pages, referrers, countries or events.Top pages, referrers, countries and event names, or just one of them.
list_segmentsDates only.Saved segments, with people counts when available (otherwise null).
list_sourcesDates only.Sources with their event and people counts for the window, and health from each one’s last event.
friction_findingsstate: happening (default), stopped or muted.Friction findings in that state last seen in the window. people7d is the finding’s rolling seven-day count.

Tools for companies

A group is an account your events are stamped with: a company, a workspace, a team. Each project names its own types, so start with list_group_types. Companies and groups explains the model.

ToolArguments besides datesReturns
list_group_typesDates only.The group types the project shows, in order: groupType (the key, such as company), labelSingular and labelPlural. Hidden types are left out. Call it first.
list_groupsgroupType (required); search, matched against the ID and the name; sort: last_seen (default), events, members or name; cursor, for the next page.A page of 50 groups of that type: groupId, name, firstSeen, lastSeen, events and activeMembers in the window, and totalEvents. total counts every match, and page.nextCursor continues the list.
group_profilegroupType and groupId (both required).One group: its name, first and last seen, total events, traits, traitsWithheld and traitsUpdatedAt; metrics and previousMetrics (activeMembers, events, activeDays for the window and the equally long window before it); and members.
event_breakdownsIts usual arguments, plus count_by, a groupType.The same four lists, counting unique groups of that type instead of people. countBy names the type. Each row has label, count and unstampedShare; event rows also have eventCount.
funnel_resultsIts usual arguments, plus count_by, a groupType.The saved funnel counting the groups of that type instead of people. countBy names the type and counted is its plural, such as companies. Every count that reads people on a people funnel reads count, the count mode reads unique_companies, and results.unstampedShare is the share of the funnel’s step events that carry no group of the type.
retentionIts usual arguments, plus count_by, a groupType.The retention grid with cohorts of groups of that type instead of people. countBy and counted name the type, totalPeople reads totalCount, and results.unstampedShare is the share of the report’s events that carry no group of the type.

What these tools return is about companies, never about a person:

  • Traits. Secrets are dropped, as everywhere in ClickClacks. So is any trait that holds personal data: one named like email, phone, ip, address or password, or whose value reads as an email address or a phone number. Those traits are named in traitsWithheld and their values aren’t returned, even when the source is allowed to store them. A name that reads as an email address or a phone number comes back as null.
  • Members are never identified. members.active is how many people had events for the group in the window. members.top lists up to ten of the most active as rank, events and shareOfEvents, with no person ID, name, email or session. No argument turns identifiers on.
  • A groupType the project doesn’t show, because it is unknown or hidden in Lexicon, is refused with a pointer to list_group_types.

With count_by on event_breakdowns:

  • Only events stamped with a group of that type count. unstampedShare is the share, from 0 to 1, of the row’s events that carry none and are left out.
  • Pages, referrers and countries are read from pageviews. A group sits in every row it has a pageview for, so rows can add up to more than the number of groups.
  • Each list holds the five values with the most events, ordered by unique groups.
  • Report filters apply as usual, and can name a group: g:company is the group’s ID, and g:company.plan a trait of the event’s group, as in { "property": "g:company.plan", "values": ["pro"] }.

With count_by on funnel_results and retention:

  • A group enters a funnel at its first step-one event in the window, from any member, and completes each later step on the earliest matching event stamped with that group, again from any member, inside the conversion window. So when one person signs up and a colleague sends the first invite, the company converts.
  • A retention cohort holds the groups whose first starting event falls in the period. A group is back in a later period when any of its members’ events is.
  • A funnel counted by a group type is never counted by session: sessions belong to people, so a funnel saved in events mode is read as unique groups.
  • Left out, the report counts what it was saved to count: a funnel or retention definition saved with Count by Companies answers in companies. list_funnels does the same for each funnel it lists, with counted on the definition and on its row.
  • A saved Count by whose type the project no longer shows, because it is hidden in Lexicon, is read counting people.
  • With an agency key, these tools take the project argument like every other tool.
  • If the project’s group data can’t be read, the answer is degraded with a reason and data: null.

Questions to ask

You ask in plain language; the client picks the tools. Some that work well, and the tools they use:

AskTools
“Which step of our signup funnel loses the most people this month? Show the numbers.”list_funnels, funnel_results
“Compare weekly retention for the last eight weeks. Is any cohort clearly weaker?”retention
“What are our top referrers this month, and how does that compare with last month?”event_breakdowns
“Is every source still sending? Which one went quiet?”list_sources
“What friction is happening right now, and on which pages?”friction_findings, event_breakdowns
“How many visitors did we have yesterday, only on the pro plan?”overview with a property filter
“Which companies were most active this month, and which of them are on the Pro plan?”list_group_types, list_groups, group_profile
“Which events do the most companies use, and how many events carry no company?”event_breakdowns with count_by
“What share of companies that start a trial reach their first invite?”list_funnels, funnel_results with count_by

Adding “cite the provenance” or “stop if the data is degraded” to a prompt keeps an agent honest about what it actually read.

Dates and filters

  • start and end are YYYY-MM-DD dates. Send both or neither. The range is inclusive, end can’t be before start, and a window is at most 3,660 days.
  • Without dates, a tool reads the last 30 days including today, in the project’s reporting time zone (Settings › General).

overview, retention, list_events and event_breakdowns also take report filters: a sourceId, a saved segmentId, and up to 20 propertyFilters, each with up to 100 values.

  • operator is is (the default), is_not, contains, not_contains, is_set, is_not_set, gt, lt or between. is_set and is_not_set take no values, gt and lt one, and between two (inclusive). Bounds are numbers or YYYY-MM-DD dates. contains ignores case.
  • applyTo is matching-events (only events that match count) or people-ever-matched (everything from people who ever matched).
  • Every ID is resolved inside the key’s project.
arguments
{
  "start": "2026-08-01",
  "end": "2026-08-31",
  "sourceId": "src_…",
  "segmentId": "seg_…",
  "propertyFilters": [
    { "property": "plan", "operator": "is", "values": ["pro"], "applyTo": "matching-events" },
    { "property": "amount_cents", "operator": "gt", "values": ["5000"], "applyTo": "matching-events" }
  ]
}

Provenance

Every successful call returns its answer twice: structuredContent with data and provenance for programs, and a text version, with the same provenance, for the model reading it.

structuredContent
{
  "data": { … },
  "provenance": {
    "window": { "start": "2026-08-25", "end": "2026-08-31", "timeZone": "Europe/London" },
    "filters": { "interval": "weekly" },
    "scope": {
      "organizationId": "org_…",
      "projectId": "prj_…",
      "label": "organization org_… / project prj_…"
    },
    "freshness": { "dataAsOf": "2026-08-31T21:14:03.000Z", "cache": "not-exposed" },
    "degraded": false,
    "reason": null,
    "definitionHash": "…"
  }
}
  • window is the dates that were read, with the timeZone when the project doesn’t report in UTC.
  • filters records every accepted argument other than the dates, including defaults such as interval.
  • scope always comes from the verified key.
  • freshness.dataAsOf is the newest timestamp in the answer. cache is not-exposed: ClickClacks doesn’t guess whether a result was cached.
  • definitionHash identifies the saved definition behind list_funnels, funnel_results, retention and list_segments.

When a report can’t be read, degraded is true, reason says what’s missing, and the numbers come back as null. Saved definitions, such as a funnel’s steps, can still come back. Treat a degraded answer as unknown, never as zero.

Agency keys

An agency that manages several client organizations can use one key for all of them. Agency owners and admins create agency keys (cka_agency_…) in Agency settings › MCP keys. Agency keys are part of the Pro plan.

  • It reads what its creator can open, right now. The key stores no project list; access is checked on every call. Remove the creator from a project and the key stops reading it; remove them from the agency and the key stops working.
  • Every tool takes a project argument, a slug or ID as list_projects returns it. It’s required unless the key can read exactly one project.
  • list_projects lists the projects the key can read, with slug, ID, time zone, source count and events this month.
  • compare_projects compares visitors (the default) or events across projects over the same calendar dates, each in its own time zone, sorted high to low. A total is given for events only, since visitors don’t add up across projects.
  • Every call is logged per project it read, and the key list shows each key’s calls over the last 30 days. Any agency owner or admin can revoke any agency key.

Rate limits and errors

  • Each key can make about 120 requests a minute. The limit is approximate: it’s counted per server instance, not globally.
  • Responses carry X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset.
  • Over the limit, a call gets the JSON-RPC error -32029 with retryAfterSeconds, and a Retry-After header.
  • Bad arguments get -32602, an unknown method -32601, and a report that can’t run -32603. An agency key whose agency isn’t on a plan with agency keys gets -32003.
  • Responses are sent with Cache-Control: private, no-store.

Next steps