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
- Use only search, context, or recent as the tool name.
- Re-fetch the tool list (ListToolsRequest) so the client reflects the current supported names.
- If you need a mutating operation, use the write surface (not the read-only recall MCP server).
- 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
- Always drive MCP tools from the server's ListTools response, not a hardcoded list.
- Keep client and server versions in sync to avoid schema/name skew.
- Remember the recall MCP server is read-only (search/context/recent).
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
- "${key}" is required
- observation_add: "content" is required
- observation_record_event: "eventType" is required
- observation_search: "query" is required
- observation_context: "query" is required
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/fff104eb67d7d28e.
Report an issue: GitHub.