monitoring.mdc•8.62 kB
---
description:
globs:
alwaysApply: false
---
# Monitoring
Observability patterns using Sentry across the MCP server.
## Architecture
Different Sentry SDKs for different environments:
- **Core server**: `@sentry/core` (platform-agnostic)
- **Cloudflare Workers**: `@sentry/cloudflare`
- **Node.js stdio**: `@sentry/node`
- **React client**: `@sentry/react`
## Core Server Instrumentation
### Error Logging
See `logIssue` in @packages/mcp-server/src/telem/logging.ts (documented in @docs/logging.mdc) for the canonical way to create an Issue and structured log entry.
### Tracing Pattern
```typescript
export async function createTracedToolHandler<T extends ToolName>(
name: T,
handler: ToolHandlerFunction<T>
): Promise<[T, ToolHandlerFunction<T>]> {
return [
name,
async (context: ServerContext, params: ToolParams<T>) => {
const attributes = {
"mcp.tool.name": name,
...extractMcpParameters(params),
};
return await withActiveSpan(
`tools/call ${name}`,
attributes,
async () => handler(context, params)
);
},
];
}
```
### Span Management
```typescript
async function withActiveSpan<T>(
name: string,
attributes: Record<string, any>,
fn: () => Promise<T>
): Promise<T> {
const activeSpan = getActiveSpan();
const span = activeSpan?.startSpan(name) ?? startInactiveSpan({ name });
span.setAttributes(attributes);
try {
return await fn();
} catch (error) {
span.setStatus({ code: 2, message: error.message });
throw error;
} finally {
span.end();
}
}
```
## Cloudflare Workers Setup
### Configuration
```typescript
// sentry.config.ts
export default function getSentryConfig(env: Env, context: ExecutionContext) {
return {
dsn: env.VITE_SENTRY_DSN,
environment: env.VITE_SENTRY_ENVIRONMENT || "development",
context,
integrations: [
Sentry.rewriteFramesIntegration({ root: "/" }),
],
beforeSend(event) {
// Redact sensitive data
if (event.request?.headers?.authorization) {
event.request.headers.authorization = "[REDACTED]";
}
return event;
},
};
}
```
### Worker Instrumentation
```typescript
export default Sentry.withSentry(
(env) => getSentryConfig(env),
{
async fetch(request, env, ctx): Promise<Response> {
// Attach OAuth provider to request
request.OAUTH_PROVIDER = oAuthProvider.configure(/* ... */);
return app.fetch(request, env, ctx);
},
}
);
```
## Node.js Stdio Setup
```typescript
// Init at startup
import * as Sentry from "@sentry/node";
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV || "production",
integrations: [
Sentry.nodeProfilingIntegration(),
],
tracesSampleRate: 0.1,
profilesSampleRate: 0.1,
});
// Handle uncaught errors
process.on("uncaughtException", (error) => {
Sentry.captureException(error);
process.exit(1);
});
```
## OpenTelemetry Semantic Conventions
Sentry follows OpenTelemetry semantic conventions for consistent observability.
### MCP Attributes (Model Context Protocol)
Based on [OpenTelemetry MCP conventions](https://github.com/open-telemetry/semantic-conventions/blob/3097fb0af5b9492b0e3f55dc5f6c21a3dc2be8df/docs/registry/attributes/mcp.md) (currently in **draft form**):
- `mcp.method.name` - The name of the request or notification method (e.g., "notifications/cancelled", "initialize", "notifications/initialized")
- `mcp.prompt.name` - The name of the prompt or prompt template provided in the request or response (e.g., "analyze-code")
- `mcp.request.argument.<key>` - Additional arguments passed to the request within `params` object (e.g., "mcp.request.argument.location='Seattle, WA'", "mcp.request.argument.a='42'")
- `mcp.request.id` - A unique identifier for the request (e.g., "42")
- `mcp.resource.uri` - The value of the resource uri (e.g., "postgres://database/customers/schema", "file:///home/user/documents/report.pdf")
- `mcp.session.id` - Identifies MCP session (e.g., "191c4850af6c49e08843a3f6c80e5046")
- `mcp.tool.name` - The name of the tool provided in the request (e.g., "get-weather", "execute_command")
### Custom MCP Attributes
These are custom attributes - *not in draft spec* - we've added to enhance MCP observability:
- `mcp.resource.name` - The name of the resource (e.g., "sentry-docs-platform", "sentry-query-syntax")
- `mcp.transport` - The transport method used for MCP communication (values: "http", "sse", "stdio")
### User Agent Tracking
Following [OpenTelemetry semantic conventions for user agent](https://opentelemetry.io/docs/specs/semconv/attributes-registry/user-agent/):
- `user_agent.original` - The original User-Agent header value from the client
**Cloudflare Transport**: Captured from the initial SSE/WebSocket connection request headers and cached for the session
### Network Attributes
Based on [OpenTelemetry network conventions](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/network.md):
- `network.transport` - Transport protocol used ("pipe" for stdio, "tcp" for SSE)
### GenAI Attributes (Generative AI)
Based on [OpenTelemetry GenAI conventions](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/registry/attributes/gen-ai.md):
- `gen_ai.system` - The AI system being used (e.g., "anthropic")
- `gen_ai.request.model` - Name of the GenAI model
- `gen_ai.request.max_tokens` - Maximum tokens to generate
- `gen_ai.operation.name` - Type of operation (e.g., "chat")
- `gen_ai.usage.input_tokens` - Number of tokens in input
- `gen_ai.usage.output_tokens` - Number of tokens in response
### Span Naming Pattern
Follows the format: `{mcp.method.name} {target}` per OpenTelemetry MCP semantic conventions
- Tools: `tools/call {tool_name}` (e.g., `tools/call find_issues`)
- Prompts: `prompts/get {prompt_name}` (e.g., `prompts/get analyze-code`)
- Resources: `resources/read {resource_uri}` (e.g., `resources/read https://github.com/...`)
- Client: `mcp.client/{target}` (e.g., `mcp.client/agent`)
- Connect: `mcp.connect/{transport}` (e.g., `mcp.connect/stdio`)
- Auth: `mcp.auth/{method}` (e.g., `mcp.auth/oauth`)
**Note**: Span names are flexible and can be adjusted based on your needs. However, attribute names MUST follow the OpenTelemetry semantic conventions exactly as specified above.
### Example Attributes
```typescript
// MCP Tool Execution
{
"mcp.tool.name": "find_issues",
"mcp.session.id": "191c4850af6c49e08843a3f6c80e5046"
}
// GenAI Agent
{
"gen_ai.system": "anthropic",
"gen_ai.request.model": "claude-3-5-sonnet-20241022",
"gen_ai.operation.name": "chat",
"gen_ai.usage.input_tokens": 150,
"gen_ai.usage.output_tokens": 2048
}
// Connection
{
"network.transport": "pipe", // "pipe" for stdio, "tcp" for SSE
"mcp.session.id": "191c4850af6c49e08843a3f6c80e5046",
"mcp.transport": "stdio", // Custom attribute: "stdio" or "sse"
"service.version": "1.2.3" // Version of the MCP server/client
}
// MCP Client
{
"mcp.session.id": "191c4850af6c49e08843a3f6c80e5046",
"network.transport": "pipe", // "pipe" for stdio, "tcp" for SSE
"mcp.transport": "stdio", // Custom attribute: "stdio" or "sse"
"gen_ai.system": "anthropic",
"gen_ai.request.model": "claude-3-5-sonnet-20241022",
"gen_ai.operation.name": "chat",
"service.version": "1.2.3" // Version of the MCP client
}
```
## Error Classification
### Skip Logging For:
- `UserInputError` - Expected user errors
- 4xx API responses (except 429)
- Validation errors
### Always Log:
- 5xx errors
- Network failures
- Unexpected exceptions
- Rate limit errors (429)
## Performance Monitoring
### Traces Configuration
```typescript
{
tracesSampleRate: 0.1, // 10% in production
profilesSampleRate: 0.1, // 10% of traces
}
```
## Environment Variables
### Required for Monitoring
```bash
# Cloudflare (build-time)
VITE_SENTRY_DSN=https://...@sentry.io/...
VITE_SENTRY_ENVIRONMENT=production
# Node.js (runtime)
SENTRY_DSN=https://...@sentry.io/...
NODE_ENV=production
```
## Best Practices
1. **Context is King**: Always include relevant context
2. **Redact Secrets**: Never log tokens or sensitive data
3. **Sample Wisely**: Use appropriate sampling rates
4. **Tag Everything**: Use consistent tags for filtering
5. **Skip Expected Errors**: Don't pollute with user errors
## References
- Core logging: `packages/mcp-server/src/logging.ts`
- Worker config: `packages/mcp-cloudflare/src/server/sentry.config.ts`
- Tracing helpers: `packages/mcp-server/src/tracing.ts`
- Sentry docs: https://docs.sentry.io/