Tool Call
Tool Call Flow
Client-side tool
Server-side tool (trusted, inline)
Server-side tool (permission required)
Unexposed server-side tools
The server may have internal tools that are not declared in GET /meta. The server may still stream tool_call and tool_result events for these tools so the client can observe them. Clients should be prepared to handle unknown tool names — either displaying them or discarding them.
Parallel tool calls
The server may emit multiple tool_call events before turn_stop. The client should handle all of them — execute client-side tools and respond to untrusted server tool permissions — then re-submit all results and permissions together in a single POST /sessions/:id/turns. Trusted server-side tools are handled inline by the server and do not require client action.
Example with two client-side tools, one trusted server tool, and one untrusted server tool — all called in parallel:
Tool call resolving
Server
After the LLM emits tool calls, the server resolves each one:
- For each
tool_call, check if it is a trusted server-side tool — if so, execute it inline immediately and emit atool_resultevent. - If any tool calls remain unexecuted, emit
turn_stopwithstopReason: "tool_use". - When the client re-submits, append the client-provided tool result messages to history.
- For each
tool_permissionin the submission, find the matchingtool_callbytoolCallId— execute the tool if granted, or store atoolmessage with a denial description (e.g."Tool call denied", or"Tool call denied: <reason>"if areasonwas provided) to inform the LLM.tool_permissionmessages are never appended to history — they are dropped after processing. - Append all
tool_resultevents to history and continue the agent loop.
Client
When the client receives turn_stop with stopReason: "tool_use":
- Collect all
tool_callevents from the current turn. - Ignore any whose
toolCallIdalready has a matchingtool_result— those were handled inline by the server. - For each remaining tool call, determine whether it is a client-side tool (by matching the name against tools declared in the request) or a server-side tool:
- Client-side tool: optionally prompt the user whether to proceed, then execute it and collect the result.
- Server-side tool: prompt the user or apply policy to grant or deny permission.
- Submit all results and permissions together in a single
POST /sessions/:id/turns.
Tool call resumption
If a client has no in-memory state (e.g. after a restart or recovery), it can call GET /sessions/:id/history to retrieve the session history and resume from where it left off:
- Fetch session history via
GET /sessions/:id/history. - Inspect the last assistant message in history — if it has unresolved tool calls (no matching
toolmessage in history), the last turn ended withstopReason: "tool_use"and requires client action. - Apply the same client-side resolving logic: identify client-side tools to execute and server-side tools requiring permission.
- Submit results and permissions via
POST /sessions/:id/turnsto continue.