Skip to content

Commit 2590d40

Browse files
committed
Fix registering multiple tools/resources/prompts
Request handlers were being re-registered every time a new tool/resource/prompt was added, which would fail since the handlers were already registered. Now we track whether handlers have been initialized and only register them once. Added tests to verify that multiple registrations work correctly. Resolves modelcontextprotocol#124.
1 parent 438505b commit 2590d40

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

src/server/mcp.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,19 @@ describe("tool()", () => {
310310
}).toThrow(/already registered/);
311311
});
312312

313+
test("should allow registering multiple tools", () => {
314+
const mcpServer = new McpServer({
315+
name: "test server",
316+
version: "1.0",
317+
});
318+
319+
// This should succeed
320+
mcpServer.tool("tool1", () => ({ content: [] }));
321+
322+
// This should also succeed and not throw about request handlers
323+
mcpServer.tool("tool2", () => ({ content: [] }));
324+
});
325+
313326
test("should allow client to call server tools", async () => {
314327
const mcpServer = new McpServer({
315328
name: "test server",
@@ -734,6 +747,33 @@ describe("resource()", () => {
734747
}).toThrow(/already registered/);
735748
});
736749

750+
test("should allow registering multiple resources", () => {
751+
const mcpServer = new McpServer({
752+
name: "test server",
753+
version: "1.0",
754+
});
755+
756+
// This should succeed
757+
mcpServer.resource("resource1", "test://resource1", async () => ({
758+
contents: [
759+
{
760+
uri: "test://resource1",
761+
text: "Test content 1",
762+
},
763+
],
764+
}));
765+
766+
// This should also succeed and not throw about request handlers
767+
mcpServer.resource("resource2", "test://resource2", async () => ({
768+
contents: [
769+
{
770+
uri: "test://resource2",
771+
text: "Test content 2",
772+
},
773+
],
774+
}));
775+
});
776+
737777
test("should prevent duplicate resource template registration", () => {
738778
const mcpServer = new McpServer({
739779
name: "test server",
@@ -1210,6 +1250,39 @@ describe("prompt()", () => {
12101250
}).toThrow(/already registered/);
12111251
});
12121252

1253+
test("should allow registering multiple prompts", () => {
1254+
const mcpServer = new McpServer({
1255+
name: "test server",
1256+
version: "1.0",
1257+
});
1258+
1259+
// This should succeed
1260+
mcpServer.prompt("prompt1", async () => ({
1261+
messages: [
1262+
{
1263+
role: "assistant",
1264+
content: {
1265+
type: "text",
1266+
text: "Test response 1",
1267+
},
1268+
},
1269+
],
1270+
}));
1271+
1272+
// This should also succeed and not throw about request handlers
1273+
mcpServer.prompt("prompt2", async () => ({
1274+
messages: [
1275+
{
1276+
role: "assistant",
1277+
content: {
1278+
type: "text",
1279+
text: "Test response 2",
1280+
},
1281+
},
1282+
],
1283+
}));
1284+
});
1285+
12131286
test("should throw McpError for invalid prompt name", async () => {
12141287
const mcpServer = new McpServer({
12151288
name: "test server",

src/server/mcp.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,13 @@ export class McpServer {
8181
await this.server.close();
8282
}
8383

84+
private _toolHandlersInitialized = false;
85+
8486
private setToolRequestHandlers() {
87+
if (this._toolHandlersInitialized) {
88+
return;
89+
}
90+
8591
this.server.assertCanSetRequestHandler(
8692
ListToolsRequestSchema.shape.method.value,
8793
);
@@ -165,6 +171,8 @@ export class McpServer {
165171
}
166172
},
167173
);
174+
175+
this._toolHandlersInitialized = true;
168176
}
169177

170178
private setCompletionRequestHandler() {
@@ -249,7 +257,13 @@ export class McpServer {
249257
return createCompletionResult(suggestions);
250258
}
251259

260+
private _resourceHandlersInitialized = false;
261+
252262
private setResourceRequestHandlers() {
263+
if (this._resourceHandlersInitialized) {
264+
return;
265+
}
266+
253267
this.server.assertCanSetRequestHandler(
254268
ListResourcesRequestSchema.shape.method.value,
255269
);
@@ -342,9 +356,17 @@ export class McpServer {
342356
);
343357

344358
this.setCompletionRequestHandler();
359+
360+
this._resourceHandlersInitialized = true;
345361
}
346362

363+
private _promptHandlersInitialized = false;
364+
347365
private setPromptRequestHandlers() {
366+
if (this._promptHandlersInitialized) {
367+
return;
368+
}
369+
348370
this.server.assertCanSetRequestHandler(
349371
ListPromptsRequestSchema.shape.method.value,
350372
);
@@ -406,6 +428,8 @@ export class McpServer {
406428
);
407429

408430
this.setCompletionRequestHandler();
431+
432+
this._promptHandlersInitialized = true;
409433
}
410434

411435
/**

0 commit comments

Comments
 (0)