diff --git a/docs/platforms/javascript/common/agent-tracing/index.mdx b/docs/platforms/javascript/common/agent-tracing/index.mdx index 066df31c97b82..e572f21c94ae5 100644 --- a/docs/platforms/javascript/common/agent-tracing/index.mdx +++ b/docs/platforms/javascript/common/agent-tracing/index.mdx @@ -220,4 +220,4 @@ If you're using an AI framework with a Sentry exporter, you can send traces to S ## MCP Server Monitoring -If you're building MCP (Model Context Protocol) servers, Sentry can also track tool executions, prompt retrievals, and resource access. See Instrument MCP Servers for setup instructions. +If you're building MCP (Model Context Protocol) servers, Sentry can also track tool executions, prompt retrievals, and resource access. See MCP Monitoring for setup instructions. diff --git a/docs/platforms/javascript/common/tracing/instrumentation/mcp-module.mdx b/docs/platforms/javascript/common/mcp-monitoring/index.mdx similarity index 50% rename from docs/platforms/javascript/common/tracing/instrumentation/mcp-module.mdx rename to docs/platforms/javascript/common/mcp-monitoring/index.mdx index 6eaaeeb6441c9..dfbec2cbf925a 100644 --- a/docs/platforms/javascript/common/tracing/instrumentation/mcp-module.mdx +++ b/docs/platforms/javascript/common/mcp-monitoring/index.mdx @@ -1,7 +1,9 @@ --- -title: Instrument MCP Servers -sidebar_order: 600 -description: "Learn how to manually instrument your code to use Sentry's MCP monitoring." +title: Set Up MCP Monitoring +sidebar_title: MCP Monitoring +sidebar_order: 8 +sidebar_section: features +description: "Monitor MCP server tool executions, prompt retrievals, resource access, and errors." supported: - javascript.node - javascript.aws-lambda @@ -26,21 +28,91 @@ supported: - javascript.tanstackstart-react --- -With Sentry's [MCP monitoring](/product/mcp-servers/), 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. +With Sentry's [MCP Monitoring](/product/mcp-servers/), 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. -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. +Before you begin, set up tracing. -## Automatic Instrumentation +## Instrument the MCP Server -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. +Wrap each `McpServer` instance with `wrapMcpServerWithSentry` to automatically record MCP requests, tool calls, prompt retrievals, resource reads, and handler errors. -- [MCP (Model Context Protocol)](/product/mcp-servers/getting-started/) + + +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 + +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 + +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 {filename:index.js} +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 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. + + + + + +## Hono on Cloudflare Workers + +If your Hono app runs on Cloudflare Workers, MCP work can finish after the Worker returns its response. Set `traceLifecycle: "stream"` in the Hono Sentry middleware so each sampled span is sent when it finishes: + +```javascript {filename:index.js} +import { sentry } from "@sentry/hono/cloudflare"; + +app.use( + sentry(app, { + dsn: "___PUBLIC_DSN___", + tracesSampleRate: 1.0, + traceLifecycle: "stream", + }) +); +``` + +This changes how spans are delivered; it doesn't replace `wrapMcpServerWithSentry`. Stream mode requires `@sentry/hono` and `@sentry/cloudflare` version `10.49.0` or newer. See Streamed Spans for configuration and filtering differences. + + ## Manual Instrumentation -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 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. -The [Sentry.startSpan()](/platforms/javascript/tracing/instrumentation/custom-instrumentation/#starting-a-span) method can be used to create these spans. +You don't need this if you're already using `wrapMcpServerWithSentry` — it creates these spans for you. Otherwise, use [Sentry.startSpan()](/platforms/javascript/tracing/instrumentation/custom-instrumentation/#starting-a-span) to create the spans described below. ## Spans @@ -51,12 +123,6 @@ The [Sentry.startSpan()](/platforms/javascript/tracing/instrumentation/custom-in #### Example Tool Execution Span: ```javascript -import * as Sentry from "@sentry/node"; - -Sentry.init({ - // ... your Sentry configuration -}); - // Example tool execution const toolName = "get_weather"; const toolArguments = { city: "San Francisco" }; @@ -115,12 +181,6 @@ await Sentry.startSpan( #### Example Prompt Retrieval Span: ```javascript -import * as Sentry from "@sentry/node"; - -Sentry.init({ - // ... your Sentry configuration -}); - // Example prompt retrieval const promptName = "code_review"; const promptArguments = { language: "python" }; @@ -173,12 +233,6 @@ await Sentry.startSpan( #### Example Resource Read Span: ```javascript -import * as Sentry from "@sentry/node"; - -Sentry.init({ - // ... your Sentry configuration -}); - // Example resource access const resourceUri = "file:///path/to/resource.txt"; diff --git a/docs/platforms/javascript/guides/cloudflare/index.mdx b/docs/platforms/javascript/guides/cloudflare/index.mdx index 274a5dea6a27d..69c7ec62aff84 100644 --- a/docs/platforms/javascript/guides/cloudflare/index.mdx +++ b/docs/platforms/javascript/guides/cloudflare/index.mdx @@ -379,17 +379,19 @@ Server-side spans will display `0ms` for their durations. In the Cloudflare Work This is expected behavior in the Cloudflare Workers environment and affects all frameworks deployed to Cloudflare Workers, including Next.js, Astro, Remix, and others. -### Missing Spans in `waitUntil()` +### Spans in `waitUntil()` -If you're using Cloudflare's [`waitUntil()`](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#contextwaituntil) to run background tasks, spans created inside `waitUntil()` may not appear in Sentry because the request's root span has already finished before the background work starts. +Cloudflare's [`waitUntil()`](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#contextwaituntil) lets work continue after the Worker returns a response. With the static trace lifecycle, Sentry snapshots the request transaction when the response is returned, so spans that finish later may be missing. -To capture spans inside `waitUntil()`, wrap your deferred work with `startSpan` and set `forceTransaction: true`. This creates a separate transaction for the background work. +Set `traceLifecycle: "stream"` so the SDK can send each sampled span when it finishes. Span streaming on Cloudflare requires `@sentry/cloudflare` version `10.49.0` or newer. -The `forceTransaction: true` option is required because it creates a separate transaction for the `waitUntil()` work. Without it, spans created after the request ends might get lost. +Stream mode sends span records instead of assembling one transaction event with embedded spans. See Streamed Spans for filtering and migration details. + +If you need to keep the static lifecycle, use `forceTransaction: true` on the background operation instead. This records the work as a separate transaction. `forceTransaction` isn't available in stream mode. @@ -397,26 +399,29 @@ The `forceTransaction: true` option is required because it creates a separate tr ```javascript {filename:index.js} import * as Sentry from "@sentry/cloudflare"; -export default { +const worker = { async fetch(request, env, ctx) { - // Main request handling - const response = processRequest(request); - - // Background work with proper tracing ctx.waitUntil( - Sentry.startSpan( - { name: "background.task", op: "task", forceTransaction: true }, - () => updateCacheAndDatabase() + Sentry.startSpan({ name: "background.task", op: "task" }, () => + updateCacheAndDatabase() ) ); - return response; + return processRequest(request); }, }; +export default Sentry.withSentry( + (env) => ({ + dsn: env.SENTRY_DSN, + tracesSampleRate: 1.0, + traceLifecycle: "stream", + }), + worker +); + async function updateCacheAndDatabase() { - // Database operations - // Any spans created here will be captured + // Deferred work and any child spans are captured when they finish. } ``` diff --git a/docs/product/mcp-servers/getting-started.mdx b/docs/product/mcp-servers/getting-started.mdx index 80d512a1ddda2..d4ab1888f977a 100644 --- a/docs/product/mcp-servers/getting-started.mdx +++ b/docs/product/mcp-servers/getting-started.mdx @@ -12,7 +12,7 @@ keywords: - Node.js MCP --- -Sentry MCP Observability helps you track and debug Model Context Protocol (MCP) implementations using our supported SDKs and integrations. Monitor your complete MCP workflows from client connections to server responses, including tool executions, resource access, and protocol communications. +Sentry MCP Monitoring helps you track and debug Model Context Protocol (MCP) implementations using our supported SDKs and integrations. Monitor your complete MCP workflows from client connections to server responses, including tool executions, resource access, and protocol communications. To start sending MCP data to Sentry, make sure you've created a Sentry project for your MCP-enabled repository and follow the guide below: @@ -21,18 +21,18 @@ To start sending MCP data to Sentry, make sure you've created a Sentry project f ### JavaScript - MCP Server -The Sentry JavaScript SDK supports MCP observability by wrapping the MCP Server from the [@modelcontextprotocol/sdk](https://www.npmjs.com/package/@modelcontextprotocol/sdk) package. This wrapper automatically captures spans for your MCP server workflows including tool executions, resource access, and client connections. +The example below uses [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk) 1.x. The Sentry wrapper automatically captures spans for MCP server workflows, including tool executions, resource access, and client connections. #### Quick Start with MCP Server ```javascript import * as Sentry from "@sentry/node"; -import { McpServer } from "@modelcontextprotocol/sdk"; +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; // Sentry init needs to be above everything else Sentry.init({ @@ -40,30 +40,30 @@ Sentry.init({ tracesSampleRate: 1.0, }); -// Your MCP server with optional input/output recording +// Wrap every MCP server instance const server = Sentry.wrapMcpServerWithSentry( new McpServer({ name: "my-mcp-server", version: "1.0.0", }), - { - recordInputs: true, - recordOutputs: true, - } ); ... ``` +Stable `@modelcontextprotocol/server` 2.x support requires Sentry JavaScript SDK version `10.70.0` or newer. For framework-specific setup, see MCP Monitoring for [Node.js](/platforms/javascript/guides/node/mcp-monitoring/), [Hono](/platforms/javascript/guides/hono/mcp-monitoring/), or [Cloudflare](/platforms/javascript/guides/cloudflare/mcp-monitoring/). + #### Options +The `recordInputs` and `recordOutputs` options require Sentry JavaScript SDK version `10.33.0` or newer. + ##### `recordInputs` _Type: `boolean`_ Records inputs to MCP tool and prompt calls (such as tool arguments and prompt parameters). -Defaults to `true` if `sendDefaultPii` is `true`. +Defaults to `dataCollection.genAI.inputs`. In Sentry JavaScript SDK 10.x, when `dataCollection` isn't configured, this follows `sendDefaultPii`. ##### `recordOutputs` @@ -71,17 +71,23 @@ _Type: `boolean`_ Records outputs from MCP tool and prompt calls (such as tool results and prompt messages). -Defaults to `true` if `sendDefaultPii` is `true`. +Defaults to `dataCollection.genAI.outputs`. In Sentry JavaScript SDK 10.x, when `dataCollection` isn't configured, this follows `sendDefaultPii`. + +#### Cloudflare Workers + +MCP work on Cloudflare can finish after the Worker returns an HTTP response. Configure `traceLifecycle: "stream"` so spans are sent when they finish instead of depending on a static request snapshot. This requires `@sentry/cloudflare` version `10.49.0` or newer. + +See [MCP Monitoring on Cloudflare](/platforms/javascript/guides/cloudflare/mcp-monitoring/) for the configuration and filtering differences in stream mode. ### Python - MCP Server -The Sentry Python SDK supports MCP observability for the [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) (both low-level and FastMCP APIs) and [standalone FastMCP](https://gofastmcp.com/getting-started/welcome). The integration automatically captures spans for your MCP server workflows including tool executions, resource access, and prompt handling. +The Sentry Python SDK supports MCP Monitoring for the [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk) (both low-level and FastMCP APIs) and [standalone FastMCP](https://gofastmcp.com/getting-started/welcome). The integration automatically captures spans for your MCP server workflows, including tool executions, resource access, and prompt handling. #### Quick Start diff --git a/middleware.ts b/middleware.ts index 222e1a94ef5ac..59b1b8cec656b 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1996,6 +1996,10 @@ const USER_DOCS_REDIRECTS: Redirect[] = [ from: '/platforms/javascript/guides/:guide/tracing/instrumentation/opentelemetry/', to: '/platforms/javascript/guides/:guide/opentelemetry/', }, + { + from: '/platforms/javascript/guides/:guide/tracing/instrumentation/mcp-module/', + to: '/platforms/javascript/guides/:guide/mcp-monitoring/', + }, { from: '/learn/cli/configuration/', to: '/cli/configuration/', diff --git a/platform-includes/mcp-monitoring/setup/javascript.azure-functions.mdx b/platform-includes/mcp-monitoring/setup/javascript.azure-functions.mdx new file mode 100644 index 0000000000000..f9eb702cf5fb2 --- /dev/null +++ b/platform-includes/mcp-monitoring/setup/javascript.azure-functions.mdx @@ -0,0 +1,15 @@ +Import Sentry from `@sentry/node`, then wrap the MCP server instance before connecting it to a transport: + +```javascript {filename:mcp-server.js} +import * as Sentry from "@sentry/node"; +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. diff --git a/platform-includes/mcp-monitoring/setup/javascript.hono.mdx b/platform-includes/mcp-monitoring/setup/javascript.hono.mdx new file mode 100644 index 0000000000000..a97dba4575c70 --- /dev/null +++ b/platform-includes/mcp-monitoring/setup/javascript.hono.mdx @@ -0,0 +1,32 @@ +Hono uses a runtime-specific Sentry entrypoint. Import Sentry from the entrypoint that matches your deployment: + +```javascript {tabTitle:Cloudflare Workers} {filename:mcp-server.js} +import * as Sentry from "@sentry/hono/cloudflare"; +``` + +```javascript {tabTitle:Node.js} {filename:mcp-server.js} +import * as Sentry from "@sentry/hono/node"; +``` + +```javascript {tabTitle:Bun} {filename:mcp-server.js} +import * as Sentry from "@sentry/hono/bun"; +``` + +```javascript {tabTitle:Deno} {filename:mcp-server.js} +import * as Sentry from "@sentry/hono/deno"; +``` + +Then wrap the MCP server instance before connecting it to a transport: + +```javascript {filename:mcp-server.js} +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. diff --git a/platform-includes/mcp-monitoring/setup/javascript.mdx b/platform-includes/mcp-monitoring/setup/javascript.mdx new file mode 100644 index 0000000000000..41b8f6a5b2792 --- /dev/null +++ b/platform-includes/mcp-monitoring/setup/javascript.mdx @@ -0,0 +1,15 @@ +Import Sentry from your framework's SDK package, then wrap the MCP server instance before connecting it to a transport: + +```javascript {filename:mcp-server.js} +import * as Sentry from "___SDK_PACKAGE___"; +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.