MCP analytics: what your logs can and can't show
Server-side MCP analytics show who called which tool. They can't show the calls that never happened. What each method sees, and how to fill the gap.
Updated 30 October 2026
MCP analytics usually means logging what reaches your server. That is worth doing, and it answers real questions: which tools get used, by which clients, how often they fail. It cannot tell you why the calls went down.
What your server can see
Your server receives requests, so it can record anything in them.
- Which client connected. On older protocol versions, the
initializerequest carriesclientInfowith a name and version. In the 2026-07-28 spec there is no handshake, and each request carriesio.modelcontextprotocol/clientInfoin_meta. Either way the value is self-reported, and the schema says it is for display, logging and debugging. - Tool lists and tool calls.
tools/listandtools/callare plain JSON-RPC requests. You get the tool name and the arguments, and you can measure duration and errors yourself. - The method, from HTTP headers. On 2026-07-28 Streamable HTTP,
Mcp-MethodandMcp-Namemirror the method and tool name into headers, so a gateway can log them without parsing the body.
What your server can’t see
- The prompt. The user’s message goes to the model, not to you.
- The decision. In the spec’s flow, the model picks a tool on the client side. Your server hears about it only if the answer is yes. A skipped call produces no request, so it leaves no trace.
- Whether the model saw your tool at all. A
tools/listrequest doesn’t mean your tool is in the model’s context. Claude Code defers MCP tools by default: only names and server instructions load at session start, and definitions load on demand. - Every session. Clients may cache the tool list. The 2026-07-28 spec adds
ttlMsandcacheScopefor this, so list requests undercount sessions.
So when a graph goes quiet, your logs can’t separate three different situations:
- Fewer people are asking for what your tool does.
- People ask just as often, and agents now answer another way.
- Agents no longer load or see your tool.
The first is a market problem. The other two are problems you can fix, usually in the tool description, but only if you know which one you have.
What to log anyway
Keep this small. You want to be able to answer “which tool, which client, did it work”.
| Field | Why |
|---|---|
| Method and tool name | The base count for everything else |
| Client name and version | Shows when one agent changes while others don’t |
| Duration and error flag | Separates “not called” from “called and failed” |
| Protocol version | Shows which clients have moved to the newer spec |
OpenTelemetry has draft semantic conventions for MCP, still marked as in development. They name spans {mcp.method.name} {target}, for example tools/call track_order, and use attributes such as mcp.method.name, gen_ai.tool.name and mcp.protocol.version. Following them now saves a migration later. Tool arguments and results are opt-in there, which is a sensible default for privacy.
What the existing tools measure
These products do what they say. All of them work from events your server sends.
| Tool | What it records | Worth knowing |
|---|---|---|
| PostHog MCP Analytics | Tool calls, tool lists, reported models, failures, and requests for missing capabilities | In beta. Its docs include a query for advertised tools that are never called |
| AgentCat (docs.mcpcat.io redirects here) | Tool, resource and prompt events, client info, sessions, and the agent’s goal | Groups stateless traffic into sessions by user, client and a 30-minute window |
| OpenTelemetry | Whatever you instrument, in your own backend | Conventions are still in development |
PostHog and AgentCat can both add a context argument to your tool schemas, so the agent explains why it is calling. That is useful intent data, but it only exists for calls that happen.
A “never called” query is the closest a log gets to the real gap. It finds tools nobody uses at all. It can’t tell you that a tool used to be called on 84% of order questions and is now called on 31%, because a log has no count of the questions.
How to see the calls that didn’t happen
You have to measure from the agent’s side: put a known number of prompts in, and count how many produce a call.
- Write the prompts your users would type. OpenAI’s golden prompt set is a good recipe: direct prompts that name your product, indirect prompts that only describe the outcome, and negative prompts where another tool should handle it.
- Run each one several times in each agent. The same prompt doesn’t always produce the same tool call, so one run proves little.
- Count calls in your own server log. That is your ground truth, and it works for any agent.
- Repeat on a schedule. Models and agent apps change without you releasing anything. A number you measured once won’t warn you about that.
How to test an MCP server has the commands for each agent.
Uncalled is step 4 as a service: the same prompts, every day, in each agent, with an alert when the rate drops. It isn’t live yet. If you want the number for your server before then, send the URL to hello@uncalled.app and I’ll run it by hand.