thedotmack/claude-mem · error

Unknown tool: ${request.params.name}

Error message

Unknown tool: ${request.params.name}

What it means

Thrown by the CallToolRequest handler when no entry in the tools array matches request.params.name. The MCP server advertises a fixed tool list in ListTools; if a client calls a name not in that list, the lookup finds undefined and this Error is thrown before any handler runs.

Source

Thrown at src/servers/mcp-server.ts:913

  }
);

server.setRequestHandler(ListToolsRequestSchema, async () => {
  const advertisedTools = getAdvertisedMcpToolsForRuntime(tools, selectRuntime());
  return {
    tools: advertisedTools.map(tool => ({
      name: tool.name,
      description: tool.description,
      inputSchema: tool.inputSchema
    }))
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const tool = tools.find(t => t.name === request.params.name);

  if (!tool) {
    throw new Error(`Unknown tool: ${request.params.name}`);
  }

  try {
    return await tool.handler(request.params.arguments || {});
  } catch (error: unknown) {
    logger.error('SYSTEM', 'Tool execution failed', { tool: request.params.name }, error instanceof Error ? error : new Error(String(error)));
    return {
      content: [{
        type: 'text' as const,
        text: `Tool execution failed: ${error instanceof Error ? error.message : String(error)}`
      }],
      isError: true
    };
  }
});

const HEARTBEAT_INTERVAL_MS = 30_000;
let heartbeatTimer: ReturnType<typeof setInterval> | null = null;

View on GitHub (pinned to d768ba3643)

Solutions

  1. Re-list tools via tools/list and call only names that appear in the current response.
  2. Upgrade (or downgrade) the client and server to matching versions so advertised names align.
  3. Check the exact spelling and casing against the tools array in src/servers/mcp-server.ts.

Example fix

// before — client calls a non-existent tool
{ "method": "tools/call", "params": { "name": "remember", "arguments": {} } }
// throws 'Unknown tool: remember'

// after — use a name from tools/list
{ "method": "tools/call", "params": { "name": "observation_add", "arguments": { "content": "..." } } }
Defensive patterns

Strategy: validation

Validate before calling

// Before calling tools/call, confirm the name was advertised by tools/list.
const advertised = (await client.listTools()).tools.map(t => t.name);
if (!advertised.includes(requestedName)) {
  throw new Error(`Tool '${requestedName}' not advertised; available: ${advertised.join(', ')}`);
}

Type guard

function isAdvertisedTool(name: string, advertised: string[]): boolean {
  return advertised.includes(name);
}

Try / catch

try {
  await server.request({ method: 'tools/call', params: { name, arguments } });
} catch (e) {
  if (e instanceof Error && /Unknown tool/.test(e.message)) {
    // refresh the tool list and retry only if the name now exists
    await client.refreshTools();
  } else throw e;
}

Prevention

When it happens

Trigger: An MCP client sends tools/call with a name that is misspelled, removed in this version, or fabricated (e.g. 'memorize', 'remember'). Also when a client caches an older tool list after an upgrade that renamed/removed tools.

Common situations: Version skew: client discovered tools on an older server and calls a now-removed tool; typo in a hand-written JSON-RPC call; tool name was renamed (e.g. observation_add vs add_observation) and the caller uses the old spelling.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12). Data as JSON: /api/errors/a55496b07a61a089. Report an issue: GitHub.