Skip to content

Commit 77513d9

Browse files
authored
fix: workaround models not providing arguments when everything is optional (#116)
1 parent 4350cb3 commit 77513d9

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

src/server.ts

+25
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { mongoLogId } from "mongodb-log-writer";
88
import { ObjectId } from "mongodb";
99
import { Telemetry } from "./telemetry/telemetry.js";
1010
import { UserConfig } from "./config.js";
11+
import { CallToolRequestSchema, CallToolResult } from "@modelcontextprotocol/sdk/types.js";
12+
import assert from "assert";
1113

1214
export interface ServerOptions {
1315
session: Session;
@@ -33,6 +35,29 @@ export class Server {
3335
this.registerTools();
3436
this.registerResources();
3537

38+
// This is a workaround for an issue we've seen with some models, where they'll see that everything in the `arguments`
39+
// object is optional, and then not pass it at all. However, the MCP server expects the `arguments` object to be if
40+
// the tool accepts any arguments, even if they're all optional.
41+
//
42+
// see: https://github.com/modelcontextprotocol/typescript-sdk/blob/131776764536b5fdca642df51230a3746fb4ade0/src/server/mcp.ts#L705
43+
// Since paramsSchema here is not undefined, the server will create a non-optional z.object from it.
44+
const existingHandler = (
45+
this.mcpServer.server["_requestHandlers"] as Map<
46+
string,
47+
(request: unknown, extra: unknown) => Promise<CallToolResult>
48+
>
49+
).get(CallToolRequestSchema.shape.method.value);
50+
51+
assert(existingHandler, "No existing handler found for CallToolRequestSchema");
52+
53+
this.mcpServer.server.setRequestHandler(CallToolRequestSchema, (request, extra): Promise<CallToolResult> => {
54+
if (!request.params.arguments) {
55+
request.params.arguments = {};
56+
}
57+
58+
return existingHandler(request, extra);
59+
});
60+
3661
await initializeLogger(this.mcpServer, this.userConfig.logPath);
3762

3863
await this.mcpServer.connect(transport);

tests/integration/tools/mongodb/metadata/connect.test.ts

+17
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,23 @@ describeWithMongoDB("Connect tool", (integration) => {
1515
},
1616
]);
1717

18+
describe("without arguments", () => {
19+
it("prompts for connection string if not set", async () => {
20+
const response = await integration.mcpClient().callTool({ name: "connect" });
21+
const content = getResponseContent(response.content);
22+
expect(content).toContain("No connection details provided");
23+
});
24+
25+
it("connects to the database if connection string is set", async () => {
26+
config.connectionString = integration.connectionString();
27+
28+
const response = await integration.mcpClient().callTool({ name: "connect" });
29+
const content = getResponseContent(response.content);
30+
expect(content).toContain("Successfully connected");
31+
expect(content).toContain(integration.connectionString());
32+
});
33+
});
34+
1835
describe("with default config", () => {
1936
describe("without connection string", () => {
2037
it("prompts for connection string", async () => {

0 commit comments

Comments
 (0)