Skip to content

Instrument MCP server with Sentry Insights spans - #441

Merged
kentcdodds merged 2 commits into
mainfrom
fix/sentry-mcp-insights
May 12, 2026
Merged

kentcdodds merged 2 commits into
mainfrom
fix/sentry-mcp-insights

Conversation

@kody-bot

@kody-bot kody-bot commented May 12, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • wrap the Kody MCP server with Sentry MCP instrumentation
  • keep MCP input/output payload recording disabled
  • add a focused resource URI attribute for the generated UI MCP resource

Validation

  • node --input-type=module -e "import('@sentry/cloudflare').then(m=>console.log(typeof m.wrapMcpServerWithSentry))"
  • npx vitest run --config vitest.node.config.ts packages/worker/src/mcp/index.node.test.ts
  • npm run typecheck
  • npm run lint (passes with existing warnings)
  • npm test

Summary by CodeRabbit

  • Tests

    • Added a unit test verifying the MCP server is wrapped with monitoring instrumentation and payload recording is disabled.
  • Chores

    • Integrated monitoring instrumentation for server and UI resource handling (adds span attributes).
    • Refactored MCP server initialization to use a factory.
    • Updated test support with monitoring stubs.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 12, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fa27ee4a-2da6-40f4-a808-dce4426bbd75

📥 Commits

Reviewing files that changed from the base of the PR and between d5d0612 and f404298.

📒 Files selected for processing (2)
  • packages/worker/src/mcp/index.node.test.ts
  • packages/worker/src/mcp/sentry-mcp-server.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/worker/src/mcp/index.node.test.ts
  • packages/worker/src/mcp/sentry-mcp-server.ts

📝 Walkthrough

Walkthrough

Extracts MCP server instantiation into a new factory that wraps the server with Sentry (payload recording disabled), updates MCP initialization to use the factory, adds Sentry span attribution in a generated UI resource, and adds test stubs plus a unit test verifying the wrapping.

Changes

MCP Server Factory with Sentry Wrapping

Layer / File(s) Summary
Factory Definition and Server Wrapping
packages/worker/src/mcp/sentry-mcp-server.ts
New module exports createKodyMcpServer factory that constructs an McpServer with fixed identity (kody-mcp v1.0.0) and wraps it with Sentry instrumentation while disabling payload recording.
Factory Integration in MCP Initialization
packages/worker/src/mcp/index.ts
Replaces direct new McpServer(serverImplementation, {...}) construction with createKodyMcpServer({...}) factory call; switches McpServer to a type-only import and removes the inlined serverImplementation constant.
Resource Handler Observability
packages/worker/src/mcp/resources/generated-ui-app-resource.ts
Adds Sentry integration by setting mcp.resource.uri span attribute on the active Sentry span within the resource handler for request tracing.
Test Stubs and Factory Verification
packages/worker/src/test-support/sentry-cloudflare-stub.ts, packages/worker/src/mcp/index.node.test.ts
Extends Sentry stub module with getActiveSpan() and wrapMcpServerWithSentry() functions; introduces a Vitest test verifying the factory wraps the server with correct Sentry options (recordInputs: false, recordOutputs: false).

Sequence Diagram(s)

sequenceDiagram
  participant MCPCaller
  participant createKodyMcpServer
  participant McpServer
  participant SentryCloudflare
  MCPCaller->>createKodyMcpServer: instantiate with options
  createKodyMcpServer->>McpServer: new McpServer(implementation, options)
  McpServer-->>createKodyMcpServer: returns server
  createKodyMcpServer->>SentryCloudflare: wrapMcpServerWithSentry(server, {recordInputs:false,recordOutputs:false})
  SentryCloudflare-->>createKodyMcpServer: wrapped server
  createKodyMcpServer-->>MCPCaller: returns wrapped server
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • kentcdodds/kody#164: Adds @sentry/cloudflare as a dependency in packages/worker, which this PR uses for Sentry wrapping.
  • kentcdodds/kody#45: Modifies the same generated-ui-app-resource.ts function; related due to changes in that handler.

Poem

🐰 A tiny rabbit wraps the server tight,
Sentry watches spans all through the night.
Resources tagged with gentle care,
Tests confirm the wrapping there.
Hops of joy for observability's light!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of the changeset: adding Sentry Insights spans instrumentation to the MCP server. It directly reflects the primary changes across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/sentry-mcp-insights

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@kentcdodds
kentcdodds marked this pull request as ready for review May 12, 2026 01:16
@github-actions

github-actions Bot commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-441.kentcdodds.workers.dev

Worker: kody-pr-441
D1: kody-pr-441-db
KV: kody-pr-441-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/worker/src/mcp/index.node.test.ts (1)

24-28: 💤 Low value

Consider improving test clarity for the assertion.

The test currently asserts that wrapMcpServerWithSentry was called with server (the return value), which works because the mock returns its input unchanged. This creates a circular reference that may confuse future maintainers. Consider using expect.any(McpServer) or similar for the first argument to make the test's intent clearer.

📝 Alternative assertion approach
  expect(sentryMock.wrapMcpServerWithSentry).toHaveBeenCalledTimes(1)
- expect(sentryMock.wrapMcpServerWithSentry).toHaveBeenCalledWith(server, {
+ expect(sentryMock.wrapMcpServerWithSentry).toHaveBeenCalledWith(
+   expect.any(Object),
+   {
      recordInputs: false,
      recordOutputs: false,
-   })
+   },
+ )

Or verify the first argument separately:

+ const [[calledServer, calledOptions]] = sentryMock.wrapMcpServerWithSentry.mock.calls
+ expect(calledServer).toBe(server)
+ expect(calledOptions).toEqual({
+   recordInputs: false,
+   recordOutputs: false,
+ })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/mcp/index.node.test.ts` around lines 24 - 28, The
assertion currently checks wrapMcpServerWithSentry was called with the concrete
return value `server`, creating a circular/ambiguous test; update the assertion
to assert the first argument type instead (e.g. use expect.any(McpServer)) so
intent is clear: replace the toHaveBeenCalledWith(server, {...}) check with
toHaveBeenCalledWith(expect.any(McpServer), { recordInputs: false,
recordOutputs: false }) or alternatively assert the call count and verify the
first call's first argument separately via
expect(sentryMock.wrapMcpServerWithSentry.mock.calls[0][0]).toEqual(expect.any(McpServer))
and then assert the options object.
packages/worker/src/mcp/sentry-mcp-server.ts (1)

9-11: 💤 Low value

Consider adding an explicit return type annotation.

While TypeScript will infer the return type, adding an explicit annotation would improve code clarity and catch potential type mismatches earlier.

📝 Suggested return type annotation
 export function createKodyMcpServer(
   options: ConstructorParameters<typeof McpServer>[1],
-) {
+): McpServer {
   return Sentry.wrapMcpServerWithSentry(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/mcp/sentry-mcp-server.ts` around lines 9 - 11, Add an
explicit return type to the createKodyMcpServer function signature (e.g., :
McpServer) to make the API clear and catch mismatches; update the signature of
createKodyMcpServer to return the concrete McpServer type (or the appropriate
Promise<McpServer> if the implementation is async) and import/fully qualify the
McpServer type where needed so the compiler verifies the returned value matches
the annotated type.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/worker/src/mcp/index.node.test.ts`:
- Around line 24-28: The assertion currently checks wrapMcpServerWithSentry was
called with the concrete return value `server`, creating a circular/ambiguous
test; update the assertion to assert the first argument type instead (e.g. use
expect.any(McpServer)) so intent is clear: replace the
toHaveBeenCalledWith(server, {...}) check with
toHaveBeenCalledWith(expect.any(McpServer), { recordInputs: false,
recordOutputs: false }) or alternatively assert the call count and verify the
first call's first argument separately via
expect(sentryMock.wrapMcpServerWithSentry.mock.calls[0][0]).toEqual(expect.any(McpServer))
and then assert the options object.

In `@packages/worker/src/mcp/sentry-mcp-server.ts`:
- Around line 9-11: Add an explicit return type to the createKodyMcpServer
function signature (e.g., : McpServer) to make the API clear and catch
mismatches; update the signature of createKodyMcpServer to return the concrete
McpServer type (or the appropriate Promise<McpServer> if the implementation is
async) and import/fully qualify the McpServer type where needed so the compiler
verifies the returned value matches the annotated type.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 20415a2c-d3db-4e92-b8ac-ab3dad2f7a12

📥 Commits

Reviewing files that changed from the base of the PR and between b3e6b19 and d5d0612.

📒 Files selected for processing (5)
  • packages/worker/src/mcp/index.node.test.ts
  • packages/worker/src/mcp/index.ts
  • packages/worker/src/mcp/resources/generated-ui-app-resource.ts
  • packages/worker/src/mcp/sentry-mcp-server.ts
  • packages/worker/src/test-support/sentry-cloudflare-stub.ts

@kody-bot
kody-bot marked this pull request as draft May 12, 2026 01:35
@kentcdodds
kentcdodds marked this pull request as ready for review May 12, 2026 01:55
@kentcdodds
kentcdodds merged commit b85be86 into main May 12, 2026
7 checks passed
@kentcdodds
kentcdodds deleted the fix/sentry-mcp-insights branch May 12, 2026 02:31
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.

2 participants