diff --git a/packages/markdown-reader/README.md b/packages/markdown-reader/README.md index eacd7d0e..d81bc357 100644 --- a/packages/markdown-reader/README.md +++ b/packages/markdown-reader/README.md @@ -17,8 +17,8 @@ const { markdown, section } = await readSection({ file, section: "2.1" }); ## MCP tool names -- `markdown_reader__read` -- `markdown_reader__read_section` +- `read` +- `read_section` ## Standalone server invocation diff --git a/packages/markdown-reader/scripts/smoke-test.ts b/packages/markdown-reader/scripts/smoke-test.ts index 87edc103..876dcae1 100644 --- a/packages/markdown-reader/scripts/smoke-test.ts +++ b/packages/markdown-reader/scripts/smoke-test.ts @@ -21,7 +21,7 @@ async function run(): Promise { const { tools } = await client.listTools(); const names = tools.map((t) => t.name).sort(); - const expected = ["markdown_reader__read", "markdown_reader__read_section"]; + const expected = ["read", "read_section"]; const namesMatch = names.length === expected.length && expected.every((n, i) => names[i] === n); @@ -31,7 +31,7 @@ async function run(): Promise { console.log(`✓ tools/list — ${names.join(", ")}`); const result = await client.callTool({ - name: "markdown_reader__read", + name: "read", arguments: { file: "docs/plans/markdown-reader.md" }, }); @@ -39,7 +39,7 @@ async function run(): Promise { if (text?.type !== "text" || !text.text.includes("2.1")) { throw new Error(`tools/call response missing TOC: ${JSON.stringify(result)}`); } - console.log("✓ tools/call markdown_reader__read — TOC contains 2.1"); + console.log("✓ tools/call read — TOC contains 2.1"); } finally { await client.close(); } diff --git a/packages/markdown-reader/src/mcp/run.test.ts b/packages/markdown-reader/src/mcp/run.test.ts index 8c569dea..c6ed4ae9 100644 --- a/packages/markdown-reader/src/mcp/run.test.ts +++ b/packages/markdown-reader/src/mcp/run.test.ts @@ -28,7 +28,8 @@ describe("runMarkdownReaderMcp", () => { expect(runMCPMock).toHaveBeenCalledTimes(1); expect(runMCPMock).toHaveBeenCalledWith(markdownGroupMock, { name: "markdown-reader", - version: "0.0.1" + version: "0.0.1", + omitRootToolNamePrefix: true }); }); diff --git a/packages/markdown-reader/src/mcp/run.ts b/packages/markdown-reader/src/mcp/run.ts index a3af0592..7bc81886 100644 --- a/packages/markdown-reader/src/mcp/run.ts +++ b/packages/markdown-reader/src/mcp/run.ts @@ -5,6 +5,7 @@ import { markdownGroup } from "./group.js"; export async function runMarkdownReaderMcp(): Promise { await runMCP(markdownGroup, { name: "markdown-reader", - version: packageJson.version + version: packageJson.version, + omitRootToolNamePrefix: true }); } diff --git a/packages/markdown-reader/src/mcp/tools.test.ts b/packages/markdown-reader/src/mcp/tools.test.ts index acfc50db..e0bd88e7 100644 --- a/packages/markdown-reader/src/mcp/tools.test.ts +++ b/packages/markdown-reader/src/mcp/tools.test.ts @@ -4,17 +4,18 @@ import { McpClient, createSdkTestPair } from "tiny-mcp-client"; import { markdownGroup } from "./group.js"; const EXPECTED_TOOL_NAMES = [ - "markdown_reader__read", - "markdown_reader__read_section", - "markdown_reader__approvals__list", - "markdown_reader__approvals__show" + "read", + "read_section", + "approvals__list", + "approvals__show" ]; const FIXTURE_PATH = "packages/markdown-reader/src/testing/fixtures/with-frontmatter.md"; async function createClientPair() { const server = createMCPServer(markdownGroup, { name: "markdown-reader", - version: "0.0.1" + version: "0.0.1", + omitRootToolNamePrefix: true }); return createSdkTestPair(server, () => @@ -37,7 +38,7 @@ describe("markdown-reader MCP tools", () => { expect(tools.tools.map((tool) => tool.name)).toEqual(EXPECTED_TOOL_NAMES); const result = await client.callTool({ - name: "markdown_reader__read", + name: "read", arguments: { file: FIXTURE_PATH } diff --git a/packages/markdown-reader/src/testing/fixtures/markdown-reader-plan.md b/packages/markdown-reader/src/testing/fixtures/markdown-reader-plan.md index f27422d6..4da52840 100644 --- a/packages/markdown-reader/src/testing/fixtures/markdown-reader-plan.md +++ b/packages/markdown-reader/src/testing/fixtures/markdown-reader-plan.md @@ -152,10 +152,10 @@ Agent-side configuration example (Claude Code `~/.claude.json` or `.mcp.json`): } ``` -MCP tool names exposed by this server (derived by toolcraft from `group.name + command.name`): +MCP tool names exposed by this server (derived by toolcraft from command names with the root prefix omitted): -- `markdown_reader__read` — params `{ file, depth? }`. -- `markdown_reader__read_section` — params `{ file, section, includeChildren? }`. +- `read` — params `{ file, depth? }`. +- `read_section` — params `{ file, section, includeChildren? }`. ### Error cases users see @@ -184,7 +184,7 @@ const { markdown, section } = await readSection({ file, section: "2.1" }); - `src/core/read-markdown.ts`, `src/core/read-section.ts` — orchestrators used by both the SDK and MCP tool handlers. File I/O goes through an injectable `fs` so tests use `memfs`. - `src/mcp/tools.ts` — two `defineCommand` entries (`scope: ["mcp"]`) that wrap the orchestrators as MCP tools. - `src/mcp/group.ts` — `markdownGroup = defineGroup({ name: "markdown-reader", scope: ["mcp"], children: [readTool, readSectionTool] })`. - - `src/mcp/run.ts` — `runMarkdownReaderMcp()` → `runMCP(markdownGroup, { name: "markdown-reader", version })` from `toolcraft/mcp`. Mirrors [packages/terminal-pilot-mcp/src/index.ts](packages/terminal-pilot-mcp/src/index.ts). + - `src/mcp/run.ts` — `runMarkdownReaderMcp()` → `runMCP(markdownGroup, { name: "markdown-reader", version, omitRootToolNamePrefix: true })` from `toolcraft/mcp`. Mirrors [packages/terminal-pilot-mcp/src/index.ts](packages/terminal-pilot-mcp/src/index.ts). - `src/testing/fixtures/*.md` — static sample docs used by unit tests. - CLI wiring lives in [src/cli/commands/plan.ts](src/cli/commands/plan.ts). Three new commander subcommands under the existing `plan` group: - `plan markdown-read` — imports `readMarkdown` from `@poe-code/markdown-reader`, prints via the existing `writeOutput` + `resolveOutputOption` helpers in that file (`terminal` / `md` / `json`). @@ -334,7 +334,7 @@ export const markdownGroup = defineGroup({ // src/mcp/run.ts export async function runMarkdownReaderMcp(): Promise { - await runMCP(markdownGroup, { name: "markdown-reader", version: packageJson.version }); + await runMCP(markdownGroup, { name: "markdown-reader", version: packageJson.version, omitRootToolNamePrefix: true }); } ``` @@ -384,7 +384,7 @@ All tests are vitest, colocated, run under the package's `npm test` script that - `npm run dev -- plan markdown-read-section docs/plans/markdown-reader.md "Command: plan markdown-read"` returns the same body. - `npm run dev -- plan markdown-read missing.md` exits non-zero with a `UserError`-style message, not a stack trace. - `npm run dev -- plan --help` shows the three new subcommands. - - `npm run dev -- plan markdown-reader-mcp` passes an MCP handshake smoke test: an `initialize` request over stdio returns a capabilities payload, a `tools/list` request returns exactly `markdown_reader__read` and `markdown_reader__read_section`, and a `tools/call` on `markdown_reader__read` with `{ file: "docs/plans/markdown-reader.md" }` returns a TOC. Pattern to copy: [packages/terminal-pilot-mcp/scripts/smoke-test.ts](packages/terminal-pilot-mcp/scripts/smoke-test.ts). + - `npm run dev -- plan markdown-reader-mcp` passes an MCP handshake smoke test: an `initialize` request over stdio returns a capabilities payload, a `tools/list` request returns exactly `read` and `read_section`, and a `tools/call` on `read` with `{ file: "docs/plans/markdown-reader.md" }` returns a TOC. Pattern to copy: [packages/terminal-pilot-mcp/scripts/smoke-test.ts](packages/terminal-pilot-mcp/scripts/smoke-test.ts). - `npm run screenshot-poe-code -- plan markdown-read docs/plans/markdown-reader.md` — visually validate the terminal renderer once, attach to PR. - **Verification commands** (exact): `npm run build`, `npm test`, `npm run lint`, `npm run dev -- plan markdown-read docs/plans/markdown-reader.md`, `npm run dev -- plan markdown-read-section docs/plans/markdown-reader.md 2.1`, `npm run dev -- plan markdown-read-section docs/plans/markdown-reader.md 2.1 --no-include-children`, MCP smoke script against `npm run dev -- plan markdown-reader-mcp`. - **Fixtures / setup**: none external. All fixtures are in-repo markdown strings under `src/testing/fixtures/`. diff --git a/packages/terminal-pilot-mcp/src/index.ts b/packages/terminal-pilot-mcp/src/index.ts index a9fabe96..afa39e88 100644 --- a/packages/terminal-pilot-mcp/src/index.ts +++ b/packages/terminal-pilot-mcp/src/index.ts @@ -4,6 +4,7 @@ import { terminalPilotGroup } from "terminal-pilot/commands"; export async function main(): Promise { await runMCP(terminalPilotGroup, { name: "terminal-pilot", - version: "0.0.1" + version: "0.0.1", + omitRootToolNamePrefix: true }); } diff --git a/packages/terminal-pilot-mcp/src/mcp-server.test.ts b/packages/terminal-pilot-mcp/src/mcp-server.test.ts index 850d0bd3..8fc9ea32 100644 --- a/packages/terminal-pilot-mcp/src/mcp-server.test.ts +++ b/packages/terminal-pilot-mcp/src/mcp-server.test.ts @@ -28,7 +28,8 @@ describe("terminal-pilot-mcp entry point", () => { expect(runMCPMock).toHaveBeenCalledTimes(1); expect(runMCPMock).toHaveBeenCalledWith(terminalPilotGroupMock, { name: "terminal-pilot", - version: "0.0.1" + version: "0.0.1", + omitRootToolNamePrefix: true }); }); diff --git a/packages/terminal-pilot-mcp/src/mcp-tools.test.ts b/packages/terminal-pilot-mcp/src/mcp-tools.test.ts index 5a6d9ffd..15e2a1b4 100644 --- a/packages/terminal-pilot-mcp/src/mcp-tools.test.ts +++ b/packages/terminal-pilot-mcp/src/mcp-tools.test.ts @@ -5,21 +5,21 @@ import { terminalPilotGroup } from "terminal-pilot/commands"; import type { TerminalPilotRuntime } from "terminal-pilot/commands"; const EXPECTED_TOOL_NAMES = [ - "terminal_pilot__create_session", - "terminal_pilot__fill", - "terminal_pilot__type", - "terminal_pilot__press_key", - "terminal_pilot__send_signal", - "terminal_pilot__wait_for", - "terminal_pilot__wait_for_exit", - "terminal_pilot__read_screen", - "terminal_pilot__read_history", - "terminal_pilot__resize", - "terminal_pilot__close_session", - "terminal_pilot__get_session", - "terminal_pilot__list_sessions", - "terminal_pilot__approvals__list", - "terminal_pilot__approvals__show" + "create_session", + "fill", + "type", + "press_key", + "send_signal", + "wait_for", + "wait_for_exit", + "read_screen", + "read_history", + "resize", + "close_session", + "get_session", + "list_sessions", + "approvals__list", + "approvals__show" ]; const runtime: TerminalPilotRuntime = { @@ -102,6 +102,7 @@ describe("terminal-pilot-mcp tool surface", () => { const server = createMCPServer(terminalPilotGroup, { name: "terminal-pilot", version: "0.0.1", + omitRootToolNamePrefix: true, services: { terminalPilotRuntime: runtime } diff --git a/packages/toolcraft-openapi/src/define-client.test.ts b/packages/toolcraft-openapi/src/define-client.test.ts index 67e2ad4d..993a8367 100644 --- a/packages/toolcraft-openapi/src/define-client.test.ts +++ b/packages/toolcraft-openapi/src/define-client.test.ts @@ -123,6 +123,7 @@ describe("defineClient", () => { const server = createMCPServer(client.root, { name: client.name, version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client: mcpClient, cleanup } = await createClientPair(server); @@ -130,9 +131,9 @@ describe("defineClient", () => { const result = await mcpClient.listTools(); expect(result.tools.map((tool) => tool.name)).toEqual([ - "internal_agent__bots__list", - "internal_agent__approvals__list", - "internal_agent__approvals__show", + "bots__list", + "approvals__list", + "approvals__show", ]); } finally { await cleanup(); @@ -178,13 +179,14 @@ describe("defineClient", () => { const server = createMCPServer(client.root, { name: client.name, version: "1.0.0", + omitRootToolNamePrefix: true, services: client.services, }); const { client: mcpClient, cleanup } = await createClientPair(server); try { const tools = await mcpClient.listTools(); - const tool = tools.tools.find((candidate) => candidate.name === "internal_agent__bots__view"); + const tool = tools.tools.find((candidate) => candidate.name === "bots__view"); expect(tool).toMatchObject({ inputSchema: { @@ -202,7 +204,7 @@ describe("defineClient", () => { }); const result = await mcpClient.callTool({ - name: "internal_agent__bots__view", + name: "bots__view", arguments: { bot_handle: "my-bot", limit: 2, diff --git a/packages/toolcraft-openapi/src/runtime.test.ts b/packages/toolcraft-openapi/src/runtime.test.ts index 59b0ae37..a0d4d2c7 100644 --- a/packages/toolcraft-openapi/src/runtime.test.ts +++ b/packages/toolcraft-openapi/src/runtime.test.ts @@ -447,7 +447,8 @@ describe("commandsFromSpec", () => { }); const server = createMCPServer(client.root, { name: client.name, - version: "1.0.0" + version: "1.0.0", + omitRootToolNamePrefix: true }); const { client: mcpClient, cleanup } = await createClientPair(server); @@ -470,7 +471,7 @@ describe("commandsFromSpec", () => { expect(tools.tools).toContainEqual( expect.objectContaining({ - name: "internal_agent__bots__set_official_bot", + name: "bots__set_official_bot", inputSchema: expect.objectContaining({ required: ["bot_handle", "official"], properties: expect.objectContaining({ @@ -495,7 +496,8 @@ describe("commandsFromSpec", () => { }); const server = createMCPServer(client.root, { name: client.name, - version: "1.0.0" + version: "1.0.0", + omitRootToolNamePrefix: true }); const { client: mcpClient, cleanup } = await createClientPair(server); @@ -504,7 +506,7 @@ describe("commandsFromSpec", () => { expect(tools.tools).toContainEqual( expect.objectContaining({ - name: "internal_agent__campaigns__update_campaign", + name: "campaigns__update_campaign", inputSchema: expect.objectContaining({ additionalProperties: false, required: ["campaign_id", "name"] diff --git a/packages/toolcraft/README.md b/packages/toolcraft/README.md index cac98876..94a0b525 100644 --- a/packages/toolcraft/README.md +++ b/packages/toolcraft/README.md @@ -459,6 +459,7 @@ If you have an existing MCP server you want to keep running, use the MCP proxy: - `services?` / `humanInLoop?` / `apiVersion?` - `projectRoot?: string` — root used for MCP proxy cache files (`.toolcraft/mcp/*.json`). - `tools?: string[]` — allowlist of MCP tool names or group prefixes. Tool names are `__`-joined snake_case path segments (`root__bot__create`); a prefix like `root__bot` includes every descendant tool. +- `omitRootToolNamePrefix?: boolean` — defaults to `false`. Set to `true` to omit the root group name from single-root MCP tool names (`bot__create`). - `casing?: "snake" | "camel"` — affects MCP **input-schema property names** only. Tool names always stay `__`-joined snake_case. ### `HumanInLoopRuntimeOptions` diff --git a/packages/toolcraft/src/entrypoints-mcp-proxy.test.ts b/packages/toolcraft/src/entrypoints-mcp-proxy.test.ts index 673f08de..5eee02cb 100644 --- a/packages/toolcraft/src/entrypoints-mcp-proxy.test.ts +++ b/packages/toolcraft/src/entrypoints-mcp-proxy.test.ts @@ -267,13 +267,14 @@ describe("MCP proxy entrypoints", () => { await createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); expect(serverState.created).toHaveLength(1); expect(serverState.created[0]?.tools).toEqual([ - "root__github__create_issue", - "root__approvals__list", - "root__approvals__show", + "github__create_issue", + "approvals__list", + "approvals__show", ]); }); diff --git a/packages/toolcraft/src/human-in-loop/approvals-commands.test.ts b/packages/toolcraft/src/human-in-loop/approvals-commands.test.ts index e54cec28..4f2a7226 100644 --- a/packages/toolcraft/src/human-in-loop/approvals-commands.test.ts +++ b/packages/toolcraft/src/human-in-loop/approvals-commands.test.ts @@ -303,6 +303,7 @@ describe("approvals built-in commands", () => { { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, humanInLoop: { taskList, }, @@ -321,9 +322,9 @@ describe("approvals built-in commands", () => { const { tools } = await client.listTools(); const toolNames = tools.map((tool) => tool.name); - expect(toolNames).toContain("root__approvals__list"); - expect(toolNames).toContain("root__approvals__show"); - expect(toolNames).not.toContain("root__approvals__run"); + expect(toolNames).toContain("approvals__list"); + expect(toolNames).toContain("approvals__show"); + expect(toolNames).not.toContain("approvals__run"); } finally { await cleanup(); } diff --git a/packages/toolcraft/src/human-in-loop/mcp-runtime.integration.test.ts b/packages/toolcraft/src/human-in-loop/mcp-runtime.integration.test.ts index a0a3c64e..65e2644a 100644 --- a/packages/toolcraft/src/human-in-loop/mcp-runtime.integration.test.ts +++ b/packages/toolcraft/src/human-in-loop/mcp-runtime.integration.test.ts @@ -97,6 +97,7 @@ describe("human-in-loop MCP runtime", () => { const server = createMCPServer(createRoot("sync", handler), { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, humanInLoop: { provider, }, @@ -105,7 +106,7 @@ describe("human-in-loop MCP runtime", () => { try { const result = await client.callTool({ - name: "root__deploy__prod", + name: "deploy__prod", arguments: { target: "prod", }, @@ -137,6 +138,7 @@ describe("human-in-loop MCP runtime", () => { const server = createMCPServer(createRoot("sync", handler), { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, humanInLoop: { provider, }, @@ -145,7 +147,7 @@ describe("human-in-loop MCP runtime", () => { try { const result = await client.callTool({ - name: "root__deploy__prod", + name: "deploy__prod", arguments: { target: "prod", }, @@ -185,6 +187,7 @@ describe("human-in-loop MCP runtime", () => { const server = createMCPServer(createRoot("async", handler), { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, humanInLoop: { provider, taskList, @@ -198,7 +201,7 @@ describe("human-in-loop MCP runtime", () => { try { const result = await client.callTool({ - name: "root__deploy__prod", + name: "deploy__prod", arguments: { target: "prod", }, @@ -228,7 +231,7 @@ describe("human-in-loop MCP runtime", () => { }); const approvalResult = await client.callTool({ - name: "root__approvals__show", + name: "approvals__show", arguments: { approval_id: pending.approvalId, }, diff --git a/packages/toolcraft/src/mcp-proxy-integration.test.ts b/packages/toolcraft/src/mcp-proxy-integration.test.ts index 3e17082c..f891201a 100644 --- a/packages/toolcraft/src/mcp-proxy-integration.test.ts +++ b/packages/toolcraft/src/mcp-proxy-integration.test.ts @@ -903,6 +903,7 @@ describe("mcp proxy integration", () => { const server = createMCPServer(createProxyRoot(harness, { rename }).root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createSdkTestPair(server, () => new McpClient({ @@ -916,9 +917,9 @@ describe("mcp proxy integration", () => { try { const { tools } = await client.listTools(); - expect(tools.map((tool) => tool.name)).toContain("root__github__sub__renamed"); + expect(tools.map((tool) => tool.name)).toContain("github__sub__renamed"); const result = await client.callTool({ - name: "root__github__sub__renamed", + name: "github__sub__renamed", arguments: { text: "xyz" }, }); diff --git a/packages/toolcraft/src/mcp-runtime-options.test.ts b/packages/toolcraft/src/mcp-runtime-options.test.ts index 74b6b33c..32a82096 100644 --- a/packages/toolcraft/src/mcp-runtime-options.test.ts +++ b/packages/toolcraft/src/mcp-runtime-options.test.ts @@ -63,6 +63,7 @@ describe("createMCPServer human-in-loop runtime options plumbing", () => { { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, } ); const { client, cleanup } = await createClient(server); @@ -70,7 +71,7 @@ describe("createMCPServer human-in-loop runtime options plumbing", () => { try { await expect( client.callTool({ - name: "root__deploy", + name: "deploy", arguments: { target: "prod", }, diff --git a/packages/toolcraft/src/mcp.ts b/packages/toolcraft/src/mcp.ts index 15994695..b4f92770 100644 --- a/packages/toolcraft/src/mcp.ts +++ b/packages/toolcraft/src/mcp.ts @@ -62,6 +62,12 @@ export interface RunMCPOptions( root: Group, casing: Casing, - allowlist: string[] | undefined + allowlist: string[] | undefined, + omitRootToolNamePrefix: boolean ): ToolDefinition[] { const tools: ToolDefinition[] = []; @@ -323,7 +330,7 @@ function enumerateTools( } } - const rootPath = root.name.length === 0 ? [] : [root.name]; + const rootPath = omitRootToolNamePrefix || root.name.length === 0 ? [] : [root.name]; for (const child of root.children) { visit(child, rootPath, []); @@ -571,7 +578,7 @@ function createResolvedMCPServer); - const tools = enumerateTools(root, casing, options.tools); + const tools = enumerateTools(root, casing, options.tools, options.omitRootToolNamePrefix ?? false); const version = resolveMCPVersion(options.version); const server = createServer({ name: options.name, version }); diff --git a/packages/toolcraft/src/toolcraft.test.ts b/packages/toolcraft/src/toolcraft.test.ts index b601b918..9540e42d 100644 --- a/packages/toolcraft/src/toolcraft.test.ts +++ b/packages/toolcraft/src/toolcraft.test.ts @@ -784,6 +784,34 @@ describe("createMCPServer", () => { ); } + it("keeps the root group name in MCP tool names by default", async () => { + const root = defineGroup({ + name: "root", + children: [ + defineCommand({ + name: "deploy", + scope: ["mcp"], + params: S.Object({}), + handler: async () => "ok", + }), + ], + }); + + const server = createMCPServer(root, { + name: "toolcraft-test", + version: "1.0.0", + }); + const { client, cleanup } = await createClient(server); + + try { + const result = await client.listTools(); + + expect(result.tools.map((tool) => tool.name)).toContain("root__deploy"); + } finally { + await cleanup(); + } + }); + it("lists only mcp-scoped commands that match the allowlist and applies schema casing", async () => { const usage = defineCommand({ name: "usage", @@ -839,14 +867,15 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", - tools: ["root__usage", "root__bot"], + omitRootToolNamePrefix: true, + tools: ["usage", "bot"], }); const { client, cleanup } = await createClient(server); try { const result = await client.listTools(); - expect(result.tools.map((tool) => tool.name)).toEqual(["root__usage", "root__bot__create"]); + expect(result.tools.map((tool) => tool.name)).toEqual(["usage", "bot__create"]); expect(result.tools[0]?.inputSchema).toEqual({ type: "object", properties: { @@ -911,6 +940,7 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createClient(server); @@ -954,6 +984,7 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createClient(server); @@ -961,7 +992,7 @@ describe("createMCPServer", () => { const result = await client.listTools(); expect(result.tools).toHaveLength(3); - expect(result.tools[0]?.name).toBe("root__run"); + expect(result.tools[0]?.name).toBe("run"); expect(result.tools[0]?.inputSchema).toEqual({ type: "object", properties: { @@ -999,6 +1030,7 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createClient(server); @@ -1017,7 +1049,7 @@ describe("createMCPServer", () => { }); const callResult = await client.callTool({ - name: "root__run", + name: "run", arguments: { limit: null, }, @@ -1049,13 +1081,14 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createClient(server); try { await expect( client.callTool({ - name: "root__run", + name: "run", arguments: { count: 1.5, }, @@ -1092,6 +1125,7 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createClient(server); @@ -1155,7 +1189,8 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", - tools: ["root__bot_admin__bot"], + omitRootToolNamePrefix: true, + tools: ["bot_admin__bot"], casing: "camel", }); const { client, cleanup } = await createClient(server); @@ -1164,8 +1199,8 @@ describe("createMCPServer", () => { const result = await client.listTools(); expect(result.tools.map((tool) => tool.name)).toEqual([ - "root__bot_admin__bot__create_bot", - "root__bot_admin__bot__remove_bot", + "bot_admin__bot__create_bot", + "bot_admin__bot__remove_bot", ]); expect(result.tools[0]).toMatchObject({ description: "Create a bot Parameters: botName (required), botConfig.apiKey (required).", @@ -1300,12 +1335,13 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createClient(server); try { const callPromise = client.callTool({ - name: "root__deploy", + name: "deploy", arguments: {}, }); @@ -1343,11 +1379,12 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createClient(server); try { - await expect(client.callTool({ name: "root__deploy", arguments: {} })).rejects.toSatisfy((error: unknown) => { + await expect(client.callTool({ name: "deploy", arguments: {} })).rejects.toSatisfy((error: unknown) => { expect(error).toBeInstanceOf(McpError); expect(error).toMatchObject({ code: ERROR_INVALID_PARAMS, @@ -1378,12 +1415,13 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createClient(server); try { const callPromise = client.callTool({ - name: "root__deploy", + name: "deploy", arguments: {}, }); @@ -1409,6 +1447,7 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createClient(server); @@ -1466,13 +1505,14 @@ describe("createMCPServer", () => { services: { region: "us", }, + omitRootToolNamePrefix: true, casing: "camel", }); const { client, cleanup } = await createClient(server); try { const result = await client.callTool({ - name: "root__deploy", + name: "deploy", arguments: { botName: "demo", }, @@ -1515,12 +1555,13 @@ describe("createMCPServer", () => { const server = createMCPServer(root, { name: "toolcraft-test", version: "1.0.0", + omitRootToolNamePrefix: true, }); const { client, cleanup } = await createClient(server); try { const callPromise = client.callTool({ - name: "root__explode", + name: "explode", arguments: {}, });