From 31c795eae7c89e7bb863fc7a01c6c3dff857a883 Mon Sep 17 00:00:00 2001 From: cantalupo555 Date: Sat, 23 May 2026 07:38:11 -0300 Subject: [PATCH 1/2] fix(mcp): recommend direct mcp__* tool calls instead of mcptool CLI - Export MCP_TOOL_PREFIX constant - Update system message to instruct models to use direct MCP tool calls - Adjust corresponding test --- src/mcp/tool-bridge.ts | 4 +++- src/plugin.ts | 10 +++------- tests/unit/plugin-mcp-system-transform.test.ts | 8 ++++---- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/mcp/tool-bridge.ts b/src/mcp/tool-bridge.ts index 3d4f249..613f2ae 100644 --- a/src/mcp/tool-bridge.ts +++ b/src/mcp/tool-bridge.ts @@ -4,6 +4,8 @@ import type { McpClientManager } from "./client-manager.js"; const log = createLogger("mcp:tool-bridge"); +export const MCP_TOOL_PREFIX = "mcp__"; + interface DiscoveredMcpTool { name: string; serverName: string; @@ -79,7 +81,7 @@ export function buildMcpToolDefinitions(tools: DiscoveredMcpTool[]): any[] { function namespaceMcpTool(serverName: string, toolName: string): string { const sanitizedServer = serverName.replace(/[^a-zA-Z0-9]/g, "_"); const sanitizedTool = toolName.replace(/[^a-zA-Z0-9]/g, "_"); - return `mcp__${sanitizedServer}__${sanitizedTool}`; + return `${MCP_TOOL_PREFIX}${sanitizedServer}__${sanitizedTool}`; } function mcpSchemaToZod(inputSchema: Record | undefined, z: any): any { diff --git a/src/plugin.ts b/src/plugin.ts index 4a174bc..0ef2c7e 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -33,6 +33,7 @@ import { SkillResolver } from "./tools/skills/resolver.js"; import { autoRefreshModels } from "./models/sync.js"; import { readMcpConfigs, readSubagentNames } from "./mcp/config.js"; import { McpClientManager } from "./mcp/client-manager.js"; +import { MCP_TOOL_PREFIX } from "./mcp/tool-bridge.js"; import { buildMcpToolHookEntries, buildMcpToolDefinitions } from "./mcp/tool-bridge.js"; import { createOpencodeClient } from "@opencode-ai/sdk"; import { ToolRegistry as CoreRegistry } from "./tools/core/registry.js"; @@ -93,8 +94,8 @@ export function buildAvailableToolsSystemMessage( } const lines: string[] = [ - "MCP TOOLS — Use via Shell with the `mcptool` CLI.", - "Syntax: mcptool call [json-args]", + `MCP TOOLS — Use via direct tool calls (\`${MCP_TOOL_PREFIX}__\`).`, + "These tools are exposed as first-class tool calls (e.g. mcp__filesystem__read_file).", "", ]; @@ -104,11 +105,6 @@ export function buildAvailableToolsSystemMessage( const paramHint = t.params?.length ? ` (params: ${t.params.join(", ")})` : ""; lines.push(` - ${t.toolName}${paramHint}${t.description ? " — " + t.description : ""}`); } - if (tools.length > 0) { - const ex = tools[0]; - const exArgs = ex.params?.length ? ` '{"${ex.params[0]}":"..."}'` : ""; - lines.push(` Example: mcptool call ${server} ${ex.toolName}${exArgs}`); - } lines.push(""); } diff --git a/tests/unit/plugin-mcp-system-transform.test.ts b/tests/unit/plugin-mcp-system-transform.test.ts index 84e92df..cff0d97 100644 --- a/tests/unit/plugin-mcp-system-transform.test.ts +++ b/tests/unit/plugin-mcp-system-transform.test.ts @@ -12,7 +12,7 @@ describe("Plugin MCP system transform", () => { expect(systemMessage).toContain("skill_search -> search"); }); - it("includes mcptool Shell instructions when summaries provided", () => { + it("includes direct MCP tool call instructions when summaries provided", () => { const systemMessage = buildAvailableToolsSystemMessage( ["read", "write"], [], @@ -37,15 +37,15 @@ describe("Plugin MCP system transform", () => { ], ); - expect(systemMessage).toContain("mcptool call"); + expect(systemMessage).toContain("direct tool calls"); + expect(systemMessage).toContain("mcp__"); expect(systemMessage).toContain("hybrid-memory"); expect(systemMessage).toContain("memory_search"); expect(systemMessage).toContain("memory_stats"); expect(systemMessage).toContain("query, limit"); - expect(systemMessage).toContain("Shell"); }); - it("includes multiple servers in Shell instructions", () => { + it("includes multiple servers in MCP tool instructions", () => { const systemMessage = buildAvailableToolsSystemMessage( [], [], From 753500bac637431ebc73959e41647a7cadc528aa Mon Sep 17 00:00:00 2001 From: Nomadcxx Date: Sun, 24 May 2026 13:47:58 +1000 Subject: [PATCH 2/2] fix: show exact mcp tool names in prompt --- src/mcp/tool-bridge.ts | 2 +- src/plugin.ts | 29 +++++++++++++++---- .../unit/plugin-mcp-system-transform.test.ts | 26 +++++++++++++++++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/mcp/tool-bridge.ts b/src/mcp/tool-bridge.ts index 613f2ae..7529738 100644 --- a/src/mcp/tool-bridge.ts +++ b/src/mcp/tool-bridge.ts @@ -78,7 +78,7 @@ export function buildMcpToolDefinitions(tools: DiscoveredMcpTool[]): any[] { return defs; } -function namespaceMcpTool(serverName: string, toolName: string): string { +export function namespaceMcpTool(serverName: string, toolName: string): string { const sanitizedServer = serverName.replace(/[^a-zA-Z0-9]/g, "_"); const sanitizedTool = toolName.replace(/[^a-zA-Z0-9]/g, "_"); return `${MCP_TOOL_PREFIX}${sanitizedServer}__${sanitizedTool}`; diff --git a/src/plugin.ts b/src/plugin.ts index 0ef2c7e..4c99c2b 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -33,8 +33,12 @@ import { SkillResolver } from "./tools/skills/resolver.js"; import { autoRefreshModels } from "./models/sync.js"; import { readMcpConfigs, readSubagentNames } from "./mcp/config.js"; import { McpClientManager } from "./mcp/client-manager.js"; -import { MCP_TOOL_PREFIX } from "./mcp/tool-bridge.js"; -import { buildMcpToolHookEntries, buildMcpToolDefinitions } from "./mcp/tool-bridge.js"; +import { + MCP_TOOL_PREFIX, + buildMcpToolHookEntries, + buildMcpToolDefinitions, + namespaceMcpTool, +} from "./mcp/tool-bridge.js"; import { createOpencodeClient } from "@opencode-ai/sdk"; import { ToolRegistry as CoreRegistry } from "./tools/core/registry.js"; import { LocalExecutor } from "./tools/executors/local.js"; @@ -66,10 +70,16 @@ const log = createLogger("plugin"); interface McpToolSummary { serverName: string; toolName: string; + callName?: string; description?: string; params?: string[]; } +function getMcpToolDefinitionName(mcpToolDefs: any[], index: number): string | undefined { + const name = mcpToolDefs[index]?.function?.name; + return typeof name === "string" && name.length > 0 ? name : undefined; +} + export function buildAvailableToolsSystemMessage( lastToolNames: string[], lastToolMap: Array<{ id: string; name: string }>, @@ -86,8 +96,15 @@ export function buildAvailableToolsSystemMessage( } if (mcpToolSummaries && mcpToolSummaries.length > 0) { - const servers = new Map(); - for (const s of mcpToolSummaries) { + const summariesWithCallNames = mcpToolSummaries.map((summary, index) => ({ + ...summary, + callName: summary.callName + ?? getMcpToolDefinitionName(mcpToolDefs, index) + ?? namespaceMcpTool(summary.serverName, summary.toolName), + })); + + const servers = new Map>(); + for (const s of summariesWithCallNames) { const list = servers.get(s.serverName) ?? []; list.push(s); servers.set(s.serverName, list); @@ -103,7 +120,8 @@ export function buildAvailableToolsSystemMessage( lines.push(`Server: ${server}`); for (const t of tools) { const paramHint = t.params?.length ? ` (params: ${t.params.join(", ")})` : ""; - lines.push(` - ${t.toolName}${paramHint}${t.description ? " — " + t.description : ""}`); + const sourceHint = t.callName === t.toolName ? "" : ` (server: ${t.serverName}; tool: ${t.toolName})`; + lines.push(` - ${t.callName}${paramHint}${t.description ? " — " + t.description : ""}${sourceHint}`); } lines.push(""); } @@ -1873,6 +1891,7 @@ export const CursorPlugin: Plugin = async ({ $, directory, worktree, client, ser mcpToolSummaries = tools.map((t) => ({ serverName: t.serverName, toolName: t.name, + callName: namespaceMcpTool(t.serverName, t.name), description: t.description, params: t.inputSchema ? Object.keys((t.inputSchema as any).properties ?? {}) diff --git a/tests/unit/plugin-mcp-system-transform.test.ts b/tests/unit/plugin-mcp-system-transform.test.ts index cff0d97..4ac3c89 100644 --- a/tests/unit/plugin-mcp-system-transform.test.ts +++ b/tests/unit/plugin-mcp-system-transform.test.ts @@ -39,12 +39,38 @@ describe("Plugin MCP system transform", () => { expect(systemMessage).toContain("direct tool calls"); expect(systemMessage).toContain("mcp__"); + expect(systemMessage).toContain("mcp__hybrid_memory__memory_search"); expect(systemMessage).toContain("hybrid-memory"); expect(systemMessage).toContain("memory_search"); expect(systemMessage).toContain("memory_stats"); expect(systemMessage).toContain("query, limit"); }); + it("prints exact callable MCP tool names when server or tool names are sanitized", () => { + const systemMessage = buildAvailableToolsSystemMessage( + [], + [], + [ + { + type: "function", + function: { name: "mcp__test_filesystem__list_directory" }, + }, + ], + [ + { + serverName: "test-filesystem", + toolName: "list-directory", + description: "List dir", + params: ["path"], + }, + ], + ); + + expect(systemMessage).toContain("mcp__test_filesystem__list_directory"); + expect(systemMessage).toContain("server: test-filesystem"); + expect(systemMessage).toContain("tool: list-directory"); + }); + it("includes multiple servers in MCP tool instructions", () => { const systemMessage = buildAvailableToolsSystemMessage( [],