Skip to content

Commit 6b141fb

Browse files
daniel-lxsroomote
andauthored
fix: disable strict mode for MCP tools to preserve optional parameters (#10220)
Co-authored-by: Roo Code <[email protected]>
1 parent 529e0d7 commit 6b141fb

File tree

4 files changed

+75
-20
lines changed

4 files changed

+75
-20
lines changed

src/api/providers/base-provider.ts

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { ModelInfo } from "@roo-code/types"
55
import type { ApiHandler, ApiHandlerCreateMessageMetadata } from "../index"
66
import { ApiStream } from "../transform/stream"
77
import { countTokens } from "../../utils/countTokens"
8+
import { isMcpTool } from "../../utils/mcp-name"
89

910
/**
1011
* Base class for API providers that implements common functionality.
@@ -28,18 +29,26 @@ export abstract class BaseProvider implements ApiHandler {
2829
return undefined
2930
}
3031

31-
return tools.map((tool) =>
32-
tool.type === "function"
33-
? {
34-
...tool,
35-
function: {
36-
...tool.function,
37-
strict: true,
38-
parameters: this.convertToolSchemaForOpenAI(tool.function.parameters),
39-
},
40-
}
41-
: tool,
42-
)
32+
return tools.map((tool) => {
33+
if (tool.type !== "function") {
34+
return tool
35+
}
36+
37+
// MCP tools use the 'mcp--' prefix - disable strict mode for them
38+
// to preserve optional parameters from the MCP server schema
39+
const isMcp = isMcpTool(tool.function.name)
40+
41+
return {
42+
...tool,
43+
function: {
44+
...tool.function,
45+
strict: !isMcp,
46+
parameters: isMcp
47+
? tool.function.parameters
48+
: this.convertToolSchemaForOpenAI(tool.function.parameters),
49+
},
50+
}
51+
})
4352
}
4453

4554
/**

src/api/providers/openai-native.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { getModelParams } from "../transform/model-params"
2424

2525
import { BaseProvider } from "./base-provider"
2626
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
27+
import { isMcpTool } from "../../utils/mcp-name"
2728

2829
export type OpenAiNativeModel = ReturnType<OpenAiNativeHandler["getModel"]>
2930

@@ -291,13 +292,18 @@ export class OpenAiNativeHandler extends BaseProvider implements SingleCompletio
291292
...(metadata?.tools && {
292293
tools: metadata.tools
293294
.filter((tool) => tool.type === "function")
294-
.map((tool) => ({
295-
type: "function",
296-
name: tool.function.name,
297-
description: tool.function.description,
298-
parameters: ensureAllRequired(tool.function.parameters),
299-
strict: true,
300-
})),
295+
.map((tool) => {
296+
// MCP tools use the 'mcp--' prefix - disable strict mode for them
297+
// to preserve optional parameters from the MCP server schema
298+
const isMcp = isMcpTool(tool.function.name)
299+
return {
300+
type: "function",
301+
name: tool.function.name,
302+
description: tool.function.description,
303+
parameters: isMcp ? tool.function.parameters : ensureAllRequired(tool.function.parameters),
304+
strict: !isMcp,
305+
}
306+
}),
301307
}),
302308
...(metadata?.tool_choice && { tool_choice: metadata.tool_choice }),
303309
}

src/utils/__tests__/mcp-name.spec.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { sanitizeMcpName, buildMcpToolName, parseMcpToolName, MCP_TOOL_SEPARATOR, MCP_TOOL_PREFIX } from "../mcp-name"
1+
import {
2+
sanitizeMcpName,
3+
buildMcpToolName,
4+
parseMcpToolName,
5+
isMcpTool,
6+
MCP_TOOL_SEPARATOR,
7+
MCP_TOOL_PREFIX,
8+
} from "../mcp-name"
29

310
describe("mcp-name utilities", () => {
411
describe("constants", () => {
@@ -8,6 +15,29 @@ describe("mcp-name utilities", () => {
815
})
916
})
1017

18+
describe("isMcpTool", () => {
19+
it("should return true for valid MCP tool names", () => {
20+
expect(isMcpTool("mcp--server--tool")).toBe(true)
21+
expect(isMcpTool("mcp--my_server--get_forecast")).toBe(true)
22+
})
23+
24+
it("should return false for non-MCP tool names", () => {
25+
expect(isMcpTool("server--tool")).toBe(false)
26+
expect(isMcpTool("tool")).toBe(false)
27+
expect(isMcpTool("read_file")).toBe(false)
28+
expect(isMcpTool("")).toBe(false)
29+
})
30+
31+
it("should return false for old underscore format", () => {
32+
expect(isMcpTool("mcp_server_tool")).toBe(false)
33+
})
34+
35+
it("should return false for partial prefix", () => {
36+
expect(isMcpTool("mcp-server")).toBe(false)
37+
expect(isMcpTool("mcp")).toBe(false)
38+
})
39+
})
40+
1141
describe("sanitizeMcpName", () => {
1242
it("should return underscore placeholder for empty input", () => {
1343
expect(sanitizeMcpName("")).toBe("_")

src/utils/mcp-name.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ export const MCP_TOOL_SEPARATOR = "--"
1717
*/
1818
export const MCP_TOOL_PREFIX = "mcp"
1919

20+
/**
21+
* Check if a tool name is an MCP tool (starts with the MCP prefix and separator).
22+
*
23+
* @param toolName - The tool name to check
24+
* @returns true if the tool name starts with "mcp--", false otherwise
25+
*/
26+
export function isMcpTool(toolName: string): boolean {
27+
return toolName.startsWith(`${MCP_TOOL_PREFIX}${MCP_TOOL_SEPARATOR}`)
28+
}
29+
2030
/**
2131
* Sanitize a name to be safe for use in API function names.
2232
* This removes special characters and ensures the name starts correctly.

0 commit comments

Comments
 (0)