diff --git a/src/adapters/cursor/tool-definitions.ts b/src/adapters/cursor/tool-definitions.ts index 7688f209a1..6580531c6a 100644 --- a/src/adapters/cursor/tool-definitions.ts +++ b/src/adapters/cursor/tool-definitions.ts @@ -91,29 +91,18 @@ export function cursorToolChoiceAliases(tool: Pick[], -): boolean { - return catalog.some(isBareCodexShellBridgeTool); -} - /** - * Catalog-aware tool_choice matching for Cursor. - * When a bare Codex shell bridge is in the catalog, raw `shell_command` / `exec_command` - * choices select only that bridge (never a namespaced remote with the same raw name). - * When no bare bridge exists, raw bridge names may select a namespaced tool by raw name. + * Tool-choice matching for Cursor. + * Raw `shell_command` / `exec_command` choices select only a bare Codex shell bridge + * (never a namespaced remote with the same raw name), and fail closed when absent. * Explicit wire names (`mcp__remote__exec_command`) always match the namespaced tool. */ function cursorToolChoiceMatches( tool: Pick, choiceName: string, - catalog: readonly Pick[], ): boolean { if (isCodexShellBridgeToolName(choiceName)) { - if (catalogHasBareCodexShellBridge(catalog)) { - return isBareCodexShellBridgeTool(tool); - } - return tool.name === choiceName || cursorToolWireName(tool) === choiceName; + return isBareCodexShellBridgeTool(tool); } if (tool.name === choiceName || cursorToolWireName(tool) === choiceName) return true; return cursorToolChoiceAliases(tool).includes(choiceName); @@ -371,14 +360,14 @@ export function cursorShellBridgeArgsValid( export function cursorToolAllowedByChoice( tool: Pick, toolChoice: OcxRequestOptions["toolChoice"] | undefined, - catalog: readonly Pick[] = [tool], + _catalog: readonly Pick[] = [tool], ): boolean { if (!toolChoice || toolChoice === "auto" || toolChoice === "required") return true; if (toolChoice === "none") return false; if ("allowedTools" in toolChoice) { - return toolChoice.allowedTools.some(choiceName => cursorToolChoiceMatches(tool, choiceName, catalog)); + return toolChoice.allowedTools.some(choiceName => cursorToolChoiceMatches(tool, choiceName)); } - return cursorToolChoiceMatches(tool, toolChoice.name, catalog); + return cursorToolChoiceMatches(tool, toolChoice.name); } function quotedNames(names: readonly string[]): string { diff --git a/tests/cursor-tool-choice.test.ts b/tests/cursor-tool-choice.test.ts index fe6da06331..829180db6f 100644 --- a/tests/cursor-tool-choice.test.ts +++ b/tests/cursor-tool-choice.test.ts @@ -44,21 +44,22 @@ describe("Cursor Responses tool_choice support", () => { expect(buildCursorToolDefinitions(toolsWithRemote, { name: "mcp__remote__exec_command" }).map(tool => tool.toolName)).toEqual(["mcp__remote__exec_command"]); }); - test("raw exec_command selects namespaced remote when no bare shell bridge exists", () => { + test("raw exec_command fails closed when no bare shell bridge exists", () => { const remoteOnly: OcxTool[] = [ { name: "exec_command", namespace: "mcp__remote", description: "Remote exec", parameters: {} }, ]; - expect(buildCursorToolDefinitions(remoteOnly, { name: "exec_command" }).map(tool => tool.toolName)).toEqual(["mcp__remote__exec_command"]); - expect(buildCursorToolDefinitions(remoteOnly, { mode: "required", allowedTools: ["exec_command"] }).map(tool => tool.toolName)).toEqual(["mcp__remote__exec_command"]); + expect(buildCursorToolDefinitions(remoteOnly, { name: "exec_command" }).map(tool => tool.toolName)).toEqual([]); + expect(buildCursorToolDefinitions(remoteOnly, { mode: "required", allowedTools: ["exec_command"] }).map(tool => tool.toolName)).toEqual([]); expect(buildCursorToolDefinitions(remoteOnly, { name: "mcp__remote__exec_command" }).map(tool => tool.toolName)).toEqual(["mcp__remote__exec_command"]); }); - test("raw shell_command selects namespaced remote when no bare shell bridge exists", () => { + test("raw shell_command fails closed when no bare shell bridge exists", () => { const remoteOnly: OcxTool[] = [ { name: "shell_command", namespace: "mcp__remote", description: "Remote shell", parameters: {} }, ]; - expect(buildCursorToolDefinitions(remoteOnly, { name: "shell_command" }).map(tool => tool.toolName)).toEqual(["mcp__remote__shell_command"]); - expect(buildCursorToolDefinitions(remoteOnly, { mode: "required", allowedTools: ["shell_command"] }).map(tool => tool.toolName)).toEqual(["mcp__remote__shell_command"]); + expect(buildCursorToolDefinitions(remoteOnly, { name: "shell_command" }).map(tool => tool.toolName)).toEqual([]); + expect(buildCursorToolDefinitions(remoteOnly, { mode: "required", allowedTools: ["shell_command"] }).map(tool => tool.toolName)).toEqual([]); + expect(buildCursorToolDefinitions(remoteOnly, { name: "mcp__remote__shell_command" }).map(tool => tool.toolName)).toEqual(["mcp__remote__shell_command"]); }); test("parser preserves parallel_tool_calls false for Cursor request enforcement", () => {