Skip to Content
Rius

How do I trace my agent’s calls to MCP servers?

Rius traces your agent’s outgoing MCP tool calls automatically after you call init in Python or TypeScript, with one span for each call. Python needs nothing extra. TypeScript needs the @modelcontextprotocol/sdk package, which any agent that calls MCP tools already has. Each span records the tool name, the arguments, the result and any failure.

How it works

The MCP instrumentation ships inside the Rius SDK. It turns itself on when the MCP client library can be found: the mcp package in Python, @modelcontextprotocol/sdk in TypeScript. There is no extra to install, and Python has no mcp extra because MCP tracing is built in.

Each tool call becomes a span named execute_tool followed by the tool name. In Python the call goes through mcp.ClientSession.call_tool(). In TypeScript it goes through the MCP SDK’s Client.callTool(). Each span carries:

  • gen_ai.tool.name: the tool being called.
  • input.value: the tool arguments.
  • output.value: the tool result. In Python it prefers structured content and falls back to text blocks.
  • mcp.method.name, set to tools/call.
  • mcp.protocol.version, the negotiated protocol version, when the session exposes it. In TypeScript this covers stdio, SSE and Streamable HTTP for a client that connects after init().
  • gen_ai.agent.name, the agent that made the call: the innermost enclosing agent span you opened with observe or the scoped span helper, otherwise your configured agent name.

The span’s OpenTelemetry kind is CLIENT. A call is marked ERROR when it raises (Python) or rejects (TypeScript), and also when the MCP result itself is flagged as an error. Rius reads is_error and isError, so both major versions of the MCP libraries work. A flagged result sets error.type to tool_error and keeps its output, because the error content is what you need to see.

When a tool call comes back asking for more input, that round records no output, since an input request carries conversation content. Its span still has mcp.method.name set to tools/call, so the round counts as an MCP tool call. The final round of the same call records its output as usual.

Argument and result values are content attributes, so the same privacy controls apply to them as to prompts. For example, RIUS_CAPTURE_CONTENT set to false strips them at export.

Set it up

  1. Make sure the MCP client library is installed. In Python, the mcp package is already there if your agent calls MCP tools, so there is nothing to add. In TypeScript, @modelcontextprotocol/sdk must be resolvable. If it is not in your project yet, install it:

    npm install @modelcontextprotocol/sdk
  2. Call init() once, before you make tool calls, and keep using your MCP client as before. In Python:

    import rius rius.init(api_key="ri_...", service_name="my-agent") # use mcp.ClientSession exactly as before

    In TypeScript:

    import { init } from '@glassflow-ai/rius' init({ apiKey: 'ri_...', serviceName: 'my-agent' }) // use the MCP SDK's Client exactly as before
  3. In TypeScript, init() patches the MCP SDK’s Client class itself, so every client you construct afterwards is traced. In a CommonJS application, require the MCP SDK before init(). The SDK patches the copies of Client already in your process, and a copy first required later stays untraced.

  4. Run the agent and open the trace. Each MCP call shows as an execute_tool span. The MCP integration page has the full reference, and Integrations lists the other libraries and frameworks Rius traces.

What you get

  • A span for every outgoing MCP tool call, with the tool name, arguments and result, in both Python and TypeScript.
  • Failures that stand out. Raised or rejected calls and error-flagged results all get ERROR status, and the error content stays visible.
  • The calling agent’s name on each call, so you can see which agent used which tool.
  • One waterfall across your agent and the MCP server, in Python on mcp 2.x. Trace context propagates through the call, so the server’s spans appear under your agent’s execute_tool span. This needs two things. The server must be instrumented, with the Rius SDK or any OpenTelemetry SDK. It must also export its traces to Rius with an API key for the same workspace as your agent.
  • Separate but queryable traces in the other cases. On mcp 1.x, and in TypeScript, an instrumented server’s spans still arrive, but as their own traces. The timestamps line up, but there is no single waterfall across the call.

When something else fits

This integration traces your agent calling MCP servers. If you want AI clients such as Claude Code or Codex to query your Rius telemetry, that is the separate Rius MCP server, and it works independently of this integration. If you need nested server spans in TypeScript, the SDK does not propagate context there, so you compare the two traces side by side.

Still stuck? Get help

Last updated on