How do agent frameworks differ on security?
Agent frameworks differ on which hook can still refuse a side effect before it happens. Eve, Mastra, Claude Agent SDK, OpenAI Agents SDK, LangGraph JS, and LangChain Python each expose a different inbound path, a different way to deny an authored tool, and a different answer for MCP and other tools that you didn't write. Eve, Mastra, Claude Agent SDK, and LangGraph JS can deny tools that you didn't wrap. LangChain Python denies only the tools that you name in a ToolPolicy, and on OpenAI Agents SDK, hosted tools, MCP, and handoffs aren't Arcjet deny points. If your agent relies on MCP or built-in tools, choose one of the first four frameworks or plan a separate control for those paths. Arcjet ships first-party adapters for 15 frameworks, including all six, so one centrally managed policy decides in code, in the path of the tool call, with no proxy to route traffic through.
Arcjet publishes this comparison. Framework details come from each framework's public documentation and from the Arcjet framework integrations documentation, reviewed on September 25, 2026.
The agent framework security page is the series hub, and each column in its table is a job: screening inbound text, denying an authored tool, denying an unwrapped or MCP tool, and the human-in-the-loop (HITL) trap. The dedicated How-tos name the helper for each host. For the vendor-layer map, see AI agent security platforms.
A helper name that works on one framework often doesn't exist on the next, so a team that copies the last repository's helper into a new one can end up with a check that never runs. guardInbound exists on Eve but not on OpenAI Agents or LangGraph, and guardHooks exists on Mastra and Claude Agent SDK but not on LangGraph. Compare frameworks by the job each hook does rather than by the identifier.
Coding agents don't need a framework adapter. For Claude Code, GitHub Copilot, Cursor, OpenAI Codex, and Muse Code, Arcjet enforces the same kind of policy through the hooks each agent already fires, installed through managed settings. For more information, see how to secure AI coding agents.
What does each stack deny?
Each framework can refuse work for a job only if it exposes a hook for that job, and the following table names the Arcjet helper for each hook on six stacks. An entry of "None" in the MCP column means the Arcjet adapter has no deny point for tools that you didn't write.
| Stack | Inbound screen | Authored-tool deny | Unwrapped / MCP deny | HITL trap |
|---|---|---|---|---|
| Eve |
|
|
| onAllow: "user-approval" |
| Mastra |
|
|
| requireApproval |
| Claude Agent SDK |
|
|
|
|
| OpenAI Agents SDK | A direct |
| None. Hosted tools, MCP, handoffs, and agents used as tools aren't Arcjet deny points |
|
| LangGraph JS | A direct |
|
| interrupt() |
| LangChain Python | An application |
| Only the tools that you name in a | A human callback that you add. |
On OpenAI Agents, the SDK's own tool guardrails can attach to local MCP servers through toolInputGuardrails in the server options, according to the OpenAI Agents SDK guardrails guide. Those are OpenAI tripwires that you write yourself rather than Arcjet policy, and the same guide says hosted MCP tools, other hosted tools, and handoffs don't use that pipeline. For more information about that split, see OpenAI Agents guardrails vs Arcjet.
LangChain in JavaScript has its own adapter. guardTool wraps an authored tool, and guardMiddleware on wrapToolCall gates every model-selected tool call, including tools that you didn't wrap.
The Vercel AI SDK adapter combines guardTool with createAgentContext and aiToolsContext, and it has no separate inbound hook. For more information about that wrapper, see How do I secure a Vercel AI SDK agent?.
The same action-selected policy model covers eight other first-party adapters:
- TanStack AI:
guardMiddlewareononBeforeToolCall. - Google ADK:
guardPluginonbeforeToolCallbackin JavaScript, andguard_toolonbefore_tool_callbackorguard_pluginon Runnerpluginsin Python. - Cloudflare Think:
guardHooksonbeforeToolCall. - Claude Managed Agents:
guardEventsbeforeevents.send, andguardCustomToolon custom tools. Anthropic runs the built-in tools, so they have already run by the time your code sees the event. - CrewAI:
register_arcjet_hooksonPRE_TOOL_CALL. - Genkit:
guardToolon aToolAction, andguardMiddlewareon thetoolhook. - Strands Agents:
guardToolon an authored tool, andguardHooksonBeforeToolCallEvent. - Microsoft Agent Framework in Go:
GuardToolandGuardToolson atool.FuncTool, andGuardMiddlewareonagent.Config.Middlewares.
For the full matrix, including import paths, see framework integrations.
What is the HITL trap on each stack?
Human-in-the-loop controls pause a call so that a person can approve it, but they don't evaluate a policy, and a run that nobody is watching stalls. Eve user-approval, Mastra requireApproval, and Claude canUseTool are covered in Human approval is not a security policy. OpenAI needsApproval, hosted MCP approval, and LangGraph interrupt() are covered in needsApproval and LangGraph interrupt() are not a security policy.
On Claude Agent SDK, the gap is concrete. The Claude Agent SDK permissions documentation states that a call approved by an allow rule or a permission mode skips the canUseTool callback, and recommends a PreToolUse hook for checks that must run on every tool call.
A reviewer who approves a run of lookups and one refund has also approved whatever the next call sends, and by then the model has already read the prompt. Screen inbound text first, deny the tool or connection before the framework calls it, and then reserve a human pause for the few irreversible actions that a policy allows.
What happens on each stack when Guard is unavailable?
Every framework wrapper fails closed when the policy can't be evaluated, but each stack reports that differently, and the shape decides what your error handling looks like. A denial means that the policy refused the call. An unavailable result means that the check didn't complete.
On the Vercel AI SDK, the tool doesn't execute and the model receives a retryable denial result with reason ERROR. LangChain Python separates the two cases by exception type: guard_tool raises ArcjetToolUnavailableError rather than ArcjetToolDeniedError, while guard_action and ArcjetMiddleware raise ArcjetUnavailableError rather than ArcjetDeniedError. CrewAI's register_arcjet_hooks raises the same HookAborted for a denial and for unavailability.
Eve, Mastra, Claude Agent SDK, LangGraph, and OpenAI Agents helpers all default to onGuardError: "deny". The OpenAI Agents guardTool returns a plain ArcjetDenialResult and doesn't throw, so the denial arrives in the tool output rather than as an error.
Inbound screening is the one place where "allow" is often defensible, because failing closed on a user's first message stops the agent answering at all during an outage. Set it deliberately for each call site, and never on a tool that sends data outward. A direct guard() call behaves differently again: it fails open and reports that on hasFailedOpen(), so an inbound screen that only checks for DENY still starts the agent during an outage.
Which Learning Center guide do I read for each framework?
Start with the security guide for the framework that you ship, then read the inbound or unwrapped-tool recipe if you need a single surface:
- Eve: Vercel Eve security guide, then How to detect prompt injection in an Eve agent and How to secure Eve MCP connections.
- Mastra: Mastra security guide, then How to secure a Mastra agent and How to secure Mastra MCP tools.
- Claude Agent SDK: Claude Agent SDK security guide, then How to screen inbound prompts in Claude Agent SDK and How to block Bash in Claude Agent SDK.
- OpenAI Agents: OpenAI Agents security guide, then How do I screen inbound prompts in OpenAI Agents SDK?.
- LangGraph: LangGraph security guide, then How do I secure MCP tools in LangGraph?.
- LangChain: LangChain security guide, then How do I secure a LangChain Python agent?.
- Vercel AI SDK: Vercel AI SDK security guide.
- Other adapters: TanStack AI, Google ADK, Cloudflare Think, Claude Managed Agents, CrewAI, Genkit, Strands Agents, and Microsoft Agent Framework.
How do I pick a starting check?
If the framework has a channel or prompt-submit hook, screen that text before the turn starts. If you wrote the tool, wrap it. If the framework invokes MCP or a built-in tool that you didn't write, use that framework's unwrapped deny, and on OpenAI Agents plan for those paths to stay outside an Arcjet deny.
Use protect() on HTTP routes and guard() on tools, MCP handlers, and any path with no Request object. Don't construct a fake Request to reach protect() from a tool. Bot detection and Shield are HTTP rules, so they run on protect() only. A direct guard() call fails open, while the framework wrappers default to deny.
OpenAI Agents inputGuardrails are SDK tripwires rather than Arcjet checks. For more information about that split, see OpenAI Agents guardrails vs Arcjet. For more information about the two first-party SDKs, see OpenAI Agents SDK vs Claude Agent SDK. Adapter documentation lives under framework integrations.
Frequently asked questions
How do agent frameworks differ on security?
Agent frameworks differ on which hook can still refuse a side effect. Eve, Mastra, Claude Agent SDK, OpenAI Agents SDK, LangGraph JS, and LangChain Python each expose a different inbound path, a different way to deny an authored tool, and a different answer for MCP and other tools that you didn't write. Arcjet ships a first-party adapter for each of them.
Which frameworks can deny MCP or unwrapped tools?
With Arcjet, Eve uses guardApproval on the connection, Mastra uses guardHooks on beforeToolCall, Claude Agent SDK uses PreToolUse, and LangGraph JS uses guardToolNode. LangChain Python denies only the tools that you name in a ToolPolicy. On OpenAI Agents, hosted tools, MCP, and handoffs aren't Arcjet deny points.
Is human approval a security policy on any of these frameworks?
No. Eve user-approval, Mastra requireApproval, Claude canUseTool, OpenAI needsApproval, hosted MCP approval, and LangGraph interrupt() pause a call for a person. None of them evaluates a policy, and a run that nobody is watching stalls. Screen inbound text and deny the tool or connection first, then reserve a human pause for the few irreversible actions that a policy allows.
Where do I start on the framework I ship?
Start with the Learning Center security guide for the framework that you ship, then read its inbound or unwrapped-tool recipe if you need a single surface. For example, on Claude Agent SDK, read the security guide first, then the guides on screening inbound prompts and blocking Bash. The agent framework security page links each dedicated guide.
Does Arcjet detect bots on these agent paths?
No. Bot detection and Shield are HTTP rules that run on protect(), so they apply to HTTP routes rather than to tool calls. Use guard() for tools, MCP handlers, and paths with no Request object, and don't construct a fake Request inside a tool to reach protect().
What happens when Arcjet is unavailable on each framework?
Every framework wrapper fails closed by default with onGuardError: "deny", but each stack reports unavailability differently. The Vercel AI SDK returns a retryable denial with reason ERROR, and LangChain Python raises ArcjetToolUnavailableError or ArcjetUnavailableError. A direct guard() call fails open and reports it on hasFailedOpen().
Do coding agents need a framework adapter?
No. For Claude Code, GitHub Copilot, Cursor, OpenAI Codex, and Muse Code, Arcjet enforces policy through the hooks each agent already fires, with no SDK and no code change. An administrator installs the hooks through managed settings, so one policy applies across all five agents and developers can't remove it without admin access.
AI runtime security in your code
Protect your AI agent workflows with Arcjet
Arcjet runs inside your application, where it can use runtime context to enforce agent actions and budgets, detect prompt injection, and protect sensitive information before a workflow acts.