---
title: "MCP Monitoring"
description: "Monitor MCP server tool executions, prompt retrievals, resource access, and errors."
url: https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring/
---

# Set Up MCP Monitoring | Sentry for Cloudflare

With Sentry's [MCP Monitoring](https://docs.sentry.io/product/mcp-servers.md), you can track and debug MCP servers with full-stack context. You can monitor tool executions, prompt retrievals, resource access, and error rates alongside your other Sentry data, including logs, errors, and traces.

Before you begin, [set up tracing](https://docs.sentry.io/platforms/javascript/guides/cloudflare/tracing.md).

## [Instrument the MCP Server](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#instrument-the-mcp-server)

Wrap each `McpServer` instance with `wrapMcpServerWithSentry` to automatically record MCP requests, tool calls, prompt retrievals, resource reads, and handler errors.

Import Sentry from your framework's SDK package, then wrap the MCP server instance before connecting it to a transport:

```javascript
import * as Sentry from "<sdk-package-name>";
import { McpServer } from "@modelcontextprotocol/server";

const server = Sentry.wrapMcpServerWithSentry(
  new McpServer({
    name: "my-mcp-server",
    version: "1.0.0",
  }),
);
```

Register tools, prompts, and resources on `server` as usual. The wrapper returns the same server instance.

Support for `@modelcontextprotocol/server` 2.x requires Sentry JavaScript SDK version `10.70.0` or newer. For `@modelcontextprotocol/sdk` 1.x, use Sentry JavaScript SDK version `9.46.0` or newer and import `McpServer` from `@modelcontextprotocol/sdk/server/mcp.js`. The Sentry wrapper is otherwise the same.

### [Configure Input and Output Recording](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#configure-input-and-output-recording)

MCP inputs and outputs may contain sensitive data. Use `recordInputs` and `recordOutputs` to control collection for a specific server:

```javascript
const server = Sentry.wrapMcpServerWithSentry(mcpServer, {
  recordInputs: false,
  recordOutputs: false,
});
```

These options override the corresponding `dataCollection.genAI.inputs` and `dataCollection.genAI.outputs` settings and require Sentry JavaScript SDK version `10.33.0` or newer.

## [Preserve MCP Spans After the Response](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#preserve-mcp-spans-after-the-response)

Cloudflare MCP work can finish after the Worker returns an HTTP response, including work kept alive with `waitUntil()`. With the static trace lifecycle, Sentry snapshots the request transaction when the response is returned, so MCP spans that finish later may be missing.

Set `traceLifecycle: "stream"` so the SDK can send each sampled span when it finishes. This changes how spans are delivered; you still need to wrap the MCP server as shown above. Span streaming on Cloudflare requires `@sentry/cloudflare` version `10.49.0` or newer.

```javascript
import * as Sentry from "@sentry/cloudflare";

const worker = {
  async fetch(request, env, ctx) {
    return handleMcpRequest(request, env, ctx);
  },
};

export default Sentry.withSentry(
  (env) => ({
    dsn: env.SENTRY_DSN,
    tracesSampleRate: 1.0,
    traceLifecycle: "stream",
  }),
  worker,
);
```

Stream mode sends span records instead of assembling one transaction event with embedded spans. `beforeSendTransaction` and `ignoreTransactions` don't apply to streamed spans. See [Streamed Spans](https://docs.sentry.io/platforms/javascript/guides/cloudflare/tracing/streamed-spans.md) for the `beforeSendSpan` and `ignoreSpans` configuration.

If you use `McpAgent`, wrap the `McpServer` returned by its `server` getter, and wrap the Agent class separately with `instrumentAgentWithSentry` to preserve request and RPC context. Agent instrumentation, MCP server wrapping, and span streaming solve different parts of the setup; none replaces the others. See [Agents SDK](https://docs.sentry.io/platforms/javascript/guides/cloudflare/features/agents-sdk.md).

## [Manual Instrumentation](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#manual-instrumentation)

The setup above automatically instruments MCP servers built with the official [MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) (`@modelcontextprotocol/sdk`). If your server uses a different library or a custom implementation that `wrapMcpServerWithSentry` can't wrap, you can record the same spans manually.

You don't need this if you're already using `wrapMcpServerWithSentry` — it creates these spans for you. Otherwise, use [Sentry.startSpan()](https://docs.sentry.io/platforms/javascript/tracing/instrumentation/custom-instrumentation.md#starting-a-span) to create the spans described below.

## [Spans](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#spans)

### [Tool Execution Span](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#tool-execution-span)

Describes MCP tool execution.

* The span `op` (transaction mode) or the span's `sentry.op` attribute (stream mode) MUST be `"mcp.server"`.
* The span `name` SHOULD be `"tools/call {mcp.tool.name}"`.
* The `mcp.tool.name` attribute MUST be set to the tool's name. (e.g. `"get_weather"`)
* The `mcp.method.name` attribute SHOULD be set to `"tools/call"`.
* All [Common Span Attributes](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#common-span-attributes) SHOULD be set.

Additional attributes on the span:

| Data Attribute                  | Type    | Requirement Level | Description                                              | Example                                           |
| ------------------------------- | ------- | ----------------- | -------------------------------------------------------- | ------------------------------------------------- |
| `mcp.tool.name`                 | string  | required          | The name of the MCP tool being called.                   | `"get_weather"`                                   |
| `mcp.method.name`               | string  | recommended       | Should be set to "tools/call".                           | `"tools/call"`                                    |
| `mcp.request.id`                | string  | optional          | The unique identifier for the MCP request.               | `"req_123abc"`                                    |
| `mcp.request.argument.*`        | any     | optional          | Tool input arguments (requires `send_default_pii=True`). | `"San Francisco"` for `mcp.request.argument.city` |
| `mcp.tool.result.content`       | string  | optional          | The result/output content from the tool execution.       | `"The weather is sunny"`                          |
| `mcp.tool.result.content_count` | int     | optional          | The number of items/keys in the tool result.             | `5`                                               |
| `mcp.tool.result.is_error`      | boolean | optional          | Whether the tool execution resulted in an error.         | `True`                                            |

#### [Example Tool Execution Span:](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#example-tool-execution-span)

```javascript
// Example tool execution
const toolName = "get_weather";
const toolArguments = { city: "San Francisco" };

await Sentry.startSpan(
  {
    op: "mcp.server",
    name: `tools/call ${toolName}`,
  },
  async (span) => {
    // Set MCP-specific attributes
    span.setAttribute("mcp.tool.name", toolName);
    span.setAttribute("mcp.method.name", "tools/call");

    // Set request metadata
    span.setAttribute("mcp.request.id", "req_123abc");
    span.setAttribute("mcp.session.id", "session_xyz789");
    span.setAttribute("mcp.transport", "stdio"); // or "http", "sse" for HTTP/WebSocket/SSE
    span.setAttribute("network.transport", "pipe"); // or "tcp" for HTTP/SSE

    // Set tool arguments (optional, requires recordInputs: true)
    for (const [key, value] of Object.entries(toolArguments)) {
      span.setAttribute(`mcp.request.argument.${key}`, value);
    }

    // Execute the tool
    try {
      const result = executeTool(toolName, toolArguments);

      // Set result data
      span.setAttribute("mcp.tool.result.content", JSON.stringify(result));
      span.setAttribute("mcp.tool.result.is_error", false);

      // Set result content count if applicable
      if (
        Array.isArray(result) ||
        (typeof result === "object" && result !== null)
      ) {
        span.setAttribute(
          "mcp.tool.result.content_count",
          Array.isArray(result)
            ? result.length
            : Object.keys(result).length,
        );
      }
    } catch (error) {
      span.setAttribute("mcp.tool.result.is_error", true);
      throw error;
    }
  },
);
```

### [Prompt Retrieval Span](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#prompt-retrieval-span)

Describes MCP prompt retrieval.

* The span `op` (transaction mode) or the span's `sentry.op` attribute (stream mode) MUST be `"mcp.server"`.
* The span `name` SHOULD be `"prompts/get {mcp.prompt.name}"`.
* The `mcp.prompt.name` attribute MUST be set to the prompt's name. (e.g. `"code_review"`)
* The `mcp.method.name` attribute SHOULD be set to `"prompts/get"`.
* All [Common Span Attributes](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#common-span-attributes) SHOULD be set.

Additional attributes on the span:

| Data Attribute                      | Type   | Requirement Level | Description                                                                       | Example                                        |
| ----------------------------------- | ------ | ----------------- | --------------------------------------------------------------------------------- | ---------------------------------------------- |
| `mcp.prompt.name`                   | string | required          | The name of the MCP prompt being retrieved.                                       | `"code_review"`                                |
| `mcp.method.name`                   | string | recommended       | Should be set to "prompts/get".                                                   | `"prompts/get"`                                |
| `mcp.request.id`                    | string | optional          | The unique identifier for the MCP request.                                        | `"req_456def"`                                 |
| `mcp.request.argument.*`            | any    | optional          | Prompt input arguments (requires `send_default_pii=True`).                        | `"python"` for `mcp.request.argument.language` |
| `mcp.prompt.result.message_content` | string | optional          | The message content from the prompt retrieval (requires `send_default_pii=True`). | `"Review the following code..."`               |
| `mcp.prompt.result.message_role`    | string | optional          | The role of the message (only for single-message prompts).                        | `"user"`, `"assistant"`, `"system"`            |
| `mcp.prompt.result.message_count`   | int    | optional          | The number of messages in the prompt result.                                      | `1`, `3`                                       |

#### [Example Prompt Retrieval Span:](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#example-prompt-retrieval-span)

```javascript
// Example prompt retrieval
const promptName = "code_review";
const promptArguments = { language: "python" };

await Sentry.startSpan(
  {
    op: "mcp.server",
    name: `prompts/get ${promptName}`,
  },
  async (span) => {
    // Set MCP-specific attributes
    span.setAttribute("mcp.prompt.name", promptName);
    span.setAttribute("mcp.method.name", "prompts/get");

    // Set request metadata
    span.setAttribute("mcp.request.id", "req_456def");
    span.setAttribute("mcp.session.id", "session_xyz789");
    span.setAttribute("mcp.transport", "http");
    span.setAttribute("network.transport", "tcp");

    // Set prompt arguments (optional, requires recordInputs: true)
    for (const [key, value] of Object.entries(promptArguments)) {
      span.setAttribute(`mcp.request.argument.${key}`, value);
    }

    // Retrieve the prompt
    const promptResult = getPrompt(promptName, promptArguments);

    // Set result data
    const messages = promptResult.messages || [];
    span.setAttribute("mcp.prompt.result.message_count", messages.length);

    // For single-message prompts, set role and content
    if (messages.length === 1) {
      span.setAttribute(
        "mcp.prompt.result.message_role",
        messages[0].role,
      );
      // Content may contain sensitive data, only set if recordOutputs: true
      span.setAttribute(
        "mcp.prompt.result.message_content",
        JSON.stringify(messages[0].content),
      );
    }
  },
);
```

### [Resource Read Span](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#resource-read-span)

Describes MCP resource access.

* The span `op` (transaction mode) or the span's `sentry.op` attribute (stream mode) MUST be `"mcp.server"`.
* The span `name` SHOULD be `"resources/read {mcp.resource.uri}"`.
* The `mcp.resource.uri` attribute MUST be set to the resource's URI. (e.g. `"file:///path/to/resource"`)
* The `mcp.method.name` attribute SHOULD be set to `"resources/read"`.
* All [Common Span Attributes](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#common-span-attributes) SHOULD be set.

Additional attributes on the span:

| Data Attribute          | Type   | Requirement Level | Description                                  | Example                       |
| ----------------------- | ------ | ----------------- | -------------------------------------------- | ----------------------------- |
| `mcp.resource.uri`      | string | required          | The URI of the MCP resource being accessed.  | `"file:///path/to/resource"`  |
| `mcp.method.name`       | string | recommended       | Should be set to "resources/read"            | `"resources/read"`            |
| `mcp.request.id`        | string | optional          | The unique identifier for the MCP request.   | `"req_789ghi"`                |
| `mcp.resource.protocol` | string | optional          | The protocol/scheme of the MCP resource URI. | `"file"`, `"http"`, `"https"` |

#### [Example Resource Read Span:](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#example-resource-read-span)

```javascript
// Example resource access
const resourceUri = "file:///path/to/resource.txt";

await Sentry.startSpan(
  {
    op: "mcp.server",
    name: `resources/read ${resourceUri}`,
  },
  async (span) => {
    // Set MCP-specific attributes
    span.setAttribute("mcp.resource.uri", resourceUri);
    span.setAttribute("mcp.method.name", "resources/read");

    // Set request metadata
    span.setAttribute("mcp.request.id", "req_789ghi");
    span.setAttribute("mcp.session.id", "session_xyz789");
    span.setAttribute("mcp.transport", "http");
    span.setAttribute("network.transport", "tcp");

    // Access the resource
    const resourceData = readResource(resourceUri);
  },
);
```

## [Common Span Attributes](https://docs.sentry.io/platforms/javascript/guides/cloudflare/mcp-monitoring.md#common-span-attributes)

The following attributes are common across all MCP span types and SHOULD be set when available:

| Data Attribute      | Type   | Requirement Level | Description                                      | Example                    |
| ------------------- | ------ | ----------------- | ------------------------------------------------ | -------------------------- |
| `mcp.transport`     | string | recommended       | The transport method used for MCP communication. | `"stdio"`, `"sse", "http"` |
| `network.transport` | string | recommended       | The network transport used.                      | `"pipe"`, `"tcp"`          |
| `mcp.session.id`    | string | recommended       | The session identifier for the MCP connection.   | `"a1b2c3d4e5f6"`           |
| `mcp.request.id`    | string | optional          | The unique identifier for the MCP request.       | `"req_123abc"`             |
