What it does
The `tools/call` method is sent by a client to invoke a named tool on the server. Before issuing the call, the client must have completed capability negotiation — both sides exchange `tools` capability blocks during `initialize`, and the server must have declared tool support. The client builds a request with `params.name` (the exact tool name from `tools/list`) and an optional `params.arguments` object. If the client wants progress notifications during a long-running tool, it attaches a `_meta.progressToken` to the params; the server then emits `notifications/progress` messages keyed on that token until the result is ready. \n\nOn receipt, the server validates `arguments` against the tool's `inputSchema`. A validation failure must NOT be raised as a JSON-RPC `-32602 Invalid params` error — instead the server should return a normal `CallToolResult` with `isError: true` and a human-readable explanation in the `content` array. This keeps the transport-level error channel clean and allows the LLM to read the failure message, self-correct its arguments, and retry. Only unrecoverable protocol-level failures (unknown method, malformed JSON) should surface as JSON-RPC errors. \n\nThe response is a `CallToolResult` containing a `content` array of typed blocks — `TextContent`, `ImageContent`, `AudioContent`, `EmbeddedResource`, or `ResourceLink` — and an optional `isError` boolean. Clients must render each block according to its `type`; they must not assume a plain string. If the tool involves a side effect that may take time (database writes, subprocess execution), the server should emit progress events and only resolve the JSON-RPC response once the side effect is complete, since MCP does not have a separate async-completion channel.
When to use
Whenever the LLM (or user) decides to run a tool.
When NOT to use
For reading data — use resources/read.
Notes
Capability gate before calling
A client must not call tools/call unless the server advertised a tools capability during initialize. If you call before capability confirmation you will receive a -32601 Method not found error. Always check the negotiated capabilities object before dispatching tool calls in early connection lifecycle code.
isError vs JSON-RPC errors
Use isError:true in CallToolResult for all tool-domain failures — bad arguments, runtime errors, timeouts, third-party API failures. Reserve JSON-RPC protocol errors (-32600, -32601, -32602, -32603) for genuine transport/protocol problems. Mixing the two breaks LLM self-correction loops: the model can read a text error inside CallToolResult and retry; it cannot recover from an unhandled JSON-RPC error object.
Progress tokens and ordering
Include _meta.progressToken only when the client is prepared to receive notifications/progress messages and knows the matching request ID. Tokens must be unique per in-flight call — reusing a token across concurrent tool calls makes progress attribution ambiguous. The server may send zero or many progress events before the final response; the final response always terminates the sequence regardless of whether 100% progress was signalled.
No pagination on responses
CallToolResult has no cursor or streaming mechanism. If a tool can produce large output, break it into ResourceLink blocks pointing to resources the client can fetch separately via resources/read, or truncate with a summary and expose a follow-up tool for pagination. Returning megabytes of text inline stalls the transport and bloats context.
Retry and idempotency
MCP provides no built-in retry for tools/call. Clients that retry on network failure risk duplicate side effects unless the tool's ToolAnnotations declares idempotentHint:true. For destructive or non-idempotent tools (idempotentHint:false or absent), clients should surface a confirmation to the user before retrying rather than silently re-issuing the call.
Request parameters
| Name | Type | Purpose |
|---|---|---|
| name | string | Tool name. |
| arguments | object? | Arguments matching the inputSchema. |
| _meta.progressToken | string | number? | For progress updates. |
Response fields
| Name | Type | Purpose |
|---|---|---|
| content | ContentBlock[] | Tool output. |
| isError | boolean? | True on tool-level failure. |
Examples
Calling a tool
{ "method": "tools/call", "params": { "name": "search", "arguments": { "q": "mcp" } } }
Common mistakes
❌ Returning -32602 for bad arguments
✅ Return CallToolResult with isError:true so the LLM can self-correct.