The short answer
All nine frameworks below give you a place to check or approve a tool call before it runs: the OpenAI Agents SDK, the Claude Agent SDK, the Vercel AI SDK, LangChain, CrewAI, Mastra, Pydantic AI, Google ADK and LlamaIndex. They fall into three shapes. Some run a hook that sees the arguments and can block. Some pause for approval and resume when a person answers. Some let a callback skip the tool and return a result in its place.
The differences that matter are in the small print: which tools a hook doesn’t see, whether a check runs before or after an approval, and whether a callback can be bypassed by an earlier rule. Each is sourced below to the framework’s own documentation, read on 26 October 2026.
Deedglass
A tool call meets your rules before it runs
Asks to run
DELETE FROM visits;
Deletes every row in visits
Deedglass checks your rules
- Reading dataAllowed
- Deleting a whole table (DROP, TRUNCATE)Never
- Changing or deleting rows without saying which (WHERE)This one
- Other changesWait for a person
The table
| Framework | Where to check a call | Can it block? | Built-in approval | Watch out for |
|---|---|---|---|---|
| OpenAI Agents SDK (Py) | tool_input_guardrails on a tool or local MCP server1 |
Yes: skip, replace output or tripwire1 | require_approval on MCP servers2 |
Skips hosted tools, ShellTool, handoffs1 |
| Claude Agent SDK | PreToolUse hook, then rules, mode, canUseTool10 |
Yes; a hook deny holds in every mode10 | canUseTool callback10 |
Calls approved earlier never reach canUseTool10 |
| Vercel AI SDK | toolApproval on generateText, streamText, ToolLoopAgent3 |
By withholding approval | Yes; needsApproval is deprecated3 |
Execution callbacks swallow errors3 |
| LangChain v1 | HumanInTheLoopMiddleware(interrupt_on=…)4 |
Reject, or edit the arguments4 | Yes | Needs a checkpointer4 |
| CrewAI | @on(InterceptionPoint.PRE_TOOL_CALL)5 |
Raise HookAborted5 |
Build it in the hook | Hooks are global unless scoped5 |
| Mastra | requireApproval on a tool, requireToolApproval per request6 |
By declining6 | Yes | Per-request flag pauses every call6 |
| Pydantic AI | Subclass WrapperToolset, override call_tool7 |
Yes, in your override | ApprovalRequiredToolset7 |
Run ends with deferred requests to resume7 |
| Google ADK | before_tool_callback(tool, args, tool_context)8 |
Return a dict to skip the tool8 | Build it in the callback | An empty dict also skips it (Python)8 |
| LlamaIndex | Inside the tool, with wait_for_event9 |
Yes, in your tool code | Events for asking a person9 | No pre-tool hook described9 |
Three shapes of check
Hooks that block. The OpenAI Agents SDK’s tool input guardrails, the Claude Agent SDK’s PreToolUse hook and CrewAI’s pre-tool-call hook all run before the tool and can stop it. They see the tool name and arguments, so they can enforce rules like “no SQL with DROP” or “email only to our domain”. This is the shape you want for rules.
Pauses for approval. The Vercel AI SDK, LangChain’s middleware, Mastra and Pydantic AI’s approval toolset stop the run and wait for a decision. They suit “a person must say yes” policies. Note how each resumes. The Vercel AI SDK doesn’t pause at all: generateText completes and returns tool-approval-request parts, and you continue by adding a tool-approval-response to the messages.3 LangChain needs a checkpointer to hold state across the interrupt.4 Pydantic AI ends the run with DeferredToolRequests and resumes with DeferredToolResults.7 If your app is a web server, each of these means storing state between requests.
Skip and return. Google ADK’s before_tool_callback either returns None, and the tool runs, or returns a dict, and the tool is skipped with the dict as its result.8 That is flexible, and it has a sharp edge: in Python an empty dict counts as an override, so a callback that returns {} by accident silently skips every tool.8
Framework notes
OpenAI Agents SDK. Tool guardrails don’t apply to handoffs, hosted tools such as HostedMCPTool and WebSearchTool, built-in execution tools such as ShellTool and ComputerTool, or Agent.as_tool().1 For a tool that needs approval, input guardrails normally run after approval; a config flag moves them before it.1 Our Agents SDK post goes deeper.
Claude Agent SDK. Checks run in a fixed order: hooks, deny rules, ask rules, permission mode, allow rules, then canUseTool.10 The docs warn that a call approved at an earlier step never reaches canUseTool, so checks placed there are silently bypassed for that tool, and they recommend a PreToolUse hook for checks that must run on every call.10 Also: allowed_tools doesn’t constrain bypassPermissions.10
Vercel AI SDK. onToolExecutionStart and onToolExecutionEnd run around each tool’s execute, but errors thrown inside them are silently caught.3 They are for observing, not blocking.
LangChain. interrupt_on maps tool names to allowed decisions: approve, edit, reject.4 Edit is useful: a reviewer can fix an argument instead of rejecting the call outright.
CrewAI. A blocked call doesn’t run, and the agent gets a “Tool execution blocked by hook” message. Hooks receive a mutable tool_input, so a hook can also rewrite arguments.5
Mastra. Approval is per tool or per request, and declining can carry a reason the model sees in place of the tool result.6
LlamaIndex. Its human-in-the-loop page describes events for asking a person, with the waiting done inside the tool, and no pre-tool hook.9 That puts the check in every tool’s code, which is easy to forget in one of them.
Gaps that repeat across frameworks
Three gaps show up again and again:
- Tools outside the hook’s pipeline. Hosted tools, shell tools and sub-agents often run on a different path. List every tool your agent has and check which pipeline it uses.
- Order relative to approval. If the rule check runs after approval, people approve calls that would have been refused. If it runs before and the call changes, the check is stale.
- Check by name, not by arguments. Several approval settings decide by tool name only. “Ask before
execute_sql” means asking aboutSELECT 1too, which trains people to click yes. A check on the arguments can ask only about writes.
How to choose a control
- For rules on arguments: a hook that blocks (OpenAI, Claude, CrewAI, ADK, a Pydantic AI wrapper).
- For a person’s yes: the framework’s approval pause, scoped to the tools that write.
- For both: run the rule first, then ask a person only about what the rule allows. Fewer prompts, and each one means something. The human-in-the-loop approval entry covers the patterns.
One gate for every framework
Every control above lives inside one framework, in one process. A team with two frameworks has two sets of rules to keep in step, and an agent built without them has none. A tool-call policy enforced outside the framework, between the agent and the systems it writes to, applies the same rules whatever built the agent.
That’s the approach we take with Deedglass. It ships recipes for all nine frameworks above, each a runnable file of 15 lines or fewer with pinned packages; no live model run backs them.11 Most hand the agent Deedglass’s MCP server, so calls meet the same policy and approvals in each framework. The same caveat applies as for in-framework hooks: a tool that doesn’t go through that path, such as a built-in shell, isn’t seen. For approvals on MCP calls specifically, see our approvals post, and for Claude Code’s own hook, the PreToolUse hook entry. To try the checks without installing anything, open the playground; to grade what an agent can reach on your own machine, run npx deedglass scan (the grade, explained).
Written with AI assistance and checked against our claims register.