Instrument MCP Servers

Learn how to manually instrument your code to use Sentry's MCP monitoring.

With Sentry's MCP monitoring, you can track and debug MCP servers with full-stack context. You'll be able to monitor tool executions, prompt retrievals, resource access, and error rates. MCP monitoring data will be fully connected to your other Sentry data like logs, errors, and traces.

As a prerequisite to setting up MCP monitoring with JavaScript, you'll need to first set up tracing. Once this is done, the JavaScript SDK will automatically instrument MCP servers created with supported libraries. If that doesn't fit your use case, you can use custom instrumentation described below.

The JavaScript SDK supports automatic instrumentation for MCP servers. We recommend adding the MCP integration to your Sentry configuration to automatically capture spans for MCP operations.

For your MCP data to show up in Sentry, spans must be created with well-defined names and data attributes. See below for the different types of MCP operations you can instrument.

The Sentry.startSpan() method can be used to create these spans.

Describes MCP tool execution.

The @sentry_sdk.trace() decorator can also be used to create this span.

  • The span's op 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 SHOULD be set.

Additional attributes on the span:

Data AttributeTypeRequirement LevelDescriptionExample
mcp.tool.namestringrequiredThe name of the MCP tool being called."get_weather"
mcp.method.namestringrecommendedShould be set to "tools/call"."tools/call"
mcp.request.idstringoptionalThe unique identifier for the MCP request."req_123abc"
mcp.request.argument.*anyoptionalTool input arguments (requires send_default_pii=True)."San Francisco" for mcp.request.argument.city
mcp.tool.result.contentstringoptionalThe result/output content from the tool execution."The weather is sunny"
mcp.tool.result.content_countintoptionalThe number of items/keys in the tool result.5
mcp.tool.result.is_errorbooleanoptionalWhether the tool execution resulted in an error.True

Copied
import * as Sentry from "@sentry/node";

Sentry.init({
  // ... your Sentry configuration
});

// 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, if send_default_pii=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;
    }
  },
);

Describes MCP prompt retrieval.

The @sentry_sdk.trace() decorator can also be used to create this span.

  • The span's op 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 SHOULD be set.

Additional attributes on the span:

Data AttributeTypeRequirement LevelDescriptionExample
mcp.prompt.namestringrequiredThe name of the MCP prompt being retrieved."code_review"
mcp.method.namestringrecommendedShould be set to "prompts/get"."prompts/get"
mcp.request.idstringoptionalThe unique identifier for the MCP request."req_456def"
mcp.request.argument.*anyoptionalPrompt input arguments (requires send_default_pii=True)."python" for mcp.request.argument.language
mcp.prompt.result.message_contentstringoptionalThe message content from the prompt retrieval (requires send_default_pii=True)."Review the following code..."
mcp.prompt.result.message_rolestringoptionalThe role of the message (only for single-message prompts)."user", "assistant", "system"
mcp.prompt.result.message_countintoptionalThe number of messages in the prompt result.1, 3

Copied
import * as Sentry from "@sentry/node";

Sentry.init({
  // ... your Sentry configuration
});

// 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, if send_default_pii=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 is PII, only set if send_default_pii=true
      span.setAttribute(
        "mcp.prompt.result.message_content",
        JSON.stringify(messages[0].content),
      );
    }
  },
);

Describes MCP resource access.

The @sentry_sdk.trace() decorator can also be used to create this span.

  • The span's op 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 SHOULD be set.

Additional attributes on the span:

Data AttributeTypeRequirement LevelDescriptionExample
mcp.resource.uristringrequiredThe URI of the MCP resource being accessed."file:///path/to/resource"
mcp.method.namestringrecommendedShould be set to "resources/read""resources/read"
mcp.request.idstringoptionalThe unique identifier for the MCP request."req_789ghi"
mcp.resource.protocolstringoptionalThe protocol/scheme of the MCP resource URI."file", "http", "https"

Copied
import * as Sentry from "@sentry/node";

Sentry.init({
  // ... your Sentry configuration
});

// 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);
  },
);

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

Data AttributeTypeRequirement LevelDescriptionExample
mcp.transportstringrecommendedThe transport method used for MCP communication."stdio", "sse", "http"
network.transportstringrecommendedThe network transport used."pipe", "tcp"
mcp.session.idstringrecommendedThe session identifier for the MCP connection."a1b2c3d4e5f6"
mcp.request.idstringoptionalThe unique identifier for the MCP request."req_123abc"
Was this helpful?
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").