mastra-ai/mastra · error · Error

Tool '${toolId}' on remote MCP server '${this.name}' has no

Error message

Tool '${toolId}' on remote MCP server '${this.name}' has no execute method

What it means

After finding the tool on the remote MCP server, executeTool checks that it has an execute method before invoking it. If the tool descriptor returned by client.tools() lacks execute, this error is thrown, since the proxy cannot invoke a tool with no executable function.

Source

Thrown at packages/mcp/src/client/server-proxy.ts:153

    if (this._cachedToolList) {
      return this._cachedToolList.tools.find(t => t.id === toolId || t.name === toolId);
    }
    return this.fetchToolList().then(list => list.tools.find(t => t.id === toolId || t.name === toolId));
  }

  public async executeTool(
    toolId: string,
    args: any,
    _executionContext?: { messages?: any[]; toolCallId?: string },
  ): Promise<any> {
    const client = await this.getClient();
    const tools = await client.tools();
    const tool = tools[toolId];
    if (!tool) {
      throw new Error(`Tool '${toolId}' not found on remote MCP server '${this.name}'`);
    }
    if (!tool.execute) {
      throw new Error(`Tool '${toolId}' on remote MCP server '${this.name}' has no execute method`);
    }
    return tool.execute(args, _executionContext as any);
  }

  public async listResources(): Promise<{
    resources: Array<{
      uri: string;
      name: string;
      description?: string;
      mimeType?: string;
      _meta?: Record<string, unknown>;
    }>;
  }> {
    const client = await this.getClient();
    const resources = await client.resources.list();
    return {
      resources: resources.map((r: any) => ({
        uri: r.uri,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Inspect the raw tool descriptor from client.tools() and confirm the server implements the tool
  2. Upgrade the MCP server (or client) so descriptors match the expected Tool shape
  3. Invoke the tool directly via the underlying MCP client callTool if the server only supports raw protocol calls
  4. Report/fix the server-side tool registration so it includes execute

Example fix

// before
await proxy.executeTool('halfBakedTool', args); // descriptor lacks execute
// after
const tool = (await proxy.tools())['halfBakedTool'];
if (typeof tool?.execute === 'function') await proxy.executeTool('halfBakedTool', args);
else await client.callTool({ name: 'halfBakedTool', arguments: args });
Defensive patterns

Strategy: type-guard

Validate before calling

const tool = (await proxy.tools())[toolId];
if (tool && typeof tool.execute !== 'function') throw new Error(`Tool '${toolId}' has no execute method`);

Type guard

function isExecutableTool(t: unknown): t is { execute: (args: unknown, ctx: unknown) => Promise<unknown> } {
  return !!t && typeof (t as any).execute === 'function';
}

Try / catch

try {
  await proxy.executeTool(toolId, args);
} catch (e) {
  if (e instanceof Error && e.message.includes('has no execute method')) {
    console.error(`Remote server returned a non-executable descriptor for '${toolId}'; check server SDK version`);
  } else throw e;
}

Prevention

When it happens

Trigger: client.tools() returns a descriptor for toolId whose shape is missing execute — e.g. a malformed/older server response, a tool that is declared but not implemented, or an unexpected object type in the tools map.

Common situations: Remote MCP server returns non-standard tool descriptors; version mismatch between client SDK expectations and server tool schema; tools defined only as metadata (e.g. disabled or template tools).

Related errors


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