Skip to content

feat(core): MCP server instrumentation without breaking Miniflare #16817

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 67 commits into from
Jul 28, 2025

Conversation

betegon
Copy link
Member

@betegon betegon commented Jul 4, 2025

Closes #16826, #16654, #16666 #16978

Different approach from #16807 .

Using Proxy was causing issues in cloudflare #16182.

Now using fill we shouldn't have those problems as fill doesn't create a new wrapper object with a different identity, so now:

  1. fill just replaces the method on the existing object
  2. The transport object keeps its original identity
  3. When transport.start() runs and accesses private fields, this is still the original transport object
  4. The WeakMap recognizes it as the same object that owns the private fields

What's inside

  • Support for new MCP SDK methods (mcpServerInstance.tool(), mcpServerInstance.resource(), etc.)
  • Tracing instrumentation
  • Error handling

Tracing

It follows OTEL semantic conventions for MCP and adds more attributes we thought are useful.

It also handles PII based on user setting of sendDefaultPii.

Tracing flow

  1. Transport receives tools/call request (id: 2)
  2. Create INACTIVE mcp.server span
  3. Store span inrequestIdToSpanMap[2] = { span, method: "tools/call", startTime }
  4. Execute handler with span context (handler gets requestId: 2)
  5. Handler finds span using requestId: 2
  6. Tool execution happens within span context
  7. Response sent with tool results
  8. completeSpanWithToolResults(2, result) enriches and completes span

Error handling

  1. error capture - errorCapture.ts
  • Non-invasive error reporting that never interferes with MCP service operation
  • Error context with MCP-specific metadata
  • PII filtering respects sendDefaultPii settings
  • Resilient to Sentry failures (wrapped in try-catch)
  1. Tool execution error capturing - handlers.ts
  • Captures exceptions thrown during tool execution
  • Preserves normal MCP behaviour (errors converted to isError: true)
  • Includes tool name, arguments, and request context
  • Handles both sync and async tool handlers
  1. Transport error instrumentation - transport.ts
  • Captures connection errors and network failures
  • Intercepts JSON-RPC error responses
  • Includes transport type and session information
  • Handles error responses being sent back to clients

betegon added 24 commits June 27, 2025 20:46
…ibute names to match OTEL draft semantic convention
@betegon betegon self-assigned this Jul 4, 2025
@betegon betegon requested a review from AbhiPrasad July 4, 2025 18:28
@betegon betegon changed the title Bete/mcp server semantic convention fill feat(core): MCP server instrumentation without breaking Miniflare Jul 4, 2025
Copy link
Member

@AbhiPrasad AbhiPrasad left a comment

Choose a reason for hiding this comment

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

Very nice, all good from my eyes in overall direction!

@betegon
Copy link
Member Author

betegon commented Jul 7, 2025

Thanks @AbhiPrasad! Will keep working on this and close the other PR using Proxy. Will apply your suggestions here!

cursor[bot]

This comment was marked as outdated.

@betegon betegon requested a review from AbhiPrasad July 22, 2025 08:59
@betegon
Copy link
Member Author

betegon commented Jul 22, 2025

@AbhiPrasad just finished suggested changes + added some new stuff:

  • Session data: information to persist during a session. this includes MCP protocol version, client name, server name, etc. The idea is to be extensible for new fields as the protocol changes. closes MCP Server - instrument user_agent header from MCP clients #16978
  • Fix span status to be set as internal_error when an error occurs.
  • Added the mechanism to avoid using tags
  • Capture only JSON-RPC server side errors (so we don't report client side errors here).

@betegon betegon requested a review from mydea July 24, 2025 12:01
betegon added a commit to getsentry/sentry-docs that referenced this pull request Jul 25, 2025
## DESCRIBE YOUR PR

Closes #14106

Adds developer docs for our MCP Server instrumentation. 

Route for the documentation `sdk/expected-features/mcp-instrumentation`
that includes:

```bash
.mcp-instrumentation
├── index.mdx  # brief description on current features and limitations
├── errors.mdx # draft errors doc 
└── tracing.mdx # Tracing and span conventions
```

Followed this file structure as a start to (in the future) have this
structure for all the other features, having something like this below,
where we have :
```
.[Feature 1]
├── index.mdx 
├── logs.mdx 
├── errors.mdx 
.
.
.
.[Feature 2]
├── index.mdx 
├── errors.mdx 
├── tracing.mdx
.
.
.
 ```

The structure idea is from @abhi, who helped me settle this <3.

**NOTE:** Error docs are going to change, addressing feedback from [sentry-javascript/pull/16817](getsentry/sentry-javascript#16817)

## IS YOUR CHANGE URGENT?  


## PRE-MERGE CHECKLIST

*Make sure you've checked the following before merging your changes:*

- [x] Checked Vercel preview for correctness, including links
- [ ] PR was reviewed and approved by any necessary SMEs (subject matter experts)
- [ ] PR was reviewed and approved by a member of the [Sentry docs team](https://github.com/orgs/getsentry/teams/docs)

---------

Co-authored-by: Alex Krawiec <alex.krawiec@sentry.io>
@betegon betegon enabled auto-merge (squash) July 28, 2025 14:43
@AbhiPrasad AbhiPrasad disabled auto-merge July 28, 2025 14:50
@AbhiPrasad AbhiPrasad enabled auto-merge (squash) July 28, 2025 14:50
Copy link
Contributor

github-actions bot commented Jul 28, 2025

size-limit report 📦

Path Size % Change Change
@sentry/browser 23.76 kB - -
@sentry/browser - with treeshaking flags 22.35 kB - -
@sentry/browser (incl. Tracing) 39.41 kB - -
@sentry/browser (incl. Tracing, Replay) 77.53 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 67.39 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 82.24 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 94.36 kB - -
@sentry/browser (incl. Feedback) 40.45 kB - -
@sentry/browser (incl. sendFeedback) 28.44 kB - -
@sentry/browser (incl. FeedbackAsync) 33.34 kB - -
@sentry/react 25.5 kB - -
@sentry/react (incl. Tracing) 41.38 kB - -
@sentry/vue 28.2 kB - -
@sentry/vue (incl. Tracing) 41.21 kB - -
@sentry/svelte 23.79 kB - -
CDN Bundle 25.28 kB - -
CDN Bundle (incl. Tracing) 39.28 kB - -
CDN Bundle (incl. Tracing, Replay) 75.4 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 80.83 kB - -
CDN Bundle - uncompressed 73.86 kB - -
CDN Bundle (incl. Tracing) - uncompressed 116.29 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 230.6 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 243.41 kB - -
@sentry/nextjs (client) 43.44 kB - -
@sentry/sveltekit (client) 39.84 kB - -
@sentry/node-core 47.48 kB +0.01% +1 B 🔺
@sentry/node 145.02 kB - -
@sentry/node - without tracing 91.58 kB - -
@sentry/aws-serverless 103.03 kB - -

View base workflow run

@betegon betegon force-pushed the bete/mcp-server-semantic-convention-fill branch from 78e92a2 to 55aa5ac Compare July 28, 2025 18:30
}

if (config.captureUri && params?.uri) {
args[`${MCP_REQUEST_ARGUMENT}.uri`] = JSON.stringify(params.uri);
Copy link

Choose a reason for hiding this comment

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

Bug: MCP Instrumentation Fails on Non-Serializable Input

The MCP instrumentation calls JSON.stringify on user-provided input parameters (specifically values within the arguments object, uri, and name) without error handling. This can lead to crashes if these parameters contain non-serializable data (e.g., circular references, functions, BigInts). Implement error handling (e.g., try-catch) or use a safe serialization method to prevent unhandled exceptions.

Locations (1)
Fix in Cursor Fix in Web

@AbhiPrasad AbhiPrasad merged commit 87b4e30 into develop Jul 28, 2025
177 checks passed
@AbhiPrasad AbhiPrasad deleted the bete/mcp-server-semantic-convention-fill branch July 28, 2025 19:22
AbhiPrasad pushed a commit that referenced this pull request Jul 28, 2025
…6817)

Closes #16826, #16654, #16666  #16978

Different approach from #16807 .

Using `Proxy` was causing issues in cloudflare #16182.

Now using `fill` we shouldn't have those problems as `fill` doesn't
create a new wrapper object with a different identity, so now:

1. `fill` just replaces the method on the existing object
2. The transport object keeps its original identity
3. When `transport.start()` runs and accesses private fields, this is
still the original transport object
4. The `WeakMap` recognizes it as the same object that owns the private
fields

- Support for new MCP SDK methods (`mcpServerInstance.tool()`,
`mcpServerInstance.resource()`, etc.)
- Tracing instrumentation
- Error handling

It follows [OTEL semantic conventions for
MCP](https://github.com/open-telemetry/semantic-conventions/blob/3097fb0af5b9492b0e3f55dc5f6c21a3dc2be8df/docs/gen-ai/mcp.md)
and adds more attributes we thought are useful.

It also handles PII based on user setting of `sendDefaultPii`.

1. **Transport receives tools/call request (`id: 2`)**
2. **Create INACTIVE `mcp.server` span**
3. **Store span in**`requestIdToSpanMap[2] = { span, method:
"tools/call", startTime }`
4. **Execute handler with span context** *(handler gets requestId: 2)*
5. **Handler finds span using** `requestId: 2`
6. **Tool execution happens within span context**
7. **Response sent with tool results**
8. `completeSpanWithToolResults(2, result)` **enriches and completes
span**

1.  **error capture** - `errorCapture.ts`
- Non-invasive error reporting that never interferes with MCP service
operation
- Error context with MCP-specific metadata
- PII filtering respects `sendDefaultPii` settings
- Resilient to Sentry failures (wrapped in try-catch)

2. **Tool execution error capturing** - `handlers.ts`
- Captures exceptions thrown during tool execution
- Preserves normal MCP behaviour (errors converted to `isError: true`)
- Includes tool name, arguments, and request context
- Handles both sync and async tool handlers

3. **Transport error instrumentation** - `transport.ts`
- Captures connection errors and network failures
- Intercepts JSON-RPC error responses
- Includes transport type and session information
- Handles error responses being sent back to clients
AbhiPrasad pushed a commit that referenced this pull request Jul 28, 2025
…6817)

Closes #16826, #16654, #16666  #16978

Different approach from #16807 .

Using `Proxy` was causing issues in cloudflare #16182.

Now using `fill` we shouldn't have those problems as `fill` doesn't
create a new wrapper object with a different identity, so now:

1. `fill` just replaces the method on the existing object
2. The transport object keeps its original identity
3. When `transport.start()` runs and accesses private fields, this is
still the original transport object
4. The `WeakMap` recognizes it as the same object that owns the private
fields

- Support for new MCP SDK methods (`mcpServerInstance.tool()`,
`mcpServerInstance.resource()`, etc.)
- Tracing instrumentation
- Error handling

It follows [OTEL semantic conventions for
MCP](https://github.com/open-telemetry/semantic-conventions/blob/3097fb0af5b9492b0e3f55dc5f6c21a3dc2be8df/docs/gen-ai/mcp.md)
and adds more attributes we thought are useful.

It also handles PII based on user setting of `sendDefaultPii`.

1. **Transport receives tools/call request (`id: 2`)**
2. **Create INACTIVE `mcp.server` span**
3. **Store span in**`requestIdToSpanMap[2] = { span, method:
"tools/call", startTime }`
4. **Execute handler with span context** *(handler gets requestId: 2)*
5. **Handler finds span using** `requestId: 2`
6. **Tool execution happens within span context**
7. **Response sent with tool results**
8. `completeSpanWithToolResults(2, result)` **enriches and completes
span**

1.  **error capture** - `errorCapture.ts`
- Non-invasive error reporting that never interferes with MCP service
operation
- Error context with MCP-specific metadata
- PII filtering respects `sendDefaultPii` settings
- Resilient to Sentry failures (wrapped in try-catch)

2. **Tool execution error capturing** - `handlers.ts`
- Captures exceptions thrown during tool execution
- Preserves normal MCP behaviour (errors converted to `isError: true`)
- Includes tool name, arguments, and request context
- Handles both sync and async tool handlers

3. **Transport error instrumentation** - `transport.ts`
- Captures connection errors and network failures
- Intercepts JSON-RPC error responses
- Includes transport type and session information
- Handles error responses being sent back to clients
AbhiPrasad added a commit that referenced this pull request Jul 29, 2025
backport of #16817

Co-authored-by: Miguel Betegón <miguelbetegongarcia@gmail.com>
lucas-zimerman pushed a commit to getsentry/sentry-docs that referenced this pull request Jul 29, 2025
## DESCRIBE YOUR PR

Closes #14106

Adds developer docs for our MCP Server instrumentation. 

Route for the documentation `sdk/expected-features/mcp-instrumentation`
that includes:

```bash
.mcp-instrumentation
├── index.mdx  # brief description on current features and limitations
├── errors.mdx # draft errors doc 
└── tracing.mdx # Tracing and span conventions
```

Followed this file structure as a start to (in the future) have this
structure for all the other features, having something like this below,
where we have :
```
.[Feature 1]
├── index.mdx 
├── logs.mdx 
├── errors.mdx 
.
.
.
.[Feature 2]
├── index.mdx 
├── errors.mdx 
├── tracing.mdx
.
.
.
 ```

The structure idea is from @abhi, who helped me settle this <3.

**NOTE:** Error docs are going to change, addressing feedback from [sentry-javascript/pull/16817](getsentry/sentry-javascript#16817)

## IS YOUR CHANGE URGENT?  


## PRE-MERGE CHECKLIST

*Make sure you've checked the following before merging your changes:*

- [x] Checked Vercel preview for correctness, including links
- [ ] PR was reviewed and approved by any necessary SMEs (subject matter experts)
- [ ] PR was reviewed and approved by a member of the [Sentry docs team](https://github.com/orgs/getsentry/teams/docs)

---------

Co-authored-by: Alex Krawiec <alex.krawiec@sentry.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

MCP Server tracing instrumentation
2 participants