tool-call-flow — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited tool-call-flow (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A tool-call flow is the multi-turn protocol by which a language model uses external capabilities. The four phases are stable:
| Phase | Who acts | Output | Becomes |
|---|---|---|---|
| 1. Declaration | Runtime/provider/SDK | Tool catalog, schemas, grammar constraints, or a discovery/search surface | Model input for the next turn |
| 2. Request | Model | Structured tool-call intent, programmatic code that calls allowed tools, UI action request, or final answer | Assistant/model output in the transcript |
| 3. Execution | Runtime/provider/MCP server/sandbox/UI harness | Result of invoking the capability after validation and policy checks | Tool result, function output, screenshot, code result, or provider-hosted observation |
| 4. Continuation | Runtime/provider/SDK | Result paired to the request by ID, plus provider-required continuity artifacts | Next model input; the cycle repeats |
The cycle ends when the model emits a turn without tool-call requests. The final message's content is the answer.
The cycle's defining property is the separation of planning from execution. The model produces structured intent; the runtime carries it out. This is not a workaround for model limitations. It is a deliberate design choice that makes the system auditable, composable, and recoverable.
This skill covers the protocol-level cycle by which a language model uses external capabilities: declaration, request, execution, continuation, ID pairing, model-visible state, vendor message shapes, strict schemas, grammar-constrained custom tools, MCP discovery and results, SDK-managed loops, hosted/server tools, tool search and deferred loading, programmatic tool calling, code execution with MCP, computer-use/browser-control loops, parallel and streaming tool calls, error encoding, untrusted tool output, runtime responsibilities, and the boundary between model-side intent and runtime-side execution.
It does not decide whether a tool should be called, which tool is optimal, or how many calls are cost-effective. That is tool-call-strategy. It does not design multi-agent orchestration, prompt wording, external APIs, or eval suites.
A tool-call flow is the smallest durable unit of agentic capability: one model turn asks for outside work, one runtime decides whether and how to execute it, and one continuation turn makes the result visible again. The important craft is keeping those responsibilities separate even when modern SDKs, hosted tools, MCP servers, computer-use loops, or provider-resumed interactions hide some mechanics.
The philosophy is therefore explicit serialization over magical control. The model should emit intent; the runtime should validate, authorize, execute, log, and encode the result; the next model turn should reason over the record it can actually see. A system that blurs those roles may feel easier in a demo, but it becomes harder to audit, replay, secure, and port between providers.
Vendor encoding can change, but these invariants do not:
| Invariant | What to check | Failure if broken |
|---|---|---|
| Tool declaration is model input | The model sees a bounded catalog with names, descriptions, and input contracts, or a discovery surface that can expose that catalog just in time. | The model invents unavailable tools or malformed arguments. |
| Tool request is structured intent | The model emits a typed block/item/action, not direct execution authority. | Runtime code treats free text as permission to act. |
| Runtime validates before execution | Tool name, arguments, grammar, authorization, idempotency, and side-effect policy are checked before dispatch. | Malformed, unauthorized, or destructive calls execute because the model asked. |
| Result is paired by ID | Every result carries the request ID: tool_use_id, tool_call_id, call_id, Gemini function-call id, or framework equivalent. | The continuation turn cannot prove which result belongs to which request. |
| Continuation preserves required output | The next request includes prior assistant tool-call output and provider-required reasoning, thinking, response, or interaction artifacts. | The provider rejects the request or the model loses the context needed to continue. |
| Tool output stays in a data channel | Results remain in tool-result/function-output/screenshot/result blocks and are treated as untrusted data. | Prompt injection inside retrieved content can be promoted into instructions. |
| Loop termination is explicit | Runtime caps steps and exits when the model emits a non-tool answer or hits a guardrail. | A model can re-call tools indefinitely. |
The old shorthand "message history is the only state" is useful only if read as model-visible state. The precise rule is:
A tool result influences the model only when the next turn includes it, or when the provider resumes an equivalent state through a documented continuation mechanism.
OpenAI Responses integrations preserve response.output items and return function_call_output items with the matching call_id; reasoning models also require reasoning items to be passed back with tool outputs. Gemini manual history must preserve function-call IDs, and Gemini thinking models may require thoughtSignature values to be passed back exactly. Gemini Interactions can continue through previous_interaction_id. Anthropic extended/structured tool flows may require preserving content blocks in a strict order. SDKs may hold runner state for you. None of that means the model has arbitrary hidden memory. It means the runtime must honor each provider's continuation contract.
The cycle is the same; the encoding differs.
Anthropic client tools use tool_use blocks inside assistant content and tool_result blocks inside the following user message. Pair results with tool_use_id. Tool-result blocks must immediately follow the corresponding assistant tool-use message in history, and inside the user message they come before any explanatory text.
{
"role": "assistant",
"content": [
{ "type": "text", "text": "I'll check the weather." },
{
"type": "tool_use",
"id": "toolu_01A",
"name": "get_weather",
"input": { "location": "Paris" }
}
]
}
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A",
"content": "{\"temp_c\":18,\"conditions\":\"cloudy\"}"
}
]
}Anthropic server tools are different in locus, not in concept: the provider executes the tool internally and incorporates the result without requiring the client to run the tool. The application still owns tool choice policy, approvals, observability, and trust boundaries.
OpenAI Responses represents tool requests as output items. Preserve the response output, execute each function_call, then append a function_call_output input item with the matching call_id. The function_call item's id is not the pairing key; call_id is.
// Model output item
{
"type": "function_call",
"id": "fc_123",
"call_id": "call_123",
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}
// Runtime continuation item
{
"type": "function_call_output",
"call_id": "call_123",
"output": "{\"temp_c\":18,\"conditions\":\"cloudy\"}"
}For reasoning models, pass back any reasoning items returned with tool calls along with the tool outputs. Treat them as provider-required continuity artifacts, not as normal user-visible text.
OpenAI Responses can declare custom tools whose input is text rather than a JSON object. A custom tool can use grammar constraints such as Lark or regex. The flow is still declaration, request, execution, continuation: the model emits a custom_tool_call with a call_id, the runtime validates/parses the text, executes only after policy checks, and returns the matching output.
{
"type": "custom",
"name": "timestamp",
"description": "Saves a timestamp in a strict textual format.",
"format": {
"type": "grammar",
"syntax": "regex",
"definition": "^(January|February|March)\\s+\\d{1,2}\\s+at\\s+\\d{1,2}(AM|PM)$"
}
}Do not collapse custom text tools into JSON-schema function tools. The runtime's validation contract changes from "parse JSON arguments" to "parse/check grammar-constrained text and then enforce the same authorization, approval, logging, and result-pairing policy."
Chat Completions encodes the same cycle with assistant tool_calls and role: "tool" result messages:
{
"role": "assistant",
"content": null,
"tool_calls": [{
"id": "call_abc",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Paris\"}"
}
}]
}
{
"role": "tool",
"tool_call_id": "call_abc",
"content": "{\"temp_c\":18,\"conditions\":\"cloudy\"}"
}This shape remains important for existing integrations and OpenAI-compatible APIs, but it is not the only OpenAI encoding.
Gemini generateContent uses function declarations and functionCall / functionResponse parts. Gemini 3 model APIs generate a unique id for each function call; when manually constructing history or using REST, pass the matching id back in the functionResponse. Gemini function-calling modes also distinguish AUTO, ANY, NONE, and VALIDATED; VALIDATED constrains schema-adherent calls while still allowing natural language where applicable.
{
"functionCall": {
"id": "gth23981",
"name": "get_weather",
"args": { "location": "Paris" }
}
}
{
"functionResponse": {
"name": "get_weather",
"id": "gth23981",
"response": {
"content": { "temp_c": 18, "conditions": "cloudy" }
}
}
}For thinking models, preserve thoughtSignature values when manually carrying history; SDKs may handle this automatically, but hand-rolled REST/history code must not drop them.
Gemini Interactions API beta changes the continuation surface without changing the concept. An Interaction records typed steps such as model thoughts, function_call, function_result, and final output. A later turn can continue through previous_interaction_id; current-turn tools, system instruction, and generation configuration are scoped to the interaction and must be specified as needed. Treat this as beta, version-gated provider-resumed state with storage and retention caveats, not as permanent hidden model memory.
MCP externalizes declaration and tool execution to a provider-neutral JSON-RPC layer:
tools/list on an MCP server.inputSchema and optional outputSchema.tools/call { name, arguments }.structuredContent, and isError.MCP's contribution is dynamic discovery, provider neutrality, output schemas, structured results, rich content types, and a standardized host/server boundary. It is not a different four-phase cycle.
MCP 2025-11-25 is the current stable spec as of this audit. It defines stdio and Streamable HTTP transports, tools/list, tools/call, structuredContent, outputSchema, and two error layers: JSON-RPC protocol errors versus tool execution errors with isError: true.
Tool-call flow is the same cycle even when execution moves.
| Execution locus | Who runs the tool | What the app still owns |
|---|---|---|
| Client/user-defined tool | Your runtime executes local code, service calls, or human workflows. | Validation, authorization, dispatch, result encoding, retries, loop caps, logs. |
| Provider-hosted/server tool | The model provider executes an approved hosted tool such as web search, code execution, file search, computer use, or hosted MCP. | Tool choice policy, approval settings, observability, output trust boundaries, returned artifacts, and data-retention fit. |
| MCP server tool | An MCP host/client discovers tools with tools/list, invokes tools/call, and translates results into the provider's format. | MCP transport/session security, server trust, tool approval, result shaping, and version pinning. |
| SDK-managed runner | An SDK wraps the loop and may execute tools, append results, and stop after configured iterations. | Correct definitions, approval gates, error policy, trace capture, max iterations, and knowing when to take over manually. |
| Programmatic sandbox | Generated code calls allowed tools, loops, filters, and distills intermediate results before returning a compact observation. | Sandbox isolation, allowed callers, egress limits, credential scope, provider resource limits, provenance, and validation of distilled output. |
| Computer-use/browser-control harness | The model returns screenshot-grounded UI actions; the harness clicks, types, scrolls, waits, drags, moves, or captures screenshots. | Isolated environment, action allowlist, coordinate mapping, screenshot/result feedback, high-impact approvals, prompt-injection handling, and trace capture. |
Large tool catalogs should not always be declared in full. Tool search/deferred loading is a declaration-phase sub-protocol: the model first sees a small search/discovery surface, uses it to retrieve relevant tool references, and only then receives or activates the full definitions for tools it can call.
| Pattern | Flow | Failure mode |
|---|---|---|
| Provider-hosted tool search | Mark functions/MCP servers as deferred; include tool_search; provider searches and loads a subset. | Deferring the search tool itself, hiding always-needed tools, or assuming discovery authorizes execution. |
| Client-executed tool search | Model emits a search call; your runtime performs BM25, semantic, regex, policy-filtered, filesystem, or tenant-specific lookup and returns definitions. | Returning untrusted or unauthorized tools, leaking private metadata, or bypassing approval gates. |
| MCP discovery | Host/client lists tools from MCP servers and shapes the provider-facing catalog just in time. | Treating discovery as trust, flooding context with every schema, or failing to cache/version definitions deliberately. |
| Code execution with MCP | Tool definitions are exposed as filesystem/code APIs inside a sandbox, so the model reads only the needed files and calls tools from code. | Confusing sandbox state with model-visible state, omitting sandbox policy, or letting intermediate data leak into logs. |
Deferred loading changes how declaration is populated. A discovered tool still needs a stable name, schema or grammar, request ID, validation, authorization, result pairing, and model-visible result formatting.
Programmatic tool calling is not a fifth phase. It moves part of execution into a code-execution environment where the model writes code that calls allowed tools, loops, filters, branches, and distills results before returning a smaller observation.
| Variant | What changes | What must remain explicit |
|---|---|---|
| Client-side direct execution | The application exposes functions to generated code and runs that code locally. | Safe arbitrary-code execution, callable allowlist, arguments, side effects, returned data, and logs. |
| Self-managed sandbox | Generated code runs in a restricted container and calls tools through an explicit bridge. | Isolation, egress policy, resource limits, IPC/tool-call protocol, credentials, audit logs, and result validation. |
| Provider-managed programmatic tool calling | Provider manages the sandbox and invocation channel for allowed tools. | Allowed-caller policy, tool restrictions, data retention, approval policy, trace capture, and returned artifacts. |
| Code execution with MCP | Code calls MCP tools or MCP-like adapters to avoid sending every intermediate result through model context. | MCP server trust, credential scope, sandbox-to-MCP permissions, explicit state handles, and final result shaping. |
For Anthropic's programmatic tool-calling surface, Claude writes Python code in a code-execution container. When code calls a user-defined tool, execution pauses and the API returns a tool_use block with caller/code-execution metadata; the client returns the tool result and code execution continues. Intermediate results are not loaded into Claude's context unless the code logs or returns them. Current PTC uses allowed_callers, a caller field on tool-use blocks, container IDs, and an expires_at deadline while awaiting tool results. allowed_callers guides invocation but is not a security boundary; clients must still handle and validate direct calls.
Provider resource limits are version-specific. Current Anthropic code-execution containers are documented with 5 GiB RAM, 5 GiB workspace storage, 1 CPU, no outbound network, workspace-scoped file access, 30-day maximum container lifetime, and cleanup after 4.5 minutes idle. PTC currently has feature restrictions: tools with strict: true are not supported with programmatic calling, direct tool_choice forcing cannot force a programmatic call, disable_parallel_tool_use is not supported with PTC, and MCP connector tools cannot be called programmatically.
The key distinction is context economy, not authority. PTC can reduce model round trips and token use because loops, joins, filtering, and data transformation happen in code. It does not authorize arbitrary execution or remove validation, approval, timeout, sandbox, provenance, and result-shaping duties.
Computer-use and browser-control tools are specialized tool-call flows for visual/UI environments. They do not make the model execute UI actions directly. The model observes a screenshot or UI state, emits action requests, the harness performs them, captures changed state, and returns a new screenshot/result.
| Element | Protocol meaning | Runtime duty |
|---|---|---|
| Screenshot/UI state | Model-visible observation grounding the next action. | Capture declared dimensions, redact sensitive regions when needed, preserve viewport/source provenance, and return fresh state after actions. |
| Action batch | Structured intent such as screenshot, click, double click, type, keypress, scroll, drag, mouse move, wait, or provider equivalent. | Execute only supported actions, in order, with timeout/resource limits and approval before sensitive or externally visible effects. |
| Coordinates | Arguments whose frame is the screenshot or declared display. | Keep display dimensions aligned with the actual image; handle downsampling, device-pixel-ratio, zoom, crop regions, and coordinate scaling. |
| Page/screen content | Tool output controlled by websites, apps, documents, emails, or images. | Treat on-screen instructions as untrusted data, not user permission; stop or ask before credentials, purchases, account changes, phishing, or other high-impact actions. |
| Continuation | New screenshot/result after action execution. | Pair it to the request (call_id, tool_use_id, or equivalent) and repeat until the model stops or a guardrail fires. |
Browser-control harnesses built with Playwright, Selenium, VNC, or MCP adapters are the same pattern with a different execution substrate. A DOM/API shortcut may be safer and more deterministic than UI actions, but the model-visible contract still needs observation, structured action intent, runtime execution, result feedback, and loop caps.
Tool schemas do two jobs: they teach the model the argument shape, and they let the runtime validate before execution. Strict modes strengthen the model-output side; they do not authorize the action.
type, required, enums where useful, bounded arrays/strings where possible, and clear descriptions for each argument.lark or regex) instead of JSON-schema arguments; validate by grammar parsing and execution policy.outputSchema and structuredContent; clients should validate structured results when an output schema is declared.const values, examples, or regex patterns. Schemas are often cached and logged differently from message content.Protocols allow multiple tool-call blocks/items in one assistant turn. Those calls are an unordered batch. The runtime may execute them concurrently, sequentially, or in any order, but the model cannot condition one call in the batch on another call's result. Dependent calls must be sequential across turns.
{
"role": "assistant",
"content": [
{ "type": "tool_use", "id": "toolu_01A", "name": "get_weather", "input": { "location": "Paris" } },
{ "type": "tool_use", "id": "toolu_01B", "name": "get_weather", "input": { "location": "Tokyo" } }
]
}If a batched call turns out to depend on another result and fails naturally, return that failure as an error result; the model can reissue the dependent call on the next turn. When using Anthropic-style parallel tool results, send the batch's tool-result blocks in one continuation message and place result blocks before any explanatory text. When deterministic ordering matters more than latency, disable parallel calls through the provider's controls where available.
Streaming changes when the runtime can observe a request, not the correctness contract. The safe rule is: aggregate argument deltas, parse and validate when the provider says the item/block is complete, then execute. Some providers expose fine-grained argument streaming where chunks arrive before server-side JSON buffering or validation; this reduces latency for large arguments but means clients must handle incomplete/invalid JSON and max_tokens cutoffs. Speculative execution is safe only when the call name, ID, and arguments are complete enough for the tool's idempotency and validation policy.
There are two failure layers:
| Failure layer | Examples | Handling |
|---|---|---|
| Tool execution failure | Business/API rejection, timeout, permission denied, schema-valid input fails domain validation, dependency missing, tool-specific error | Return a model-visible tool result with error content (is_error, isError, error object, or framework equivalent). The model can retry, choose another tool, ask the user, or stop. |
| Protocol/transport/request-shape failure | Malformed JSON-RPC, invalid message ordering, missing tool_call_id, wrong call_id, provider 400 from misplaced result blocks, lost MCP Streamable HTTP session, incompatible strict schema | Runtime handles, retries, or fails closed outside the model when needed. If the model can recover, summarize the problem into a valid continuation; otherwise log the trace and stop safely. |
The runtime should not throw raw exceptions into the conversation or let transport errors silently disappear. The design goal is model-visible recovery for errors the model can act on, and fail-closed runtime handling for errors it cannot repair.
Tool outputs often contain text controlled by web pages, files, emails, user uploads, API records, screenshots, or other external systems. Treat those bytes as data, not instructions.
system messages or unlabeled user text.The runtime is the orchestrator. It owns:
The model owns only planning: which tool, which arguments, and when to stop.
Current SDKs and providers automate more loop mechanics:
execute, strict mode, approval requests, multi-step stopping, and lifecycle callbacks.These displace boilerplate loop code in common cases. They do not displace the need to understand ID pairing, model-visible state, validation, authorization, approval, prompt-injection boundaries, loop caps, trace persistence, and when to take over manually.
Keep stable MCP guidance grounded in the implemented spec version. As of this audit, 2025-11-25 is the latest stable MCP spec; the 2026-07-28 release candidate is available but final publication is scheduled for July 28, 2026.
Version-gate these RC/draft points:
Mcp-Session-Id are removed in the RC direction; applications can still keep state through explicit model-visible handles such as basket_id or browser_id.initialize / notifications/initialized are removed; protocol version, client identity, and capabilities move into request _meta.server/discover becomes the up-front capability/version discovery RPC.Mcp-Method and Mcp-Name.ttlMs and cacheScope (public or private).-32002 to JSON-RPC -32602 (Invalid Params).Do not silently apply release-candidate behavior to stable deployments. Name the MCP version you implement.
After applying this skill, verify:
call_id, not the output item id.response.output, append function_call_output with the matching call_id, and preserve reasoning items for reasoning models.tool_result blocks immediately after the assistant tool_use message and put tool-result blocks first in the user content array.previous_interaction_id as beta provider-managed continuation, re-specify current-turn tools/system/config as needed, and account for storage/retention limits.outputSchema/structuredContent where present, and distinguish protocol errors from execution errors.| Instead of this skill | Use | Why |
|---|---|---|
| Deciding when to call a tool versus when to write a script | tool-call-strategy | Strategy owns the decision; flow owns the protocol that carries it out. |
| Choosing a multi-agent coordination pattern | agent-engineering | Agent engineering owns system architecture; tool-call-flow is one cycle inside one agent/runner. |
| Writing the natural-language description inside a tool declaration | prompt-craft | Prompt craft owns wording; this skill owns the structural contract. |
| Designing the JSON shape of an external API a tool wraps | api-design | API design owns the external service surface; this skill owns the model-facing tool contract. |
| Designing evals for tool-use correctness | eval-driven-development | Eval design owns measurement; this skill describes the behavior being measured. |
| Debugging a tool's domain result quality | debugging | Debugging owns the diagnostic activity; this skill owns protocol mechanics. |
function_call_output, call_id pairing, reasoning-item preservation, strict mode, Chat Completions, and custom grammar tools.tool_use / tool_result pairing, result placement, is_error, server-tool distinction, and untrusted result warning.allowed_callers, caller metadata, container expiration, and incompatibilities.tools/list, tools/call, structuredContent, outputSchema, isError, and protocol-vs-execution error split.stdio and Streamable HTTP transport guidance.previous_interaction_id, and function_result / call_id pairing.<!-- skill-graph-context:start (generated — do not edit by hand) -->
Classification
ai-engineeringtrueagent/protocolWhen to use
how does tool calling actually work, what message shape should a tool result have, Responses API vs Chat Completions tool calls, MCP vs function calling vs Anthropic tools, why do tool results need matching IDs, where do tool errors live in the history, what does an SDK tool runner automate, how should tool search deferred loading fit the flow, what is programmatic tool calling in the tool-use loop, how does computer use fit the tool-call loopNot for
Related skills
tool-call-strategyagent-engineering, api-design, type-safety, client-server-boundary, tool-call-strategyConcept
Grounding
universalhttps://developers.openai.com/api/docs/guides/function-calling, https://developers.openai.com/api/docs/guides/tools-tool-search, https://developers.openai.com/api/docs/guides/tools-computer-use, https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls, https://platform.claude.com/docs/en/agents-and-tools/tool-use/parallel-tool-use, https://platform.claude.com/docs/en/agents-and-tools/tool-use/fine-grained-tool-streaming, https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling, https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool, https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool, https://www.anthropic.com/engineering/code-execution-with-mcp, https://modelcontextprotocol.io/specification/2025-11-25/server/tools, https://modelcontextprotocol.io/specification/2025-11-25/basic/transports, https://modelcontextprotocol.io/specification/draft/changelog, https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/, https://ai.google.dev/gemini-api/docs/function-calling, https://ai.google.dev/gemini-api/docs/thought-signatures, https://ai.google.dev/gemini-api/docs/interactions/interactions-overview, https://ai.google.dev/gemini-api/docs/interactions/function-calling, https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-callingKeywords
tool call flow, tool use protocol, OpenAI Responses API, function calling, MCP tools, tool result IDs, strict schemas, deferred tool loading, programmatic tool calling, computer use<!-- skill-graph-context:end -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.