thedotmack/claude-mem · error

Unknown tool: ${name}

Error message

Unknown tool: ${name}

What it means

Thrown by dispatchToolCall() in the recall MCP server when the requested tool `name` is not one of the supported read tools (search, context, recent). This is a read-only recall surface; mutating tools are intentionally absent. createRecallMcpServer converts this into an MCP error response.

Source

Thrown at src/server/mcp/recall-mcp-server.ts:133

    const observations = await backend.context({
      projectId: requireString(args, 'projectId'),
      query: requireString(args, 'query'),
      limit: clampLimit(args.limit, CONTEXT_LIMIT),
    });
    const context = observations
      .map((o) => (o as { content?: unknown }).content)
      .filter((t): t is string => typeof t === 'string' && t.length > 0)
      .join('\n\n');
    return jsonResult({ observations, context });
  }
  if (name === 'recent') {
    const observations = await backend.recent({
      projectId: requireString(args, 'projectId'),
      limit: clampLimit(args.limit, RECENT_LIMIT),
    });
    return jsonResult({ observations });
  }
  throw new Error(`Unknown tool: ${name}`);
}

/**
 * Build a read-only recall MCP server bound to `backend`. The caller owns the
 * transport (stdio in the CLI, streamable-HTTP in Server Beta).
 */
export function createRecallMcpServer(backend: RecallBackend, version: string): Server {
  const server = new Server(
    { name: 'claude-mem', version },
    { capabilities: { tools: {} } },
  );

  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));

  server.setRequestHandler(CallToolRequestSchema, async (request): Promise<CallToolResult> => {
    const name = request.params.name;
    const args = (request.params.arguments ?? {}) as Record<string, unknown>;
    try {

View on GitHub (pinned to d768ba3643)

Solutions

  1. Use only search, context, or recent as the tool name.
  2. Re-fetch the tool list (ListToolsRequest) so the client reflects the current supported names.
  3. If you need a mutating operation, use the write surface (not the read-only recall MCP server).
  4. Check for typos/casing in the tool name.

Example fix

// before: hallucinated tool name -> "Unknown tool: write"
client.callTool({ name: 'write', arguments: {...} });
// after: use a supported read tool
client.callTool({ name: 'search', arguments: { projectId: 'p1', query: 'auth' } });
Defensive patterns

Strategy: type-guard

Validate before calling

const RECALL_TOOLS = new Set(['search', 'context', 'recent']);
function isKnownRecallTool(name: string): boolean {
  return RECALL_TOOLS.has(name);
}
// before calling: if (!isKnownRecallTool(name)) surface a clear client error

Type guard

function isRecallToolName(name: string): name is 'search' | 'context' | 'recent' {
  return name === 'search' || name === 'context' || name === 'recent';
}

Try / catch

try {
  result = await dispatchToolCall(backend, name, args);
} catch (error) {
  if (/Unknown tool/.test((error as Error).message)) {
    // refresh the client's tool list (ListTools) and retry with a valid name
    return makeMcpError(`Unknown tool: ${name}. Available: search, context, recent`);
  }
  throw error;
}

Prevention

When it happens

Trigger: An MCP client invokes a tool name outside {search, context, recent}; a client cached an older/newer tool list that included a renamed or removed tool; a typo in the tool name; an attempt to call a write tool over the read-only recall endpoint.

Common situations: Client and server are version-skewed on the tool list. An LLM client invents a tool name. A user expects a `write`/`add` tool on the recall surface.

Related errors


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