Runtime tools let you define tools directly in dispatch requests, without saving them to your account first. This is useful for dynamic tool configurations, testing, and multi-tenant applications.
Runtime tools support the same types as saved tools:
Call any HTTP API:
Execute JavaScript in a secure sandbox:
Execute another Runtype flow as a tool:
Delegate a self-contained sub-task to a focused child agent. The child runs in its own context window — it cannot see the parent’s conversation — and returns only its final answer, which keeps the parent’s context clean for work that needs it. The child’s allowedTools are always intersected with the parent’s resolved tools, so a subagent can never use a tool the parent lacks.
To let an agent decide what to delegate at runtime, add a subagentConfig to its tools configuration. Runtype synthesizes a spawn_subagent tool the model can call, choosing the task, the tools to grant (from toolPool), and an optional system prompt:
The parent emits a single tool bubble per subagent call — the child’s internal turns and tool
calls do not leak into the parent’s stream. Each subagent call counts as one tool call against the
parent’s maxToolCalls, and the child’s cost rolls up into the parent’s total.
Use the secrets field for sensitive values:
Reference in tool config: {{secrets.api_token}}
Tool configurations support template variables:
Example:
Mix runtime tools with saved tools:
The TypeScript SDK provides helper functions:
Runtime tools (above) execute server-side — Runtype calls the URL, runs the
sandboxed code, or invokes the nested flow. Client tools are the opposite:
they execute in your own client (a browser page or your SDK process). You
declare them per-dispatch in the top-level clientTools[] field; when the model
calls one, Runtype pauses the run and streams an await event, you run the tool
locally, and you resume with the result.
Each entry has a name, description, parametersSchema, and an origin:
origin: 'sdk' — a tool your SDK process executes. Admitted automatically.origin: 'webmcp' — a tool registered by a browser page via WebMCP
(document.modelContext). On the API-key /v1/dispatch path the caller holds
a secret key and controls the page, so webmcp tools are admitted by
default — their presence in clientTools[] is the opt-in.Client tools merge into the model’s tool set with the precedence
saved < runtimeTools < clientTools, so a later turn can override a saved tool
of the same name without editing the flow.
The API-key /v1/dispatch examples below are the lower-level path. Prefer the
Persona widget for browser-embedded chat. Use direct dispatch when you are
building a non-Persona chat UI, running local tools from an SDK/native process,
or proxying browser tool calls through your own server that safely holds the
Runtype API key. Do not expose a Runtype API key in an untrusted browser page.
By default every submitted client tool is admitted. To narrow which
origin: 'webmcp' tools are accepted, pass an optional clientToolsPolicy with
an allowlist of glob patterns (an exact name, or a single trailing *).
SDK-origin tools are never gated by the allowlist.
Here only search_products is admitted; delete_account is dropped. Omit
clientToolsPolicy entirely to admit every webmcp tool.
clientToolsPolicy applies only to the raw API-key dispatch request. It is a
global self-restriction over bare tool names, not an origin-scoped surface
policy. Persona and other client-token chat surfaces use
behavior.webmcp.allowlist instead.
The examples above use the API-key /v1/dispatch path. Persona chat widgets use
the public client-token path (/v1/client/chat), so WebMCP admission is
controlled by the chat surface’s behavior.webmcp policy instead of only the
request payload.
On a Persona surface:
document.modelContext.registerTool(...).clientTools[] with origin: 'webmcp'.webmcp: prefix before the model sees the
tool.behavior.webmcp.enabled must be true, and any allowlist rules must match
the validated request origin and the bare tool name.allowedOrigins remains the enforced CORS boundary for
which browser origins may call the surface.The dashboard WebMCP tab shows page tools and origins observed on the chat surface over the trailing 7 days. You can promote a discovered tool into an origin-scoped allowlist rule from there.
The examples above use the API-key /v1/dispatch path, where you complete a
paused tool call by posting the result back to /v1/dispatch/resume. That route
requires a secret API key with DISPATCH:* scope, so a browser page (the
embedded Persona widget, or your own client-token integration) cannot use it.
Browsers authenticate with a client token (ct_live_…) against the
/v1/client/* routes instead. To complete a paused local-tool turn, resume via
/v1/client/resume — the session-authenticated sibling of
/v1/dispatch/resume:
sessionId is the session from /v1/client/init; it authenticates the
request (active session, active client token, matching Origin).executionId comes from the await event of the paused run. It scopes the
resume to your session’s user — a client token can only resume its own user’s
executions.toolOutputs is keyed by the per-call toolCallId from the await event
(preferred — this is what makes parallel calls of the same tool
addressable), or by tool name (legacy, single-call only).You do not re-send the clientTools[] definitions on resume; Runtype already
has them from the originating /v1/client/chat dispatch.
The Persona chat widget drives this /v1/client/resume round-trip for you when it runs in
client-token mode — you only implement the local tools themselves. The endpoint is documented here
for custom client-token integrations.
The API uses camelCase for all field names:
If you use the same runtime tool repeatedly, save it to your account via the API or dashboard for cleaner code.
Use lowercase header names (e.g., authorization not Authorization) to avoid issues with
automatic case conversion.
Use runtime tools to test configurations, then save working tools for production use.
Ensure parametersSchema is valid JSON Schema. Invalid schemas cause tool calls to fail.