Heuristic:Microsoft Agent framework Tool Approval Mode Production
| Knowledge Sources | |
|---|---|
| Domains | Security, AI_Agents |
| Last Updated | 2026-02-11 16:45 GMT |
Overview
Security best practice requiring `approval_mode="always_require"` on tool decorators in production to prevent unattended tool execution.
Description
The `@tool` decorator supports an `approval_mode` parameter that controls whether the framework requires human approval before executing a tool call. Samples use `approval_mode="never_require"` for brevity, but this is unsafe for production. In production, tools that perform side effects (API calls, database writes, file operations) must use `approval_mode="always_require"` so that a human reviews and approves each invocation before it executes.
Usage
Apply this heuristic whenever defining tools with the `@tool` decorator that will be deployed to production. Any tool that performs external actions, modifies data, or has irreversible consequences must require approval. Only read-only, side-effect-free tools (like weather lookups or data formatting) may safely use `"never_require"`.
The Insight (Rule of Thumb)
- Action: Set `approval_mode="always_require"` on the `@tool` decorator for all production tools with side effects.
- Value: `@tool(approval_mode="always_require")` for dangerous tools; `@tool(approval_mode="never_require")` only for safe, read-only tools.
- Trade-off: Requires human-in-the-loop approval for each tool call, which adds latency but prevents unintended actions.
Reasoning
AI agents can hallucinate tool calls or call tools with incorrect arguments. Without approval, a tool could execute harmful actions (deleting data, sending emails, making purchases) without human oversight. The framework's approval system provides a safety gate between the LLM's intent and actual execution. Every sample in the repository includes the comment:
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production
@tool(approval_mode="never_require")
def get_weather(city: str) -> str:
...
This pattern appears across 20+ sample files, indicating it is a deliberate framework-wide convention.
The approval workflow is handled via `AgentResponse.user_input_requests` which surfaces pending approvals, and `content.to_function_approval_response()` which sends the user's decision back to the agent.