Skip to content

Commit 8ec42a2

Browse files
betegonclaude
andcommitted
test(core): add tests and e2e coverage for register* MCP API
- Add createMockMcpServerWithRegisterApi() to test utilities - Test validation accepts register*-only servers and rejects invalid ones - Test that registerTool/registerResource/registerPrompt get wrapped - Add registerTool handler to node-express, node-express-v5, tsx-express e2e apps Co-Authored-By: claude-sonnet-4-6 <noreply@anthropic.com>
1 parent a470a44 commit 8ec42a2

File tree

5 files changed

+125
-2
lines changed

5 files changed

+125
-2
lines changed

dev-packages/e2e-tests/test-applications/node-express-v5/src/mcp.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ server.tool('echo', { message: z.string() }, async ({ message }, rest) => {
3535
};
3636
});
3737

38+
server.registerTool(
39+
'echo-register',
40+
{ description: 'Echo tool (register API)', inputSchema: { message: z.string() } },
41+
async ({ message }) => ({
42+
content: [{ type: 'text', text: `registerTool echo: ${message}` }],
43+
}),
44+
);
45+
3846
server.prompt('echo', { message: z.string() }, ({ message }, extra) => ({
3947
messages: [
4048
{
@@ -103,6 +111,14 @@ streamableServer.tool('echo', { message: z.string() }, async ({ message }) => {
103111
};
104112
});
105113

114+
streamableServer.registerTool(
115+
'echo-register',
116+
{ description: 'Echo tool (register API)', inputSchema: { message: z.string() } },
117+
async ({ message }) => ({
118+
content: [{ type: 'text', text: `registerTool echo: ${message}` }],
119+
}),
120+
);
121+
106122
streamableServer.prompt('echo', { message: z.string() }, ({ message }) => ({
107123
messages: [
108124
{

dev-packages/e2e-tests/test-applications/node-express/src/mcp.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ server.tool('echo', { message: z.string() }, async ({ message }, rest) => {
3535
};
3636
});
3737

38+
server.registerTool(
39+
'echo-register',
40+
{ description: 'Echo tool (register API)', inputSchema: { message: z.string() } },
41+
async ({ message }) => ({
42+
content: [{ type: 'text', text: `registerTool echo: ${message}` }],
43+
}),
44+
);
45+
3846
server.prompt('echo', { message: z.string() }, ({ message }, extra) => ({
3947
messages: [
4048
{
@@ -103,6 +111,14 @@ streamableServer.tool('echo', { message: z.string() }, async ({ message }) => {
103111
};
104112
});
105113

114+
streamableServer.registerTool(
115+
'echo-register',
116+
{ description: 'Echo tool (register API)', inputSchema: { message: z.string() } },
117+
async ({ message }) => ({
118+
content: [{ type: 'text', text: `registerTool echo: ${message}` }],
119+
}),
120+
);
121+
106122
streamableServer.prompt('echo', { message: z.string() }, ({ message }) => ({
107123
messages: [
108124
{

dev-packages/e2e-tests/test-applications/tsx-express/src/mcp.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ server.tool('echo', { message: z.string() }, async ({ message }, rest) => {
3535
};
3636
});
3737

38+
server.registerTool(
39+
'echo-register',
40+
{ description: 'Echo tool (register API)', inputSchema: { message: z.string() } },
41+
async ({ message }) => ({
42+
content: [{ type: 'text', text: `registerTool echo: ${message}` }],
43+
}),
44+
);
45+
3846
server.prompt('echo', { message: z.string() }, ({ message }, extra) => ({
3947
messages: [
4048
{
@@ -103,6 +111,14 @@ streamableServer.tool('echo', { message: z.string() }, async ({ message }) => {
103111
};
104112
});
105113

114+
streamableServer.registerTool(
115+
'echo-register',
116+
{ description: 'Echo tool (register API)', inputSchema: { message: z.string() } },
117+
async ({ message }) => ({
118+
content: [{ type: 'text', text: `registerTool echo: ${message}` }],
119+
}),
120+
);
121+
106122
streamableServer.prompt('echo', { message: z.string() }, ({ message }) => ({
107123
messages: [
108124
{

packages/core/test/lib/integrations/mcp-server/mcpServerWrapper.test.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
22
import * as currentScopes from '../../../../src/currentScopes';
33
import { wrapMcpServerWithSentry } from '../../../../src/integrations/mcp-server';
44
import * as tracingModule from '../../../../src/tracing';
5-
import { createMockMcpServer } from './testUtils';
5+
import { createMockMcpServer, createMockMcpServerWithRegisterApi } from './testUtils';
66

77
describe('wrapMcpServerWithSentry', () => {
88
const startSpanSpy = vi.spyOn(tracingModule, 'startSpan');
@@ -45,6 +45,19 @@ describe('wrapMcpServerWithSentry', () => {
4545
expect(startInactiveSpanSpy).not.toHaveBeenCalled();
4646
});
4747

48+
it('should accept a server with only the new register* API (no legacy methods)', () => {
49+
const mockServer = createMockMcpServerWithRegisterApi();
50+
const result = wrapMcpServerWithSentry(mockServer);
51+
expect(result).toBe(mockServer);
52+
});
53+
54+
it('should reject a server with neither legacy nor register* methods', () => {
55+
const invalidServer = { connect: vi.fn() };
56+
const result = wrapMcpServerWithSentry(invalidServer);
57+
expect(result).toBe(invalidServer);
58+
expect(startSpanSpy).not.toHaveBeenCalled();
59+
});
60+
4861
it('should not wrap the same instance twice', () => {
4962
const mockMcpServer = createMockMcpServer();
5063

@@ -77,6 +90,19 @@ describe('wrapMcpServerWithSentry', () => {
7790
expect(wrappedMcpServer.prompt).not.toBe(originalPrompt);
7891
});
7992

93+
it('should wrap handler methods (registerTool, registerResource, registerPrompt)', () => {
94+
const mockServer = createMockMcpServerWithRegisterApi();
95+
const originalRegisterTool = mockServer.registerTool;
96+
const originalRegisterResource = mockServer.registerResource;
97+
const originalRegisterPrompt = mockServer.registerPrompt;
98+
99+
const wrapped = wrapMcpServerWithSentry(mockServer);
100+
101+
expect(wrapped.registerTool).not.toBe(originalRegisterTool);
102+
expect(wrapped.registerResource).not.toBe(originalRegisterResource);
103+
expect(wrapped.registerPrompt).not.toBe(originalRegisterPrompt);
104+
});
105+
80106
describe('Handler Wrapping', () => {
81107
let mockMcpServer: ReturnType<typeof createMockMcpServer>;
82108
let wrappedMcpServer: ReturnType<typeof createMockMcpServer>;
@@ -118,4 +144,38 @@ describe('wrapMcpServerWithSentry', () => {
118144
}).not.toThrow();
119145
});
120146
});
147+
148+
describe('Handler Wrapping (register* API)', () => {
149+
let mockServer: ReturnType<typeof createMockMcpServerWithRegisterApi>;
150+
let wrappedServer: ReturnType<typeof createMockMcpServerWithRegisterApi>;
151+
152+
beforeEach(() => {
153+
mockServer = createMockMcpServerWithRegisterApi();
154+
wrappedServer = wrapMcpServerWithSentry(mockServer);
155+
});
156+
157+
it('should register tool handlers via registerTool without throwing errors', () => {
158+
const toolHandler = vi.fn();
159+
160+
expect(() => {
161+
wrappedServer.registerTool('test-tool', {}, toolHandler);
162+
}).not.toThrow();
163+
});
164+
165+
it('should register resource handlers via registerResource without throwing errors', () => {
166+
const resourceHandler = vi.fn();
167+
168+
expect(() => {
169+
wrappedServer.registerResource('test-resource', 'res://test', {}, resourceHandler);
170+
}).not.toThrow();
171+
});
172+
173+
it('should register prompt handlers via registerPrompt without throwing errors', () => {
174+
const promptHandler = vi.fn();
175+
176+
expect(() => {
177+
wrappedServer.registerPrompt('test-prompt', {}, promptHandler);
178+
}).not.toThrow();
179+
});
180+
});
121181
});

packages/core/test/lib/integrations/mcp-server/testUtils.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { vi } from 'vitest';
22

33
/**
4-
* Create a mock MCP server instance for testing
4+
* Create a mock MCP server instance for testing (legacy API: tool/resource/prompt)
55
*/
66
export function createMockMcpServer() {
77
return {
@@ -15,6 +15,21 @@ export function createMockMcpServer() {
1515
};
1616
}
1717

18+
/**
19+
* Create a mock MCP server instance using the new register* API (SDK >=1.x / 2.x)
20+
*/
21+
export function createMockMcpServerWithRegisterApi() {
22+
return {
23+
registerResource: vi.fn(),
24+
registerTool: vi.fn(),
25+
registerPrompt: vi.fn(),
26+
connect: vi.fn().mockResolvedValue(undefined),
27+
server: {
28+
setRequestHandler: vi.fn(),
29+
},
30+
};
31+
}
32+
1833
/**
1934
* Create a mock HTTP transport (StreamableHTTPServerTransport)
2035
* Uses exact naming pattern from the official SDK

0 commit comments

Comments
 (0)