mcpField
I
integrate-arcjet-guard-claude-agent-sdk-py

integrate-arcjet-guard-claude-agent-sdk-py

github.com/arcjet安全4106 次安装3 周前更新
代码仓库

关于 integrate-arcjet-guard-claude-agent-sdk-py

此技能指导如何将 Arcjet Guard 接入官方 Python Claude Agent SDK,以控制提示词和工具调用。它区分自定义工具、入站提示词及未包装工具的拦截方式,并说明会话关联与拒绝策略。

主要功能

  1. 01通过 guard_tool 守护自定义工具
  2. 02用 guard_hooks 检查提示词和工具
  3. 03区分入站拦截与调用后捕获
  4. 04关联调用方提供的会话 UUID
  5. 05配置限流及故障时拒绝策略

适用场景

  1. 01阻止提示词注入进入模型
  2. 02限制有副作用的自定义工具
  3. 03拦截内置或未包装的 MCP 工具
  4. 04验证限流与 Guard 故障处理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/arcjet/skills --skill integrate-arcjet-guard-claude-agent-sdk-py

安装后在 Claude Code 中输入/integrate-arcjet-guard-claude-agent-sdk-py确认已加载。

详细介绍

将 Arcjet Guard 集成到 Python Claude Agent SDK

arcjet.guard.claude_agent_sdk 封装 Agent 现有的 Arcjet 客户端。 它本身不会与 Arcjet API 通信。通用 Guard 基础知识 (客户端、规则、标签、决策、捕获、注册)请参阅 ../arcjet/references/guards_python.md。 对于 Claude Agent SDK 专属内容以外的所有内容,请加载该参考文档。

仅支持官方 claude-agent-sdk>=0.2.127,<1,不支持 JS @anthropic-ai/claude-agent-sdk 适配器 (@arcjet/guard/claude-agent-sdk/v0,文档见 https://docs.arcjet.com/guards/claude-agent-sdk/)、Vercel AI、社区分支,也不支持托管在 Claude Managed Agents 上的 client.beta.sessions(arcjet.guard.claude_managed_agents)。 导入 arcjet.guard.claude_agent_sdk 不会加载 LangChain、CrewAI 或 JS 适配器。该额外组件是安全的(不包含 chromadb)。

导出内容:guard_tool、guard_hooks、claude_agent_context。 对于自有工具,请使用自定义的 @tool + create_sdk_mcp_server;对于入站的 UserPromptSubmit 和未封装的内置工具/MCP 工具,请使用 guard_hooks。 没有入站辅助函数,也没有 guard_can_use_tool。

三个入口,一个决策规则:

  • 自定义的 @tool → guard_tool。拒绝结果以 JSON 形式放入 content,并设置 is_error: True。Python 不会转发 structuredContent (这是 JS 适配器的行为)。不要抛出异常。
  • 入站文本 → guard_hooks UserPromptSubmit(decision: "block")。只有在这里才能于模型读取提示词之前拒绝一个回合。
  • 内置工具/未封装的 MCP 工具 → guard_hooks PreToolUse (permissionDecision: "deny")。PostToolUse 仅用于捕获。
  • 关联 → claude_agent_context 读取由调用方提供的 UUID session_id。它不会生成 ID。

文档:https://docs.arcjet.com/guards/claude-agent-sdk/。

未封装的工具通过 guard_hooks 在 PreToolUse 时拒绝

内置工具(Bash、Write 等)以及未通过 guard_tool 封装的 MCP 工具都没有自定义处理程序。对于这些工具,只有 PreToolUse 可以拒绝。 PostToolUse 无法撤销已经运行的工具。将每个 guard_tool 封装器都列入 exclude,否则每个自定义工具都会受到双重 Guard 保护(两次往返、两个配额单位)。条目应与报告的名称匹配: 对于自定义 MCP 工具,传入 {"server": "support", "name": "lookup_order"}(会解析为 mcp__support__lookup_order);对于 "Bash" 这样的内置工具,则传入不带限定信息的字符串。刻意设计为不带限定信息的自定义名称不会匹配所有服务器上同名的工具。

自定义 @tool 拒绝时,JSON 放入 content,并设置 is_error: True

guard_tool 会封装 @tool 定义,在 DENY(或默认 on_guard_error="deny" 下未评估 Guard)时阻止处理程序运行。 模型会在 content 中收到作为 JSON 文本的 ArcjetDenialResult,并设置 is_error: True。不要设置 structuredContent(仅适用于 JS)。不要抛出异常:抛出的异常会成为原始异常;不设置 is_error 则看起来像是成功。默认行为与 #196 相同,采用失败关闭策略:只有 "allow" 会失败开放;DENY 始终会阻止操作。核心 guard() 仍采用失败开放策略。

can_use_tool 不是策略关卡

can_use_tool 用于人工参与处理流程。allowed_tools、允许规则以及 bypassPermissions / acceptEdits 都会绕过它。这与 CrewAI human_input、JS canUseTool、LangGraph interrupt() 以及 OpenAI Agents needs_approval 存在相同的陷阱。没有入站辅助函数——请通过 guard_hooks 的 UserPromptSubmit 筛查提示词注入。

先向用户确认的问题

只询问无法从代码中推断的内容;同时建议默认值。

  1. 哪些工具具有风险(会产生外部副作用、不可逆、花费金钱或发送消息)?这些工具需要使用 guard_tool。内置工具和未包装的 MCP 工具使用 guard_hooks PreToolUse。
  2. 有哪些限制?(例如,“每位用户每分钟查询 10 次” → TokenBucket。)
  3. 元数据中的用户是谁——不透明的用户/租户 ID(绝不使用 PII)?默认值:无。会话 ID 是关联 ID,不是用户 ID。Claude SDK 要求 session_id 为 UUID,并且同一个 ID 只能创建一次——后续轮次使用 resume。
  4. Arcjet 服务中断是否不可接受?每个辅助函数默认 on_guard_error="deny"。请明确询问入站 UserPromptSubmit 的处理方式:在此处采取失败关闭意味着 Agent 会停止回答,因此在这个调用点选择 "allow" 是常见且合理的做法。

读者容易弄错的地方

  1. 这不是 JS 适配器,也不是 Claude Managed Agents。 不要导入 @arcjet/guard/claude-agent-sdk/v0 或 arcjet.guard.claude_managed_agents。
  2. 没有入站辅助函数。 通过 guard_hooks 在 UserPromptSubmit 上进行筛查。
  3. can_use_tool 用于 HITL,不是策略。
  4. Python 不会转发 structuredContent。 自定义拒绝响应采用 JSON-in-content + is_error: True。
  5. session_id 必须是 UUID,且只能使用一次。 后续轮次使用 resume。claude_agent_context 不会生成 ID。
  6. 在 exclude 中列出每个 guard_tool 包装器。 漏掉 exclude 会导致 Guard 被调用两次。
  7. 根据经过身份验证的调用方设置速率限制键,不要使用模型提供的订单 ID。将 guard_tool 返回的副本传给 query / create_sdk_mcp_server。
  8. 不要用原始 guard() 包装每个工具。
  9. 隔离需要同时设置 setting_sources=[] 和 strict_mcp_config=True。 只设置其中一项仍会暴露未经 Guard 保护的路径。
  10. 有两个不同的 ID。 ClaudeAgentOptions.session_id 是每次运行唯一的 UUID(后续使用 resume)。Guard 的 session_id 是长期有效的 Actor ID。没有决策不代表拒绝。

步骤 1:安装并查找 Guard 客户端

需要 PyPI arcjet 1.1.0(arcjet[claude-agent-sdk] extra 在 1.0.0 中不可用):

pip install "arcjet[claude-agent-sdk]"

如果 Agent 尚无 Guard 客户端,请在模块作用域启动一次:

import os
from arcjet.guard import launch_arcjet

aj = launch_arcjet(key=os.environ["ARCJET_KEY"])

步骤 2:为自定义工具设置门控 — guard_tool

from claude_agent_sdk import ClaudeAgentOptions, create_sdk_mcp_server, query, tool
from arcjet.guard import DetectPromptInjection, TokenBucket, launch_arcjet
from arcjet.guard.claude_agent_sdk import guard_hooks, guard_tool

aj = launch_arcjet(key=os.environ["ARCJET_KEY"])
lookup_limit = TokenBucket(
    label="order.looked-up",
    bucket="lookups",
    refill_rate=10,
    interval_seconds=60,
    max_tokens=10,
)
mcp_limit = TokenBucket(
    label="mcp.invoked",
    bucket="mcp-access",
    refill_rate=20,
    interval_seconds=60,
    max_tokens=20,
)
inbound = DetectPromptInjection()
user_id = authenticated_user_id
# Caller-owned UUID for this conversation. Later turns: resume=session_id.
session_id = conversation_id

@tool("lookup_order", "Look up an order by number", {"order_id": str})
async def lookup_order(args: dict) -> dict:
    return {
        "content": [{"type": "text", "text": f"{args['order_id']}: shipped"}],
    }

lookup_order = guard_tool(
    guard=aj,
    tool=lookup_order,
    action="order.looked-up",
    rules=[lookup_limit(key=user_id, requested=1)],
    on_guard_error="deny",
)
# can_use_tool=... is HITL — not this policy gate

步骤 3:筛查入站请求并为未包装的工具设置门控 — guard_hooks

async for message in query(
    prompt=user_text,
    options=ClaudeAgentOptions(
        session_id=session_id,  # later turns: resume=session_id instead
        mcp_servers={
            "support": create_sdk_mcp_server(name="support", tools=[lookup_order]),
        },
        hooks=guard_hooks(
            guard=aj,
            session_id=session_id,
            exclude=[{"server": "support", "name": "lookup_order"}],
            inbound={
                "action": "message.received",
                "rules": lambda ctx: [inbound(ctx["prompt"])],
            },
            action="mcp.invoked",
            rules=lambda ctx: [mcp_limit(key=user_id, requested=1)],
            on_guard_error="deny",
        ),
    ),
):
    pass

步骤 4:关联

claude_agent_context(session_id=session_id) 会读取同一个由调用方提供的 UUID(优先使用 hook session_id,然后使用 options.session_id)。 它不会生成 ID。将已有的 ID 传给 guard_hooks 和 ClaudeAgentOptions——不要为每轮生成新的 ID。Claude SDK 也要求 session_id 为 UUID,并且同一个 ID 只能创建一次——后续轮次使用 resume。

验证集成

  1. python -m py_compile(或项目的类型检查)通过。
  2. 测试入站 PI(UserPromptSubmit 阻止)、自定义工具拒绝响应(JSON-in-content + is_error: True,没有 structuredContent)、内置工具/未包装的 MCP 工具拒绝(PreToolUse)、速率限制,以及失败关闭(Guard 无法访问)。确认包装后的工具每次调用只产生一次 Guard 决策——如果在 PreToolUse 操作下出现第二次决策,就说明缺少 exclude 条目。
  3. 在 Arcjet Console / CLI 中确认决策使用同一个由调用方提供的 UUID session_id。
  4. 使用真实 ARCJET_KEY 进行手动 E2E 测试仍待验证,直到实际运行该测试。

示例 fastapi-claude-agent-sdk-guard 仍归 Runtime 所有——不要另起示例名称。不要在此 skills 仓库中添加示例。

评论

支持 Markdown