Skip to content

Commit d3a0de2

Browse files
authored
feat(js-mcp): manual instrumentation docs (#15530)
Adds docs for manual instrumentation of Javascript MCP Servers, aligned with the Python manual instrumentation
1 parent 923546e commit d3a0de2

File tree

2 files changed

+215
-7
lines changed

2 files changed

+215
-7
lines changed
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
---
2+
title: Instrument MCP Servers
3+
sidebar_order: 600
4+
description: "Learn how to manually instrument your code to use Sentry's MCP monitoring."
5+
supported:
6+
- javascript.node
7+
- javascript.aws-lambda
8+
- javascript.azure-functions
9+
- javascript.connect
10+
- javascript.express
11+
- javascript.fastify
12+
- javascript.gcp-functions
13+
- javascript.hapi
14+
- javascript.hono
15+
- javascript.koa
16+
- javascript.nestjs
17+
- javascript.bun
18+
- javascript.deno
19+
- javascript.nextjs
20+
- javascript.nuxt
21+
- javascript.astro
22+
- javascript.solidstart
23+
- javascript.sveltekit
24+
- javascript.remix
25+
- javascript.cloudflare
26+
- javascript.tanstackstart-react
27+
---
28+
29+
With Sentry's [MCP monitoring](/product/insights/ai/mcp/), you can track and debug MCP servers with full-stack context. You'll be able to monitor tool executions, prompt retrievals, resource access, and error rates. MCP monitoring data will be fully connected to your other Sentry data like logs, errors, and traces.
30+
31+
As a prerequisite to setting up MCP monitoring with JavaScript, you'll need to first <PlatformLink to="/tracing/">set up tracing</PlatformLink>. Once this is done, the JavaScript SDK will automatically instrument MCP servers created with supported libraries. If that doesn't fit your use case, you can use custom instrumentation described below.
32+
33+
## Automatic Instrumentation
34+
35+
The JavaScript SDK supports automatic instrumentation for MCP servers. We recommend adding the MCP integration to your Sentry configuration to automatically capture spans for MCP operations.
36+
37+
- <PlatformLink to="/integrations/mcp/">
38+
MCP (Model Context Protocol)
39+
</PlatformLink>
40+
41+
## Manual Instrumentation
42+
43+
For your MCP data to show up in Sentry, spans must be created with well-defined names and data attributes. See below for the different types of MCP operations you can instrument.
44+
45+
The [Sentry.startSpan()](/platforms/javascript/tracing/instrumentation/custom-instrumentation/#starting-a-span) method can be used to create these spans.
46+
47+
## Spans
48+
49+
### Tool Execution Span
50+
51+
<Include name="tracing/mcp-module/tool-execution-span" />
52+
53+
#### Example Tool Execution Span:
54+
55+
```javascript
56+
import * as Sentry from "@sentry/node";
57+
58+
Sentry.init({
59+
// ... your Sentry configuration
60+
});
61+
62+
// Example tool execution
63+
const toolName = "get_weather";
64+
const toolArguments = { city: "San Francisco" };
65+
66+
await Sentry.startSpan(
67+
{
68+
op: "mcp.server",
69+
name: `tools/call ${toolName}`,
70+
},
71+
async (span) => {
72+
// Set MCP-specific attributes
73+
span.setAttribute("mcp.tool.name", toolName);
74+
span.setAttribute("mcp.method.name", "tools/call");
75+
76+
// Set request metadata
77+
span.setAttribute("mcp.request.id", "req_123abc");
78+
span.setAttribute("mcp.session.id", "session_xyz789");
79+
span.setAttribute("mcp.transport", "stdio"); // or "http", "sse" for HTTP/WebSocket/SSE
80+
span.setAttribute("network.transport", "pipe"); // or "tcp" for HTTP/SSE
81+
82+
// Set tool arguments (optional, if send_default_pii=true)
83+
for (const [key, value] of Object.entries(toolArguments)) {
84+
span.setAttribute(`mcp.request.argument.${key}`, value);
85+
}
86+
87+
// Execute the tool
88+
try {
89+
const result = executeTool(toolName, toolArguments);
90+
91+
// Set result data
92+
span.setAttribute("mcp.tool.result.content", JSON.stringify(result));
93+
span.setAttribute("mcp.tool.result.is_error", false);
94+
95+
// Set result content count if applicable
96+
if (
97+
Array.isArray(result) ||
98+
(typeof result === "object" && result !== null)
99+
) {
100+
span.setAttribute(
101+
"mcp.tool.result.content_count",
102+
Array.isArray(result) ? result.length : Object.keys(result).length
103+
);
104+
}
105+
} catch (error) {
106+
span.setAttribute("mcp.tool.result.is_error", true);
107+
throw error;
108+
}
109+
}
110+
);
111+
```
112+
113+
### Prompt Retrieval Span
114+
115+
<Include name="tracing/mcp-module/prompt-retrieval-span" />
116+
117+
#### Example Prompt Retrieval Span:
118+
119+
```javascript
120+
import * as Sentry from "@sentry/node";
121+
122+
Sentry.init({
123+
// ... your Sentry configuration
124+
});
125+
126+
// Example prompt retrieval
127+
const promptName = "code_review";
128+
const promptArguments = { language: "python" };
129+
130+
await Sentry.startSpan(
131+
{
132+
op: "mcp.server",
133+
name: `prompts/get ${promptName}`,
134+
},
135+
async (span) => {
136+
// Set MCP-specific attributes
137+
span.setAttribute("mcp.prompt.name", promptName);
138+
span.setAttribute("mcp.method.name", "prompts/get");
139+
140+
// Set request metadata
141+
span.setAttribute("mcp.request.id", "req_456def");
142+
span.setAttribute("mcp.session.id", "session_xyz789");
143+
span.setAttribute("mcp.transport", "http");
144+
span.setAttribute("network.transport", "tcp");
145+
146+
// Set prompt arguments (optional, if send_default_pii=true)
147+
for (const [key, value] of Object.entries(promptArguments)) {
148+
span.setAttribute(`mcp.request.argument.${key}`, value);
149+
}
150+
151+
// Retrieve the prompt
152+
const promptResult = getPrompt(promptName, promptArguments);
153+
154+
// Set result data
155+
const messages = promptResult.messages || [];
156+
span.setAttribute("mcp.prompt.result.message_count", messages.length);
157+
158+
// For single-message prompts, set role and content
159+
if (messages.length === 1) {
160+
span.setAttribute("mcp.prompt.result.message_role", messages[0].role);
161+
// Content is PII, only set if send_default_pii=true
162+
span.setAttribute(
163+
"mcp.prompt.result.message_content",
164+
JSON.stringify(messages[0].content)
165+
);
166+
}
167+
}
168+
);
169+
```
170+
171+
### Resource Read Span
172+
173+
<Include name="tracing/mcp-module/resource-read-span" />
174+
175+
#### Example Resource Read Span:
176+
177+
```javascript
178+
import * as Sentry from "@sentry/node";
179+
180+
Sentry.init({
181+
// ... your Sentry configuration
182+
});
183+
184+
// Example resource access
185+
const resourceUri = "file:///path/to/resource.txt";
186+
187+
await Sentry.startSpan(
188+
{
189+
op: "mcp.server",
190+
name: `resources/read ${resourceUri}`,
191+
},
192+
async (span) => {
193+
// Set MCP-specific attributes
194+
span.setAttribute("mcp.resource.uri", resourceUri);
195+
span.setAttribute("mcp.method.name", "resources/read");
196+
197+
// Set request metadata
198+
span.setAttribute("mcp.request.id", "req_789ghi");
199+
span.setAttribute("mcp.session.id", "session_xyz789");
200+
span.setAttribute("mcp.transport", "http");
201+
span.setAttribute("network.transport", "tcp");
202+
203+
// Access the resource
204+
const resourceData = readResource(resourceUri);
205+
}
206+
);
207+
```
208+
209+
## Common Span Attributes
210+
211+
<Include name="tracing/mcp-module/common-span-attributes" />

docs/platforms/python/tracing/instrumentation/custom-instrumentation/mcp-module.mdx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ with sentry_sdk.start_span(
5151
# Set request metadata
5252
span.set_data("mcp.request.id", "req_123abc")
5353
span.set_data("mcp.session.id", "session_xyz789")
54-
span.set_data("mcp.transport", "pipe") # or "tcp" for HTTP/WebSocket/SSE
54+
span.set_data("mcp.transport", "stdio") # or "http", "sse" for HTTP/WebSocket/SSE
55+
span.set_data("network.transport", "pipe") # or "tcp" for HTTP/SSE
5556

5657
# Set tool arguments (optional, if send_default_pii=True)
5758
for key, value in tool_arguments.items():
@@ -101,6 +102,7 @@ with sentry_sdk.start_span(
101102
span.set_data("mcp.request.id", "req_456def")
102103
span.set_data("mcp.session.id", "session_xyz789")
103104
span.set_data("mcp.transport", "http")
105+
span.set_data("network.transport", "tcp")
104106

105107
# Set prompt arguments (optional, if send_default_pii=True)
106108
for key, value in prompt_arguments.items():
@@ -131,7 +133,6 @@ with sentry_sdk.start_span(
131133

132134
```python
133135
import sentry_sdk
134-
from urllib.parse import urlparse
135136

136137
sentry_sdk.init(...)
137138

@@ -146,15 +147,11 @@ with sentry_sdk.start_span(
146147
span.set_data("mcp.resource.uri", resource_uri)
147148
span.set_data("mcp.method.name", "resources/read")
148149

149-
# Extract and set protocol/scheme
150-
parsed_uri = urlparse(resource_uri)
151-
if parsed_uri.scheme:
152-
span.set_data("mcp.resource.protocol", parsed_uri.scheme)
153-
154150
# Set request metadata
155151
span.set_data("mcp.request.id", "req_789ghi")
156152
span.set_data("mcp.session.id", "session_xyz789")
157153
span.set_data("mcp.transport", "http")
154+
span.set_data("network.transport", "tcp")
158155

159156
# Access the resource
160157
resource_data = read_resource(resource_uri)

0 commit comments

Comments
 (0)