Skip to main content

Overview

call_tool is the HTTP transport’s primary execution verb. Where the stdio transport’s run tool composes multiple calls inside a TypeScript sandbox, call_tool invokes a single tool by path with structured arguments. One MCP call, one upstream call. Available only on the remote MCP endpoint (POST /api/mcp/:token). The CLI’s stdio surface uses run instead.

Input

ParameterTypeRequiredDescription
pathstringYesTool path (e.g. granola.personal.notes.list)
argumentsobjectNoTool arguments matching the tool’s inputSchema
Use search_tools to find a path and read_tool to see what arguments should contain.

Annotations

The MCP-level annotation on call_tool is non-destructive (it’s a meta tool), but the underlying tool may itself be destructive. Hosts should rely on the destructive field returned by read_tool to decide whether to require user confirmation before invoking.

Behavior

  1. Look up the handler by path. Returns Tool not found if the tool isn’t in the user’s filtered catalog (either it doesn’t exist or the user hasn’t connected the provider).
  2. Build a plugin context (userId, role, auth.getToken resolver, no-op elicitation, console logger).
  3. Pass arguments ?? {} through the SDK’s Zod input wrap — defaults from the tool’s inputSchema are applied here, so omitted fields take their declared default rather than undefined.
  4. Run the handler and stringify the result back as text/plain content.

Examples

// Search → read → call
{ "name": "search_tools", "arguments": { "query": "meeting notes" } }
// → returns granola.personal.notes.list (only if the user has the personal Granola key connected)

{ "name": "read_tool", "arguments": { "path": "granola.personal.notes.list" } }
// → returns inputSchema, outputSchema, destructive flag, authProvider

{ "name": "call_tool", "arguments": {
    "path": "granola.personal.notes.list",
    "arguments": { "limit": 5 }
} }
// → returns the user's 5 most recent meeting notes

Errors

If the handler throws, call_tool returns { isError: true, content: [{ type: "text", text: "Error: <message>" }] } so the agent gets a structured failure rather than a transport-level error. Common shapes:
  • Tool not found: <path> — typo or unconnected provider
  • No credentials for "<provider>". Connect it in the Toolshed dashboard.resolveToken() exhausted all three sources
  • Upstream API messages bubble through unchanged (e.g. Granola API error 401: Unauthorized)