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
opMUST be"mcp.server". - The span
nameSHOULD be"tools/call {mcp.tool.name}". - The
mcp.tool.nameattribute MUST be set to the tool's name. (e.g."get_weather") - The
mcp.method.nameattribute SHOULD be set to"tools/call". - All 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 |
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
opMUST be"mcp.server". - The span
nameSHOULD be"prompts/get {mcp.prompt.name}". - The
mcp.prompt.nameattribute MUST be set to the prompt's name. (e.g."code_review") - The
mcp.method.nameattribute SHOULD be set to"prompts/get". - All 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 |
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
opMUST be"mcp.server". - The span
nameSHOULD be"resources/read {mcp.resource.uri}". - The
mcp.resource.uriattribute MUST be set to the resource's URI. (e.g."file:///path/to/resource") - The
mcp.method.nameattribute SHOULD be set to"resources/read". - All 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" |
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 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" |
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").