mastra-ai/mastra · error · Error
MCP_SERVER_TOOL_EXECUTE_PREPARATION_FAILED
MCP_SERVER_TOOL_EXECUTE_PREPARATION_FAILED
Error message
Unknown tool: ${toolId} What it means
MCPServer.executeTool() looks the tool up in this.convertedTools; if the toolId is not registered on this server it logs a warning and throws `Unknown tool: ${toolId}` (surfaced under code MCP_SERVER_TOOL_EXECUTE_PREPARATION_FAILED). This happens before any argument validation or execution, so the args are irrelevant — the tool name itself doesn't exist on this server instance.
Source
Thrown at packages/mcp/src/server/server.ts:2946
* const result = await server.executeTool(
* 'getWeather',
* { location: 'London' },
* { toolCallId: 'call_123' }
* );
* console.log(result);
* ```
*/
public async executeTool(
toolId: string,
args: any,
executionContext?: { messages?: any[]; toolCallId?: string; requestContext?: RequestContext },
): Promise<any> {
const tool = this.convertedTools[toolId];
let validatedArgs = args;
try {
if (!tool) {
this.logger.warn('Unknown tool requested', { tool: toolId, server: this.name });
throw new Error(`Unknown tool: ${toolId}`);
}
this.logger.debug('Invoking tool', { tool: toolId, args });
const paramsSchema = tool.parameters as {
validate?: (value: unknown) => any;
safeParse?: (value: unknown) => any;
};
const validation =
typeof paramsSchema?.validate === 'function'
? paramsSchema.validate(args ?? {})
: typeof paramsSchema?.safeParse === 'function'
? paramsSchema.safeParse(args ?? {})
: null;
if (validation) {
const success = typeof validation.success === 'boolean' ? validation.success : !validation.issues?.length;View on GitHub (pinned to 75dd419e61)
Solutions
- Print Object.keys(server.getTools()) (or the server's convertedTools) and confirm the exact toolId spelling.
- Register the tool in the MCPServer `tools` option or recreate/restart the server so convertedTools includes it.
- Verify you are calling executeTool on the MCPServer instance that actually defines the tool.
- Check for casing/whitespace differences in the toolId.
- If tools are added dynamically, re-create the server instance or re-run tool conversion so the registry is current.
Example fix
// before
await server.executeTool('getWeahter', { location: 'London' });
// after
const toolId = 'getWeather';
if (!(toolId in server.getTools())) throw new Error(`Tool ${toolId} not registered`);
await server.executeTool(toolId, { location: 'London' }); Defensive patterns
Strategy: validation
Validate before calling
const tools = server.getTools?.() ?? {};
if (!(toolId in tools)) {
throw new Error(`Tool '${toolId}' is not registered on MCP server; available: ${Object.keys(tools).join(', ')}`);
} Type guard
function isKnownTool(server: MCPServer, toolId: string): boolean {
return Object.prototype.hasOwnProperty.call(server.getTools?.() ?? {}, toolId);
} Try / catch
try {
return await server.executeTool(toolId, args, ctx);
} catch (e) {
if (e instanceof Error && e.message.startsWith('Unknown tool:')) {
logger.warn(`Tool ${toolId} missing on server ${server.name}; available: ${Object.keys(server.getTools()).join(',')}`);
return { error: 'TOOL_NOT_FOUND' };
}
throw e;
} Prevention
- Derive tool IDs dynamically from server.getTools() / tools/list instead of hardcoding strings.
- List tools via tools/list (or getTools) and surface the catalog to the LLM so it can't hallucinate names.
- After renaming or adding tools, recreate/restart the MCPServer so convertedTools is refreshed.
- Confirm the target MCPServer instance is the one that registers the tool when multiple servers exist.
- Validate toolId casing/whitespace in shared constants rather than ad-hoc literals.
When it happens
Trigger: Calling executeTool with a tool name that was never registered in the server's `tools` option; a typo or casing mismatch in the toolId; calling the tool on the wrong MCPServer instance; a tool registered after the server converted its tool list (stale convertedTools snapshot); an MCP client requesting a tool name from a different server's tool list.
Common situations: Renaming a tool and forgetting to update calling code; configuring multiple MCP servers and pointing the request at the wrong one; dynamically added tools that require server recreation; LLM hallucinating a tool name from a stale tools/list response; listing tools from a registry while executing against a different server.
Related errors
- MCP_CLIENT_ON_LIST_CHANGED_TOOLS_FAILED
- The "elicitation" key is now nested under "mcp.elicitation"
- The "extra" key is now nested under "mcp.extra" in tool argu
- Invalid structured content for tool ${request.params.name}:
- Prompt "${name}" not found
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/c9b5a8631fc71677.
Report an issue: GitHub.