From c53ce0bf503ac9387f0c98e2df7a3ea79f3c5a8d Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Tue, 25 Aug 2026 10:01:33 +0900 Subject: [PATCH] docs: clarify capability visibility and authorization --- docs/context.md | 10 ++++++++++ docs/handoffs.md | 2 ++ docs/tools.md | 6 +++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/context.md b/docs/context.md index fcd5e9034c..dca006c10b 100644 --- a/docs/context.md +++ b/docs/context.md @@ -29,6 +29,16 @@ You can use the context for things like: Within a single run, derived wrappers share the same underlying app context, approval state, and usage tracking. Nested [`Agent.as_tool()`][agents.agent.Agent.as_tool] runs may attach a different `tool_input`, but they do not get an isolated copy of your app state by default. +### Use local context for capability visibility + +When function tools, MCP tools, and handoffs depend on the same request policy, keep the policy inputs or helper on your application context. Each SDK surface exposes the current run context through its own callback: + +- [`FunctionTool.is_enabled`][agents.tool.FunctionTool.is_enabled] receives a `RunContextWrapper`. +- [`Handoff.is_enabled`][agents.handoffs.Handoff.is_enabled] receives a `RunContextWrapper`. +- An MCP [`tool_filter`](mcp.md#dynamic-tool-filtering) receives a [`ToolFilterContext`][agents.mcp.ToolFilterContext], whose `run_context` property contains the current `RunContextWrapper`. + +Adapt the shared application policy to these callbacks instead of maintaining separate capability lists. The callbacks control which capabilities the SDK exposes for the current run; they cannot authorize a model-generated argument or resource selection. For function tools, enforce those decisions inside the tool implementation or with [tool input guardrails](guardrails.md#tool-guardrails) and [approvals](human_in_the_loop.md) when appropriate. MCP servers must authorize their own protected operations. For a handoff with `input_type`, check the parsed input at the start of `on_handoff`, before application side effects, and raise instead of returning when authorization fails. Tool input guardrails do not run for handoffs. See [handoff inputs](handoffs.md#handoff-inputs) for the callback lifecycle. + ### What `RunContextWrapper` exposes [`RunContextWrapper`][agents.run_context.RunContextWrapper] is a wrapper around your app-defined context object. In practice you will most often use: diff --git a/docs/handoffs.md b/docs/handoffs.md index 093c9a1cdd..c33df9dd84 100644 --- a/docs/handoffs.md +++ b/docs/handoffs.md @@ -85,6 +85,8 @@ handoff_obj = handoff( `input_type` describes the arguments for the handoff tool call itself. The SDK exposes that schema to the model as the handoff tool's `parameters`, validates the returned JSON locally, and passes the parsed value to `on_handoff`. +`is_enabled` is evaluated while the SDK prepares the available handoffs, before the model returns handoff arguments, so it cannot authorize values inside an argument-bearing handoff. When authorization depends on the parsed fields, perform the check at the start of `on_handoff`, before any application side effects. If authorization fails, raise instead of returning; the SDK continues the transfer after `on_handoff` returns successfully. Tool input guardrails apply to function tools, not handoffs. + It does not replace the next agent's main input, and it does not choose a different destination. The [`handoff()`][agents.handoffs.handoff] helper still transfers to the specific agent you wrapped, and the receiving agent still sees the conversation history unless you change it with an [`input_filter`][agents.handoffs.Handoff.input_filter] or nested handoff history settings. `input_type` is also separate from [`RunContextWrapper.context`][agents.run_context.RunContextWrapper.context]. Use `input_type` for metadata the model decides at handoff time, not for application state or dependencies you already have locally. diff --git a/docs/tools.md b/docs/tools.md index 9f16e93846..d506b58c5f 100644 --- a/docs/tools.md +++ b/docs/tools.md @@ -833,11 +833,15 @@ The `is_enabled` parameter accepts: Disabled tools are completely hidden from the LLM at runtime, making this useful for: -- Feature gating based on user permissions +- Request-scoped capability visibility - Environment-specific tool availability (dev vs prod) - A/B testing different tool configurations - Dynamic tool filtering based on runtime state +For locally configured function tools, the runner also reevaluates `is_enabled` before invocation. However, `is_enabled` controls visibility and dispatch; it does not replace authorization that depends on the tool arguments or the resource being accessed. Enforce those checks inside the tool implementation, or use [tool input guardrails](guardrails.md#tool-guardrails) and [approvals](human_in_the_loop.md) when appropriate. MCP servers must authorize their own protected operations. + +See [context management](context.md#use-local-context-for-capability-visibility) for a pattern that applies one application policy across function tools, MCP tools, and handoffs. + ## Experimental: Codex tool The `codex_tool` wraps the Codex CLI so an agent can run workspace-scoped tasks (shell, file edits, MCP tools) during a tool call. This surface is experimental and may change.