diff --git a/apps/mcp/e2e/discovery.test.ts b/apps/mcp/e2e/discovery.test.ts index 66c503f2..c252105a 100644 --- a/apps/mcp/e2e/discovery.test.ts +++ b/apps/mcp/e2e/discovery.test.ts @@ -10,9 +10,13 @@ import { const EXPECTED_TOOLS = [ "add_memory", "fetch-graph-data", + "getDocument", "get_document", "get_profile", "guided-save", + "listDocuments", + "listMemories", + "listSpaces", "list_documents", "list_memories", "list_spaces", @@ -23,6 +27,7 @@ const EXPECTED_TOOLS = [ "select-space", "set-active-tag", "upload-file", + "whoAmI", "who_am_i", ] const describeWithAuth = describe.skipIf(!OAUTH_CREDENTIALS_AVAILABLE) diff --git a/apps/mcp/src/server/tools/index.ts b/apps/mcp/src/server/tools/index.ts index 232c3932..558b3fff 100644 --- a/apps/mcp/src/server/tools/index.ts +++ b/apps/mcp/src/server/tools/index.ts @@ -16,7 +16,46 @@ import type { ToolDeps } from "./types" import * as uploadFile from "./upload-file" import * as whoAmI from "./who-am-i" -export function registerAllTools(deps: ToolDeps) { +// Renamed to snake_case in #1665; clients with a cached tool list still call the old names. +// Remove once PostHog shows ~0 $mcp_tool_call events for these names for 2 weeks. +const LEGACY_TOOL_NAMES: Record = { + get_document: "getDocument", + list_spaces: "listSpaces", + list_documents: "listDocuments", + list_memories: "listMemories", + who_am_i: "whoAmI", +} + +type LooseRegisterTool = ( + name: string, + config: { title?: string; description?: string }, + cb: unknown, +) => ReturnType + +// Aliases must stay listed: ChatGPT rejects calls to tools missing from tools/list. +function withLegacyToolNames(server: ToolDeps["server"]): ToolDeps["server"] { + const register = server.registerTool.bind(server) as LooseRegisterTool + const registerTool: LooseRegisterTool = (name, config, cb) => { + const tool = register(name, config, cb) + const legacyName = LEGACY_TOOL_NAMES[name] + if (legacyName) { + register( + legacyName, + { + ...config, + ...(config.title ? { title: `${config.title} (deprecated)` } : {}), + description: `Deprecated: use ${name}.`, + }, + cb, + ) + } + return tool + } + return { registerTool: registerTool as ToolDeps["server"]["registerTool"] } +} + +export function registerAllTools(toolDeps: ToolDeps) { + const deps = { ...toolDeps, server: withLegacyToolNames(toolDeps.server) } searchMemory.register(deps) getProfile.register(deps) listDocuments.register(deps)