- Wrap the transport once instead of editing every tool.
- One seam captures name, arguments, result, timing, and client.
- Redact in-process, sample high volume, and always fail open.
The naive way to add analytics to an MCP server is to edit every tool. It does not scale, it drifts, and new tools ship uninstrumented. There is a better seam: the protocol itself.
One seam, total coverage
Every tool call flows through the same request/response path. If you wrap the server once at that boundary, you see every call, its arguments, its result, timing, and the client, with no per-tool code.
import { withTrackMCP } from "@trackmcp/sdk";
import { server } from "./mcp";
export default withTrackMCP(server, {
apiKey: process.env.TRACKMCP_KEY,
service: "acme-mcp-server",
});What the wrapper sees
- The tool name and arguments (after local redaction)
- The result and whether it carried isError
- Client type, duration, and transport status
- A session id, so calls can be replayed in order
Keep it safe and cheap
Redact sensitive fields in-process before anything leaves. Sample if volume is high. Fail open: analytics should never be able to break a tool call. Done right, instrumentation costs a line of code and a sub-millisecond hop.
See this on your own server
TrackMCP turns your MCP server's calls into adoption, workflows, and outcomes. One line to install.