Merge pull request #2193 from acamq/fix/load-mcp-hint

fix(skill_mcp): improve hint for builtin MCP names
This commit is contained in:
YeonGyu-Kim
2026-03-02 23:27:37 +09:00
committed by GitHub
3 changed files with 67 additions and 1 deletions

View File

@@ -0,0 +1,45 @@
import { describe, it, expect } from "bun:test"
import { SkillMcpManager } from "../../features/skill-mcp-manager"
import { createSkillMcpTool } from "./tools"
const mockContext = {
sessionID: "test-session",
messageID: "msg-1",
agent: "test-agent",
directory: "/test",
worktree: "/test",
abort: new AbortController().signal,
metadata: () => {},
ask: async () => {},
}
describe("skill_mcp builtin MCP hint", () => {
it("returns builtin hint for context7", async () => {
const tool = createSkillMcpTool({
manager: new SkillMcpManager(),
getLoadedSkills: () => [],
getSessionID: () => "session",
})
await expect(
tool.execute({ mcp_name: "context7", tool_name: "resolve-library-id" }, mockContext),
).rejects.toThrow(/builtin MCP/)
await expect(
tool.execute({ mcp_name: "context7", tool_name: "resolve-library-id" }, mockContext),
).rejects.toThrow(/context7_resolve-library-id/)
})
it("keeps skill-loading hint for unknown MCP names", async () => {
const tool = createSkillMcpTool({
manager: new SkillMcpManager(),
getLoadedSkills: () => [],
getSessionID: () => "session",
})
await expect(
tool.execute({ mcp_name: "unknown-mcp", tool_name: "x" }, mockContext),
).rejects.toThrow(/Load the skill first/)
})
})

View File

@@ -1,3 +1,9 @@
export const SKILL_MCP_TOOL_NAME = "skill_mcp"
export const SKILL_MCP_DESCRIPTION = `Invoke MCP server operations from skill-embedded MCPs. Requires mcp_name plus exactly one of: tool_name, resource_name, or prompt_name.`
export const BUILTIN_MCP_TOOL_HINTS: Record<string, string[]> = {
context7: ["context7_resolve-library-id", "context7_query-docs"],
websearch: ["websearch_web_search_exa"],
grep_app: ["grep_app_searchGitHub"],
}

View File

@@ -1,5 +1,5 @@
import { tool, type ToolDefinition } from "@opencode-ai/plugin"
import { SKILL_MCP_DESCRIPTION } from "./constants"
import { BUILTIN_MCP_TOOL_HINTS, SKILL_MCP_DESCRIPTION } from "./constants"
import type { SkillMcpArgs } from "./types"
import type { SkillMcpManager, SkillMcpClientInfo, SkillMcpServerContext } from "../../features/skill-mcp-manager"
import type { LoadedSkill } from "../../features/opencode-skill-loader/types"
@@ -71,6 +71,16 @@ function formatAvailableMcps(skills: LoadedSkill[]): string {
return mcps.length > 0 ? mcps.join("\n") : " (none found)"
}
function formatBuiltinMcpHint(mcpName: string): string | null {
const nativeTools = BUILTIN_MCP_TOOL_HINTS[mcpName]
if (!nativeTools) return null
return (
`"${mcpName}" is a builtin MCP, not a skill MCP.\n` +
`Use the native tools directly:\n` +
nativeTools.map((toolName) => ` - ${toolName}`).join("\n")
)
}
function parseArguments(argsJson: string | Record<string, unknown> | undefined): Record<string, unknown> {
if (!argsJson) return {}
if (typeof argsJson === "object" && argsJson !== null) {
@@ -132,6 +142,11 @@ export function createSkillMcpTool(options: SkillMcpToolOptions): ToolDefinition
const found = findMcpServer(args.mcp_name, skills)
if (!found) {
const builtinHint = formatBuiltinMcpHint(args.mcp_name)
if (builtinHint) {
throw new Error(builtinHint)
}
throw new Error(
`MCP server "${args.mcp_name}" not found.\n\n` +
`Available MCP servers in loaded skills:\n` +