Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
7 changes: 3 additions & 4 deletions packages/mcp-cloudflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@cloudflare/workers-types": "^4.20250430.0",
"@sentry/mcp-server": "workspace:*",
"@sentry/mcp-server-tsconfig": "workspace:*",
"@sentry/vite-plugin": "^3.3.1",
"@sentry/vite-plugin": "^3.4.0",
"@tailwindcss/typography": "^0.5.16",
"@tailwindcss/vite": "^4.1.5",
"@types/react": "^19.1.2",
Expand All @@ -43,9 +43,8 @@
"@modelcontextprotocol/sdk": "^1.10.2",
"@radix-ui/react-accordion": "^1.2.8",
"@radix-ui/react-slot": "^1.2.0",
"@sentry/cloudflare": "9.14.0",
"@sentry/core": "9.14.0",
"@sentry/react": "9.14.0",
"@sentry/cloudflare": "9.16.1",
"@sentry/react": "9.16.1",
"agents": "~0.0.75",
"better-sqlite3": "^11.9.1",
"class-variance-authority": "^0.7.1",
Expand Down
6 changes: 5 additions & 1 deletion packages/mcp-cloudflare/src/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as Sentry from "@sentry/cloudflare";
import OAuthProvider from "@cloudflare/workers-oauth-provider";
import SentryMCP from "./lib/mcp-transport";
import app from "./app";
import { SCOPES } from "../constants";
import type { Env } from "./types";
import * as Sentry from "@sentry/cloudflare";

// required for Durable Objects
export { SentryMCP };
Expand All @@ -29,6 +29,10 @@ export default Sentry.withSentry(
environment:
env.SENTRY_ENVIRONMENT ??
(process.env.NODE_ENV !== "production" ? "development" : "production"),
_experiments: {
enableLogs: true,
},
integrations: [Sentry.consoleLoggingIntegration()],
}),
oAuthProvider,
) satisfies ExportedHandler<Env>;
48 changes: 38 additions & 10 deletions packages/mcp-cloudflare/src/server/lib/mcp-transport.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import * as Sentry from "@sentry/cloudflare";
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { configureServer } from "@sentry/mcp-server/server";
import type { Env, WorkerProps } from "../types";
import { flush } from "@sentry/cloudflare";
import { wrapMcpServerWithSentry } from "@sentry/core";
import { LIB_VERSION } from "@sentry/mcp-server/version";

// Context from the auth process, encrypted & stored in the auth token
// and provided to the DurableMCP as this.props
export default class SentryMCP extends McpAgent<Env, unknown, WorkerProps> {
server = wrapMcpServerWithSentry(
new McpServer({
name: "Sentry MCP",
version: LIB_VERSION,
}),
);
class SentryMCPBase extends McpAgent<Env, unknown, WorkerProps> {
server = new McpServer({
name: "Sentry MCP",
version: LIB_VERSION,
});
// Note: This does not work locally with miniflare so we are not using it
// server = wrapMcpServerWithSentry(
// new McpServer({
// name: "Sentry MCP",
// version: LIB_VERSION,
// }),
// );

// biome-ignore lint/complexity/noUselessConstructor: Need the constructor to match the durable object types.
constructor(state: DurableObjectState, env: Env) {
super(state, env);
}

async init() {
await configureServer({
Expand All @@ -25,8 +34,27 @@ export default class SentryMCP extends McpAgent<Env, unknown, WorkerProps> {
userId: this.props.id,
},
onToolComplete: () => {
Copy link
Member

Choose a reason for hiding this comment

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

do we actually n eed this flush at this point? still no idea why it didnt do anything before

Copy link
Member Author

Choose a reason for hiding this comment

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

Shouldn't need this flush now that we have durable objects instrumentation. We can keep it around for now, let me test quickly to make sure everything is okay - I'll open another PR in a sec.

this.ctx.waitUntil(flush(2000));
this.ctx.waitUntil(Sentry.flush(2000));
},
});
}
}

export default Sentry.instrumentDurableObjectWithSentry(
(env) => ({
dsn: env.SENTRY_DSN,
tracesSampleRate: 1,
sendDefaultPii: true,
initialScope: {
tags: {
durable_object: true,
mcp_server_version: LIB_VERSION,
},
},
_experiments: {
enableLogs: true,
},
integrations: [Sentry.consoleLoggingIntegration()],
Copy link
Member

Choose a reason for hiding this comment

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

does this make console.error go to sentry as a new issue? if so prob gonna remove it as i prefer the more explicit abstraction

Copy link
Member Author

@AbhiPrasad AbhiPrasad May 7, 2025

Choose a reason for hiding this comment

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

does this make console.error go to sentry as a new issue

Right now it only records it as a error level log.

Once the SDK is not experimental, we'll merge consoleLoggingIntegration with the regular console instrumentation (which is enabled by default), which give users the option to create issues from console errors. For now it will stay separate, and only create logs.

Copy link
Member

Choose a reason for hiding this comment

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

ah thats what i want (I dont ever want console to create issues, generally speaking)

maybe sometimes id want things showing up as logs to be issues, but by default logger integrations are noisey

Copy link
Member Author

Choose a reason for hiding this comment

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

maybe sometimes id want things showing up as logs to be issues, but by default logger integrations are noisey

yeah we're debating between just a boolean option to forward everything, or some callback that allows you to create issues on log message. We'll have this implemented by GA.

Copy link
Member

Choose a reason for hiding this comment

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

id just have the server handle it - no reason we cant have a thing that says "turn logs that look like X into issues"

}),
SentryMCPBase,
);
3 changes: 1 addition & 2 deletions packages/mcp-cloudflare/src/server/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { OAuthHelpers } from "@cloudflare/workers-oauth-provider";
import type SentryMCP from "./lib/mcp-transport";
import type { ServerContext } from "@sentry/mcp-server/types";

export type WorkerProps = ServerContext & {
Expand All @@ -17,7 +16,7 @@ export interface Env {
SENTRY_CLIENT_SECRET: string;
SENTRY_DSN?: string;
SENTRY_HOST?: string;
MCP_OBJECT: DurableObjectNamespace<SentryMCP>;
MCP_OBJECT: DurableObjectNamespace;
OAUTH_PROVIDER: OAuthHelpers;
AI: Ai;
}
3 changes: 1 addition & 2 deletions packages/mcp-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.10.2",
"@sentry/core": "^9.14.0",
"@sentry/node": "^9.14.0",
"@sentry/node": "^9.16.1",
"zod": "^3.24.3"
}
}
8 changes: 6 additions & 2 deletions packages/mcp-server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { startStdio } from "./transports/stdio";
import { wrapMcpServerWithSentry } from "@sentry/core";
import * as Sentry from "@sentry/node";
import { LIB_VERSION } from "./version";

Expand Down Expand Up @@ -46,6 +45,11 @@ if (!accessToken) {
Sentry.init({
dsn: sentryDsn,
sendDefaultPii: true,
initialScope: {
tags: {
mcp_server_version: LIB_VERSION,
},
},
environment:
process.env.SENTRY_ENVIRONMENT ??
(process.env.NODE_ENV !== "production" ? "development" : "production"),
Expand All @@ -56,7 +60,7 @@ const server = new McpServer({
version: LIB_VERSION,
});

const instrumentedServer = wrapMcpServerWithSentry(server);
const instrumentedServer = Sentry.wrapMcpServerWithSentry(server);

const SENTRY_TIMEOUT = 5000; // 5 seconds

Expand Down
2 changes: 1 addition & 1 deletion packages/mcp-server/src/logging.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { captureException, captureMessage, withScope } from "@sentry/core";
import { captureException, captureMessage, withScope } from "@sentry/node";
Copy link
Member

Choose a reason for hiding this comment

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

mcp-server is used on multi-env which is why im not binding this to node


export function logError(
error: Error | unknown,
Expand Down
2 changes: 1 addition & 1 deletion packages/mcp-server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { TOOL_HANDLERS } from "./tools";
import { TOOL_DEFINITIONS } from "./toolDefinitions";
import type { ServerContext } from "./types";
import { setUser, startNewTrace, startSpan } from "@sentry/core";
import { setUser, startNewTrace, startSpan } from "@sentry/node";
import { logError } from "./logging";
import { RESOURCES } from "./resources";
import { PROMPT_DEFINITIONS } from "./promptDefinitions";
Expand Down
Loading
Loading