From 8445e3b4af80b0fb9780f16787d1ffabbb1f88d3 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Thu, 24 Apr 2025 17:35:45 +0200 Subject: [PATCH 1/3] fix: workaround windsurf sometimes skipping the arguments --- src/server.ts | 10 ++++++++++ .../tools/mongodb/metadata/connect.test.ts | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/server.ts b/src/server.ts index fd16c75d..7adab9ae 100644 --- a/src/server.ts +++ b/src/server.ts @@ -8,6 +8,7 @@ import { mongoLogId } from "mongodb-log-writer"; import { ObjectId } from "mongodb"; import { Telemetry } from "./telemetry/telemetry.js"; import { UserConfig } from "./config.js"; +import { CallToolRequestSchema, CallToolResult } from "@modelcontextprotocol/sdk/types.js"; export interface ServerOptions { session: Session; @@ -33,6 +34,15 @@ export class Server { this.registerTools(); this.registerResources(); + const existingHandler = this.mcpServer.server["_requestHandlers"].get(CallToolRequestSchema.shape.method.value); + this.mcpServer.server.setRequestHandler(CallToolRequestSchema, (request, extra): Promise => { + if (!request.params.arguments) { + request.params.arguments = {}; + } + + return existingHandler(request, extra); + }); + await initializeLogger(this.mcpServer, this.userConfig.logPath); await this.mcpServer.connect(transport); diff --git a/tests/integration/tools/mongodb/metadata/connect.test.ts b/tests/integration/tools/mongodb/metadata/connect.test.ts index 017c6779..3b5eb6c5 100644 --- a/tests/integration/tools/mongodb/metadata/connect.test.ts +++ b/tests/integration/tools/mongodb/metadata/connect.test.ts @@ -15,6 +15,23 @@ describeWithMongoDB("Connect tool", (integration) => { }, ]); + describe("without arguments", () => { + it("prompts for connection string if not set", async () => { + const response = await integration.mcpClient().callTool({ name: "connect" }); + const content = getResponseContent(response.content); + expect(content).toContain("No connection details provided"); + }); + + it("connects to the database if connection string is set", async () => { + config.connectionString = integration.connectionString(); + + const response = await integration.mcpClient().callTool({ name: "connect" }); + const content = getResponseContent(response.content); + expect(content).toContain("Successfully connected"); + expect(content).toContain(integration.connectionString()); + }); + }); + describe("with default config", () => { describe("without connection string", () => { it("prompts for connection string", async () => { From ab4f604d0d38d116061f6f052eaafb587bf6a9fa Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Thu, 24 Apr 2025 17:43:54 +0200 Subject: [PATCH 2/3] add a comment explaining the workaround --- src/server.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/server.ts b/src/server.ts index 7adab9ae..81c54124 100644 --- a/src/server.ts +++ b/src/server.ts @@ -34,6 +34,12 @@ export class Server { this.registerTools(); this.registerResources(); + // This is a workaround for an issue we've seen with some models, where they'll see that everything in the `arguments` + // object is optional, and then not pass it at all. However, the MCP server expects the `arguments` object to be if + // the tool accepts any arguments, even if they're all optional. + // + // see: https://github.com/modelcontextprotocol/typescript-sdk/blob/131776764536b5fdca642df51230a3746fb4ade0/src/server/mcp.ts#L705 + // Since paramsSchema here is not undefined, the server will create a non-optional z.object from it. const existingHandler = this.mcpServer.server["_requestHandlers"].get(CallToolRequestSchema.shape.method.value); this.mcpServer.server.setRequestHandler(CallToolRequestSchema, (request, extra): Promise => { if (!request.params.arguments) { From 5685bd2ddac00ee1cbb747332a8aff1e8bb073b8 Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Thu, 24 Apr 2025 18:13:47 +0200 Subject: [PATCH 3/3] fix lint --- src/server.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/server.ts b/src/server.ts index 81c54124..14bea760 100644 --- a/src/server.ts +++ b/src/server.ts @@ -9,6 +9,7 @@ import { ObjectId } from "mongodb"; import { Telemetry } from "./telemetry/telemetry.js"; import { UserConfig } from "./config.js"; import { CallToolRequestSchema, CallToolResult } from "@modelcontextprotocol/sdk/types.js"; +import assert from "assert"; export interface ServerOptions { session: Session; @@ -40,7 +41,15 @@ export class Server { // // see: https://github.com/modelcontextprotocol/typescript-sdk/blob/131776764536b5fdca642df51230a3746fb4ade0/src/server/mcp.ts#L705 // Since paramsSchema here is not undefined, the server will create a non-optional z.object from it. - const existingHandler = this.mcpServer.server["_requestHandlers"].get(CallToolRequestSchema.shape.method.value); + const existingHandler = ( + this.mcpServer.server["_requestHandlers"] as Map< + string, + (request: unknown, extra: unknown) => Promise + > + ).get(CallToolRequestSchema.shape.method.value); + + assert(existingHandler, "No existing handler found for CallToolRequestSchema"); + this.mcpServer.server.setRequestHandler(CallToolRequestSchema, (request, extra): Promise => { if (!request.params.arguments) { request.params.arguments = {};