-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathindex.test.ts
More file actions
110 lines (100 loc) · 3.5 KB
/
index.test.ts
File metadata and controls
110 lines (100 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { expect, test } from '@playwright/test';
import { waitForRequest } from '@sentry-internal/test-utils';
test('sends spans for MCP tool calls', async ({ baseURL }) => {
const spanRequestWaiter = waitForRequest('cloudflare-mcp', event => {
const transaction = event.envelope[1][0][1];
return typeof transaction !== 'string' && 'transaction' in transaction && transaction.transaction === 'POST /mcp';
});
const spanMcpWaiter = waitForRequest('cloudflare-mcp', event => {
const transaction = event.envelope[1][0][1];
return (
typeof transaction !== 'string' &&
'transaction' in transaction &&
transaction.transaction === 'tools/call my-tool'
);
});
const response = await fetch(`${baseURL}/mcp`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json, text/event-stream',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: {
name: 'my-tool',
arguments: {
message: 'ʕっ•ᴥ•ʔっ',
},
},
}),
});
expect(response.status).toBe(200);
const requestData = await spanRequestWaiter;
const mcpData = await spanMcpWaiter;
const requestEvent = requestData.envelope[1][0][1];
const mcpEvent = mcpData.envelope[1][0][1];
// Check that the events have contexts
// this is for TypeScript type safety
if (
typeof mcpEvent === 'string' ||
!('contexts' in mcpEvent) ||
typeof requestEvent === 'string' ||
!('contexts' in requestEvent)
) {
throw new Error("Events don't have contexts");
}
expect(mcpEvent.contexts?.trace?.trace_id).toBe((mcpData.envelope[0].trace as any).trace_id);
expect(requestData.envelope[0].event_id).not.toBe(mcpData.envelope[0].event_id);
expect(requestEvent.contexts?.trace).toEqual({
span_id: expect.any(String),
trace_id: expect.any(String),
data: expect.objectContaining({
'sentry.origin': 'auto.http.cloudflare',
'sentry.op': 'http.server',
'sentry.source': 'url',
'sentry.sample_rate': 1,
'http.request.method': 'POST',
'url.path': '/mcp',
'url.full': 'http://localhost:38787/mcp',
'url.port': '38787',
'url.scheme': 'http:',
'server.address': 'localhost',
'http.request.body.size': 120,
'user_agent.original': 'node',
'http.request.header.content_type': 'application/json',
'network.protocol.name': 'HTTP/1.1',
'mcp.server.extra': ' /|\ ^._.^ /|\ ',
'http.response.status_code': 200,
}),
op: 'http.server',
status: 'ok',
origin: 'auto.http.cloudflare',
});
expect(mcpEvent.contexts?.trace).toEqual({
trace_id: expect.any(String),
parent_span_id: requestEvent.contexts?.trace?.span_id,
span_id: expect.any(String),
op: 'mcp.server',
origin: 'auto.function.mcp_server',
data: {
'sentry.origin': 'auto.function.mcp_server',
'sentry.op': 'mcp.server',
'sentry.source': 'route',
'mcp.transport': 'WorkerTransport',
'network.transport': 'unknown',
'network.protocol.version': '2.0',
'mcp.method.name': 'tools/call',
'mcp.request.id': '1',
'mcp.tool.name': 'my-tool',
'mcp.request.argument.message': '"ʕっ•ᴥ•ʔっ"',
'mcp.tool.extra': 'ƸӜƷ',
'mcp.tool.input': '{"message":"ʕっ•ᴥ•ʔっ"}',
'mcp.tool.result.content_count': 1,
'mcp.tool.result.content_type': 'text',
'mcp.tool.result.content': 'Tool my-tool: ʕっ•ᴥ•ʔっ',
},
});
});