Skip to content

Commit be87373

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 be87373

File tree

6 files changed

+155
-8
lines changed

6 files changed

+155
-8
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/src/integrations/mcp-server/types.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,22 +93,46 @@ export type JsonRpcMessage = JsonRpcRequest | JsonRpcNotification | JsonRpcRespo
9393
* and made the only option in SDK 2.x.
9494
*/
9595
export interface MCPServerInstance {
96-
/** Register a resource handler (legacy API) */
96+
/**
97+
* Register a resource handler.
98+
* Supported in `@modelcontextprotocol/sdk` v1.x alongside `registerResource`.
99+
* @deprecated Removed in `@modelcontextprotocol/sdk` v2.0.0 — use `registerResource` instead.
100+
*/
97101
resource?: (name: string, ...args: unknown[]) => void;
98102

99-
/** Register a tool handler (legacy API) */
103+
/**
104+
* Register a tool handler.
105+
* Supported in `@modelcontextprotocol/sdk` v1.x alongside `registerTool`.
106+
* @deprecated Removed in `@modelcontextprotocol/sdk` v2.0.0 — use `registerTool` instead.
107+
*/
100108
tool?: (name: string, ...args: unknown[]) => void;
101109

102-
/** Register a prompt handler (legacy API) */
110+
/**
111+
* Register a prompt handler.
112+
* Supported in `@modelcontextprotocol/sdk` v1.x alongside `registerPrompt`.
113+
* @deprecated Removed in `@modelcontextprotocol/sdk` v2.0.0 — use `registerPrompt` instead.
114+
*/
103115
prompt?: (name: string, ...args: unknown[]) => void;
104116

105-
/** Register a resource handler (new API, SDK >=1.x / 2.x) */
117+
/**
118+
* Register a resource handler.
119+
* Available in `@modelcontextprotocol/sdk` v1.x (alongside the legacy `resource` method)
120+
* and the only supported form in v2.0.0+.
121+
*/
106122
registerResource?: (name: string, ...args: unknown[]) => void;
107123

108-
/** Register a tool handler (new API, SDK >=1.x / 2.x) */
124+
/**
125+
* Register a tool handler.
126+
* Available in `@modelcontextprotocol/sdk` v1.x (alongside the legacy `tool` method)
127+
* and the only supported form in v2.0.0+.
128+
*/
109129
registerTool?: (name: string, ...args: unknown[]) => void;
110130

111-
/** Register a prompt handler (new API, SDK >=1.x / 2.x) */
131+
/**
132+
* Register a prompt handler.
133+
* Available in `@modelcontextprotocol/sdk` v1.x (alongside the legacy `prompt` method)
134+
* and the only supported form in v2.0.0+.
135+
*/
112136
registerPrompt?: (name: string, ...args: unknown[]) => void;
113137

114138
/** Connect the server to a transport */

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)