Short, framework-specific recipes for Eve, Mastra, Claude Agent SDK, OpenAI Agents SDK, LangGraph JS, LangChain Python, and the Vercel AI SDK.
What these guides cover
How-tos are short recipes for one enforcement point in a specific agent framework. They assume you already know the threat model and need the helper that sits on this channel, connection, or tool. Eve screens inbound channel text and gates connections that have no local execute. Mastra screens messages in processors and denies unwrapped MCP, workspace, and toolset tools on beforeToolCall. Claude Agent SDK screens prompts on UserPromptSubmit and denies unwrapped built-ins on PreToolUse. OpenAI Agents screens text with a direct guard() before run() and wraps authored invoke. LangGraph JS screens before graph.invoke and denies MCP inside ToolNode. LangChain Python and the Vercel AI SDK wrap authored tools. Each recipe names the helper, the deny shape, and the control that is not a policy gate.
Risks
Channel auth treated as a prompt-injection screen
Mounted MCP or OpenAPI connections left without a local gate
Built-in tools skipped by canUseTool or a bare allowedTools name
Authored-tool wraps assumed to cover tools you did not write
Control priorities
Inbound screen before the turn starts
Connection approval or hook deny before the host is called
PreToolUse for unwrapped built-in tools
One helper per surface so the guard is not double-called
Recommended reading order
Read the matching framework overview in AI Security first. Then open the recipe for the surface you are wiring: inbound text, a connection, an authored tool, or an unwrapped MCP or built-in tool.
Screen inbound HTTP and channel text, gate tools and MCP before the side effect, and treat observe-only hooks as a diary. Budgets, local PII, and prompt-injection checks sit on those same two boundaries.
Screen user text with a direct guard() before run(). Wrap authored tool() with guardTool. needsApproval and hosted requireApproval are HITL, not policy. Hosted tools, MCP, and handoffs are not deny points.
Screen user text with a direct guard() call before run(). There is no guardInbound. On DENY do not call run(). Direct guard() fails open; gate hasFailedOpen() if the site must fail closed.
Screen inbound text with guard() before graph.invoke or in the first node. guardTool wraps authored tool(). guardToolNode wraps ToolNode in place for unwrapped and MCP tools. interrupt() is HITL, not policy.
MCP and unwrapped tools execute inside ToolNode. Graph hooks and HITL pauses cannot stop tool.invoke. guardToolNode is the gate. Wrap the node in place; a copy leaves the original unguarded.
Use guard_action on a callable, guard_tool on a BaseTool (arcjet[langchain]), or ArcjetMiddleware plus ToolPolicy on create_agent (arcjet[langchain-agents]). ArcjetCaptureHandler cannot deny.
Wrap tool() with guardTool, create a run context with createAgentContext, and pass aiToolsContext on generateText. The wrapped tool must have execute and cannot already declare contextSchema.
needsApproval, hosted requireApproval, and LangGraph interrupt() park a call for a person. They are not a remote allow or deny. Same trap as Eve user-approval, Mastra requireApproval, and Claude canUseTool.