> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://respan.ai/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://respan.ai/docs/_mcp/server.

# MCP (tracing)

> Trace MCP clients and servers with Respan, including tool calls, resources, prompts, and server handlers.

[Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is an open standard for connecting AI applications to tools, prompts, and external context. Respan gives you full observability over MCP client requests, server tool handlers, resource reads, prompt reads, and tool outputs.

> **Note**
>
> MCP does not require the Respan gateway. This integration traces MCP client and server traffic directly, regardless of which model provider your host application uses. If the host also makes LLM calls, you can route those separate calls through the gateway using the relevant provider or framework guide.

#### Set up Respan

Create an account at [platform.respan.ai](https://platform.respan.ai) and grab an [API key](https://platform.respan.ai/platform/gateway/api-keys).

Run `npx @respan/cli setup` to set up with your coding agent.

#### Example projects

* [Python examples](https://github.com/respanai/respan-example-projects/tree/main/python/tracing/mcp)
* [TypeScript examples](https://github.com/respanai/respan-example-projects/tree/main/typescript/tracing/mcp)

## Setup

#### Install packages

**`Python`**

```bash Python
pip install respan-ai openinference-instrumentation-mcp mcp
```

**`TypeScript`**

```bash TypeScript
npm install @respan/respan @respan/tracing @respan/instrumentation-mcp @modelcontextprotocol/sdk
```

#### Set environment variables

```bash
export RESPAN_API_KEY="YOUR_RESPAN_API_KEY"
```

`RESPAN_API_KEY` is used to export traces to Respan.

#### Initialize and run

**`Python`**

```python Python
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from respan import Respan
from openinference.instrumentation.mcp import MCPInstrumentor

respan = Respan(
    app_name="mcp-python-client",
    instrumentations=[MCPInstrumentor()],
)


async def main():
    server_params = StdioServerParameters(
        command="python",
        args=["your_mcp_server.py"],
    )

    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()

            tools = await session.list_tools()
            print(f"Available tools: {[tool.name for tool in tools.tools]}")

            result = await session.call_tool(
                "summarize_city",
                arguments={"city": "Paris"},
            )
            print(result)



asyncio.run(main())
```

**`TypeScript`**

```typescript TypeScript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import { Respan } from "@respan/respan";
import { MCPInstrumentor } from "@respan/instrumentation-mcp";

const respan = new Respan({
  apiKey: process.env.RESPAN_API_KEY,
  baseURL: process.env.RESPAN_BASE_URL,
  appName: "mcp-client",
  instrumentations: [new MCPInstrumentor()],
});
await respan.initialize();

const transport = new StdioClientTransport({
  command: "node",
  args: ["server.js"],
});

const client = new Client({ name: "demo-client", version: "1.0.0" });
await client.connect(transport);

const result = await respan.withWorkflow({ name: "MCP tool call" }, async () => {
  const tools = await client.listTools();
  const toolResult = await client.callTool({
    name: "summarize_city",
    arguments: { city: "Paris" },
  });

  return { tools, toolResult };
});

console.log(result.toolResult);
await client.close();
```

#### View your trace

Open the [Traces page](https://platform.respan.ai/platform/traces) to see your MCP workflow with client operations, server tool handlers, resource reads, prompt reads, inputs, outputs, and timing.

## Configuration

| Parameter              | Type                                  | Default              | Description                                                                                  |
| ---------------------- | ------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------- |
| `api_key` / `apiKey`   | `str \| None` / `string \| undefined` | `RESPAN_API_KEY`     | Respan API key used to export traces.                                                        |
| `base_url` / `baseURL` | `str \| None` / `string \| undefined` | `RESPAN_BASE_URL`    | Optional Respan API base URL.                                                                |
| `app_name` / `appName` | `str \| None` / `string \| undefined` | `None` / `undefined` | Service name shown on exported spans.                                                        |
| `instrumentations`     | `list` / `array`                      | `[]`                 | Plugin instrumentations to activate, such as `MCPInstrumentor()` or `new MCPInstrumentor()`. |
| `customer_identifier`  | `str \| None`                         | `None`               | Default customer identifier for Python spans.                                                |
| `metadata`             | `dict \| None` / `object`             | `None` / `undefined` | Default metadata attached to exported spans.                                                 |
| `environment`          | `str \| None` / `string \| undefined` | `None` / `undefined` | Environment tag, such as `"production"` or `"test"`.                                         |

### MCPInstrumentor options

| Parameter                 | Type                  | Default       | Description                                                                     |
| ------------------------- | --------------------- | ------------- | ------------------------------------------------------------------------------- |
| `captureClientOperations` | `boolean`             | `true`        | Capture MCP client methods including connect, tools, resources, and prompts.    |
| `captureServerTools`      | `boolean`             | `true`        | Capture `McpServer.registerTool()` and `McpServer.tool()` handlers.             |
| `clientModule`            | `object \| undefined` | Auto-imported | Optional explicit `@modelcontextprotocol/sdk/client/index.js` module reference. |
| `serverModule`            | `object \| undefined` | Auto-imported | Optional explicit `@modelcontextprotocol/sdk/server/mcp.js` module reference.   |

## Attributes

### In Respan()

Set defaults at initialization — these apply to exported spans.

**`Python`**

```python Python
from respan import Respan
from openinference.instrumentation.mcp import MCPInstrumentor

respan = Respan(
    app_name="mcp-api",
    instrumentations=[MCPInstrumentor()],
    customer_identifier="user_123",
    metadata={"service": "mcp-api", "version": "1.0.0"},
)
```

**`TypeScript`**

```typescript TypeScript
import { Respan } from "@respan/respan";
import { MCPInstrumentor } from "@respan/instrumentation-mcp";

const respan = new Respan({
  appName: "mcp-api",
  environment: "production",
  instrumentations: [new MCPInstrumentor()],
});
```

### With propagate_attributes

Override per request using a context scope.

**`Python`**

```python Python
from respan import Respan, propagate_attributes
from openinference.instrumentation.mcp import MCPInstrumentor

respan = Respan(instrumentations=[MCPInstrumentor()])


async def handle_request(user_id: str, tool_name: str, args: dict):
    with propagate_attributes(
        customer_identifier=user_id,
        thread_identifier="conv_abc_123",
        metadata={"plan": "pro"},
    ):
        result = await session.call_tool(tool_name, arguments=args)
        print(result)
```

**`TypeScript`**

```typescript TypeScript
await respan.propagateAttributes(
  {
    customer_identifier: "user_123",
    thread_identifier: "mcp-session-abc",
    trace_group_identifier: "MCP request",
    metadata: { plan: "pro", feature: "city-tools" },
  },
  async () => {
    const result = await client.callTool({
      name: "summarize_city",
      arguments: { city: "Paris" },
    });
    console.log(result);
  },
);
```

| Attribute             | Type   | Description                                           |
| --------------------- | ------ | ----------------------------------------------------- |
| `customer_identifier` | `str`  | Identifies the end user in Respan analytics.          |
| `thread_identifier`   | `str`  | Groups related messages into a conversation.          |
| `metadata`            | `dict` | Custom key-value pairs. Merged with default metadata. |