Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/platforms/javascript/common/agent-tracing/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -219,4 +219,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 <PlatformLink to="/tracing/instrumentation/mcp-module/">Instrument MCP Servers</PlatformLink> for setup instructions.
If you're building MCP (Model Context Protocol) servers, Sentry can also track tool executions, prompt retrievals, and resource access. See <PlatformLink to="/mcp-monitoring/">MCP Monitoring</PlatformLink> for setup instructions.
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -26,19 +28,89 @@ 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 <PlatformLink to="/tracing/">set up tracing</PlatformLink>. 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, <PlatformLink to="/tracing/">set up tracing</PlatformLink>.

## 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/)
<PlatformContent includePath="mcp-monitoring/setup" />

## Manual Instrumentation
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.

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.
### 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.

<PlatformSection supported={["javascript.cloudflare"]}>

## 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 <PlatformLink to="/tracing/streamed-spans/">Streamed Spans</PlatformLink> 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 <PlatformLink to="/features/agents-sdk/">Agents SDK</PlatformLink>.

</PlatformSection>

<PlatformSection supported={["javascript.hono"]}>

## 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 <PlatformLink to="/tracing/streamed-spans/">Streamed Spans</PlatformLink> for configuration and filtering differences.

</PlatformSection>

## Custom Instrumentation

If you're not using a supported MCP SDK, create spans with the names and data attributes described below.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it common for us to have this type of recommendation listed in all JS frameworks? I would assume we'd have it in the browser one perhaps? Or maybe I'm misunderstanding what we're trying to say here.

If I'm on a selected SDK, and we support it, this is a confusing thing to be reading. I'm also assuming I can use these attributes even in supported SDKs?

@betegon , can you help clarify and I can make a suggestion for rewording?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm great question. i'm not sure if this is common, i'll look it up. there's a bunch of official (from anthropic) MCP SDKs. we support JS and Python for now, there's GO, PHP and some more.

>if I'm on a selected SDK, and we support it, this is a confusing thing to be reading. I'm also assuming I can use these attributes even in supported SDKs?

fair, you shouldn't use it if you're in a supported SDK, although maybe you want? say you just want to record a couple of span attributes yourself.

thanks for looking a this btw!


The [Sentry.startSpan()](/platforms/javascript/tracing/instrumentation/custom-instrumentation/#starting-a-span) method can be used to create these spans.

Expand All @@ -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" };
Expand Down Expand Up @@ -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" };
Expand Down Expand Up @@ -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";

Expand Down
35 changes: 20 additions & 15 deletions docs/platforms/javascript/guides/cloudflare/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -379,44 +379,49 @@ 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()`

<SplitLayout>
<SplitSection>
<SplitSectionText>

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 <PlatformLink to="/tracing/streamed-spans/">Streamed Spans</PlatformLink> 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.

</SplitSectionText>
<SplitSectionCode>

```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.
}
```

Expand Down
32 changes: 19 additions & 13 deletions docs/product/mcp-servers/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -21,67 +21,73 @@ To start sending MCP data to Sentry, make sure you've created a Sentry project f
### JavaScript - MCP Server

<VersionRequirement
product="MCP Observability"
product="MCP Monitoring"
sdk="Node SDK"
minVersion="9.46.0"
/>

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({
dsn: "___PUBLIC_DSN___",
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`

_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

<VersionRequirement
product="MCP Observability"
product="MCP Monitoring"
sdk="Python SDK"
minVersion="2.43.0"
/>

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

Expand Down
4 changes: 4 additions & 0 deletions middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/',
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
32 changes: 32 additions & 0 deletions platform-includes/mcp-monitoring/setup/javascript.hono.mdx
Original file line number Diff line number Diff line change
@@ -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.
15 changes: 15 additions & 0 deletions platform-includes/mcp-monitoring/setup/javascript.mdx
Original file line number Diff line number Diff line change
@@ -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.
Loading