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.

Solutions

  1. Print Object.keys(server.getTools()) (or the server's convertedTools) and confirm the exact toolId spelling.
  2. Register the tool in the MCPServer `tools` option or recreate/restart the server so convertedTools includes it.
  3. Verify you are calling executeTool on the MCPServer instance that actually defines the tool.
  4. Check for casing/whitespace differences in the toolId.
  5. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/c9b5a8631fc71677. Report an issue: GitHub.

Appendix: 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)