Available via: auto-instrumentation of the official MCP client packages (TypeScript and Python), plus
mcpServerTool() / @mcp_server_tool for tools in your own MCP server. Nothing to configure; one switch turns it off.What is traced
Each call through a patched MCP client becomes anmcp_client span (see Span kinds):
- “Was the tool listed” needs a
tools/listcall earlier in the same client. A call made before any list is recorded without this answer (never as “not listed”), and so is a call made when only the first page of a paged list was read. - “Do the arguments fit” is checked in your process against the schema the server sent: required keys and JSON types only. The answer is
true,falseorunknown(when the schema uses something the SDK doesn’t check).falseis recorded only for a definite miss. - A result the server flagged as an error is recorded as a tool error, not as a connection failure. A closed connection or a timeout is recorded as such. Servers differ in how they report an unknown tool (an error result on some, a JSON-RPC error on others); the recorded “was the tool listed” answer is the same either way.
- Hashes are of the schema with the serializer’s noise removed (
$schemaand a top-leveladditionalProperties: false), so upgrading the library a server is built with doesn’t look like the tool list changing.
signal in TypeScript, a cancelled task in Python) is not recorded as a failure.
Supported clients
- TypeScript
- Python
@modelcontextprotocol/sdk (1.x) and @modelcontextprotocol/client (2.x), either or both. Tested with @modelcontextprotocol/sdk 1.30.1, 1.31.0 and 1.32.1 and @modelcontextprotocol/client 2.3.1. Both are optional peer dependencies: nothing is installed for you.Python: one record per call
Version 2 of themcp package emits its own OpenTelemetry client span for every request. When Zespan’s OpenTelemetry exporter is installed and pointed at Zespan (enable_otel=True with otel_endpoint set), that span reaches Zespan, so the SDK adds its attributes to it (the span is closed a moment later, after the result is known) and sends nothing else. Without the exporter, inside a Zespan trace (where the library’s span would sit in another trace), or for a call you cancelled, the SDK leaves the library’s span alone and records the call itself. Either way a call is recorded at most once.
Turn it off
SetmcpAutopatch: false (TypeScript) or mcp_autopatch=False (Python) in the SDK options, or set the environment variable ZESPAN_MCP_AUTOPATCH=off. It is read at call time, so you can switch it without restarting a long-lived process that already created clients.
Your own MCP server
Wrap the handler of a tool in your own MCP server so each call is anmcp_server_tool span that joins the caller’s trace from the request’s _meta.traceparent. Model calls and other work inside the handler nest under it.
- TypeScript
- Python
traceparent is simply not joined; the call is still recorded in the current trace.
Tools from MCP adapters
Tool spans from an MCP adapter in Google ADK, LangChain and the Vercel AI SDK carry the tool name asmcp_tool_name (and zespan.mcp.server when the adapter names the server). No span is added. An adapter is recognised by its class name (ADK’s McpTool), its module in Python, or by an mcp_server key in the tool’s metadata. The LangChain MCP adapters build ordinary structured tools, so for LangChain add mcp_server to the tool’s metadata; for the Vercel AI SDK, put it in experimental_telemetry.metadata.
ADK and the LangChain adapters call the official MCP client underneath, so the same call is usually also an mcp_client span.
Where it shows up
- The spans appear in the trace view with the span kind
mcp_client(ormcp_server_tool). - Each
tools/callis also stored as an MCP tool call, with the server name and version, the JSON-RPC error code and the schema hashes. - Zespan uses the recorded answers (tool listed, arguments valid, error code, tool error, connection failure, tool list changed together with a server version change) to say whether a failed MCP call started with the model or with the MCP server.
Limits
- A tool the model provider runs on its own servers (a hosted MCP tool inside a model call) never passes through your client and can’t be seen.
- Whether the protocol version is recorded depends on the client library: version 1 of the TypeScript client has no accessor for it, so it is recorded only when the transport reports it.
- The OpenTelemetry conventions for MCP are still changing; Zespan maps the current attribute names and keeps the older error-code name readable.
Next steps
Google ADK
Agents built with ADK, including MCP toolsets.
Span kinds
Where
mcp_client and mcp_server_tool sit among the other kinds.Environment variables
The
ZESPAN_MCP_AUTOPATCH switch.OpenTelemetry
Send MCP spans from any OpenTelemetry setup.

