Skip to content
Merged
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
6 changes: 3 additions & 3 deletions docs/contributing/adding-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@ async handler(params, context: ServerContext) {
);
}

// 3. Set organization telemetry for streamed spans and error events
// Import from ../../telem/organization.
setOrganizationContext(params.organizationSlug);
// 3. Set telemetry context for streamed spans and error events
// Import from ../../telem/scope.
setTargetTagsAndAttributes(params);

// 4. Call API
const data = await api.yourMethod(params);
Expand Down
25 changes: 19 additions & 6 deletions docs/operations/monitoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,25 @@ export async function createTracedToolHandler<T extends ToolName>(
}
```

### Organization Context

Call `setOrganizationContext(slug)` from `src/telem/organization.ts` after
resolving the organization, including from URLs. It sets `organization.slug`
as a scope attribute for streamed spans, logs, and metrics, and as a tag for
errors. SDK v11 no longer copies scope tags onto spans.
### Request Context

Call `setTargetTagsAndAttributes()` from `src/telem/scope.ts` after
resolving the organization, including from URLs. It sets the Sentry
resources that the tool call targets as scope attributes for streamed spans,
logs, and metrics, and as tags for errors. It requires `organizationSlug`.
All other `Target` fields are optional, such as `projectSlug`, `teamSlug`,
`issueId`, or `traceId`, so a tool can pass its `params` directly when they
use these names. A numeric `projectSlugOrId` becomes `project.id`, any other
value `project.slug`. To send a new kind of resource, add a field to
`Target` and its key to `targetKeys`.

For other searchable values that are not a target, such as `client.id` or
`doc.path`, put the keys in one object and pass it to both `setTags` and
`setAttributes` from `@sentry/core`. SDK v11 no longer copies scope tags
onto spans, so do not call `setTag` alone.

For values set at startup, put the same keys in both `initialScope.tags` and
`initialScope.attributes` of `Sentry.init`.

### Span Management

Expand Down
17 changes: 12 additions & 5 deletions packages/mcp-cloudflare/src/server/sentry.config.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import * as Sentry from "@sentry/cloudflare";
import type { CloudflareOptions } from "@sentry/cloudflare";
import * as Sentry from "@sentry/cloudflare";
import { sentryBeforeSend } from "@sentry/mcp-core/telem/sentry";
import { LIB_VERSION } from "@sentry/mcp-core/version";
import type { Env } from "./types";

export default function getSentryConfig(env: Env): CloudflareOptions {
const versionId = env.CF_VERSION_METADATA?.id;
const scopeContext = {
"app.server.version": LIB_VERSION,
"app.upstream.host": env.SENTRY_HOST,
};

return {
dsn: env.SENTRY_DSN,
tracesSampleRate: 0.3,
beforeSend: sentryBeforeSend,
initialScope: {
tags: {
"app.server.version": LIB_VERSION,
"app.upstream.host": env.SENTRY_HOST,
},
tags: scopeContext,
// SDK v11 does not copy scope tags onto streamed spans.
attributes: scopeContext,
},
...(versionId ? { release: versionId } : {}),
environment:
Expand All @@ -39,6 +42,10 @@ getSentryConfig.partial = (config: Partial<CloudflareOptions>) => {
...((defaultConfig.initialScope ?? {}) as any).tags,
...((config.initialScope ?? {}) as any).tags,
},
attributes: {
...((defaultConfig.initialScope ?? {}) as any).attributes,
...((config.initialScope ?? {}) as any).attributes,
},
},
};
};
Expand Down
2 changes: 2 additions & 0 deletions packages/mcp-core/src/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import { LIB_VERSION } from "./version";
// Mock the Sentry core module
vi.mock("@sentry/core", () => ({
setTag: vi.fn(),
setTags: vi.fn(),
setAttribute: vi.fn(),
setAttributes: vi.fn(),
setUser: vi.fn(),
getActiveSpan: vi.fn(),
startSpan: vi.fn(),
Expand Down
23 changes: 12 additions & 11 deletions packages/mcp-core/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ import { McpServer as ModernMcpServer } from "@modelcontextprotocol/server";
import {
getActiveSpan,
type SpanAttributeValue,
setTag,
setUser,
setAttributes,
setTags,
} from "@sentry/core";
import { wrapMcpServerWithSentry } from "@sentry/core/server";
import { isApiAuthenticationErrorDeep } from "./api-client";
Expand Down Expand Up @@ -301,16 +302,16 @@ function configureServer({
};
setUser(user);
}
if (context.clientId) {
setTag("client.id", context.clientId);
}
if (context.clientFamily) {
setTag("app.client.family", context.clientFamily);
}
if (context.transport) {
setTag("app.transport", context.transport);
}
setTag("app.server.mode.experimental", experimentalMode);
const requestContext = {
...(context.clientId ? { "client.id": context.clientId } : {}),
...(context.clientFamily
? { "app.client.family": context.clientFamily }
: {}),
...(context.transport ? { "app.transport": context.transport } : {}),
"app.server.mode.experimental": experimentalMode,
};
setTags(requestContext);
setAttributes(requestContext);

// Hoisted so both the handler path and the catch (onError) share one
// narrowing instead of re-casting `params`.
Expand Down
128 changes: 0 additions & 128 deletions packages/mcp-core/src/telem/organization.test.ts

This file was deleted.

7 changes: 0 additions & 7 deletions packages/mcp-core/src/telem/organization.ts

This file was deleted.

Loading
Loading