AgentRaaS wrap

io.github.agentraas由 GitHub 账号 agentraas 发布v0.16.0更新于 Oct 31, 2026

Wraps any MCP server: identical write-tool calls run once, and every tool call is audit-logged.

已验证STDIO仅桌面开发者工具安全与监控

概览

AI 生成的概览

包装任意 MCP 服务器,使相同的写入类工具调用在去重窗口内只执行一次,并把每次工具调用写入审计日志。

可以做什么
  • 在现有 MCP 服务器命令前加一层包装,让相同的写入工具调用直接返回首次结果而不再执行
  • 依据 readOnlyHint 注解或工具名判断只读工具并保持其查询新鲜,也可按工具单独覆盖
  • 失败的调用不缓存,重试会真正执行;被去重的结果会在响应元数据中标记
  • 把每次工具调用追加记录到本地审计日志文件
  • 扫描 MCP 服务器配置,在不调用工具的情况下列出可能转账、删除数据、执行代码或发送消息的工具
适用场景
适用于智能体会重试或循环、可能重复发送同一封邮件、重复创建同一个 issue 或其他有副作用的工具调用的场景。也适合在上线使用第三方 MCP 服务器的智能体前,先了解哪些工具能对真实世界产生影响。
运行要求
以 Python 包形式通过 uvx 或 pip 安装,作为本地 stdio 进程运行,需放在另一个 MCP 服务器命令之前。包装模式未声明需要账号、API 密钥或环境变量。状态与日志默认写入用户主目录下的文件。
安装前请注意
它位于另一个服务器之前,能看到全部工具调用,并写入本地审计日志文件。去重判断是启发式的:未被识别为只读的工具都按写入处理,因此重复调用可能在默认 10 分钟窗口内直接返回缓存结果。scan 命令会启动所读配置中的 MCP 服务器,只应扫描你信任的配置。

安装

在 SourceWeft 中

  1. 打开 控制台中的 AgentRaaS wrap,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

agentraas (Python SDK)

The reliability layer for what AI agents do. Every action your agent takes (a charge, an email, a CRM update, a tool call) runs once even when it is retried, can be checked against rules before it runs, and is recorded. This package brings that to your code:

  • @exactly_once and protect_tool (LangChain/LangGraph, CrewAI): a retry, yours, your framework's or a flaky network's, never becomes a duplicate charge or message. No server needed.
  • agentraas wrap: the same for any MCP server's write tools.
  • agentraas scan: lists which tools in your MCP servers can move money, delete data, run code or send messages, without calling any of them.
  • agentraas chaos: finds the calls in your agent that would double up under retries, before production does.
  • Client: points your calls at an AgentRaaS server for action policies, human approval, spend caps, circuit breaking and an audit trail.

Works against any AgentRaaS deployment: self-hosted (./install.sh, free and unlimited on every tier) or AgentRaaS Cloud.

Install

bash
pip install agentraas

Library mode: no server needed

Wrap any function that has a side effect (charging a card, sending an email, creating a CRM record) so retries and concurrent duplicates run it exactly once. Nothing to deploy: state lives in a local SQLite file by default, or in your own Redis.

python
from agentraas.local import exactly_once, RedisStore
@exactly_once()                                   # SQLite file, one machinedef charge(customer, amount):    return stripe.Charge.create(customer=customer, amount=amount).id
charge("cus_1", 4200)   # runs for realcharge("cus_1", 4200)   # retry: returns the cached id, no second charge
# Across machines, with your own idempotency key and window:@exactly_once(store=RedisStore("redis://localhost:6379/0"),              key=lambda order: order["id"], ttl=3600)async def ship(order):    ...
  • If the function raises, nothing is cached and a retry runs it again. That includes the case where the provider did the work but the response was lost, so give the function an idempotency_key parameter and send it to the provider (e.g. Stripe's Idempotency-Key header). The decorator fills it with the same value on every retry:

    python
    @exactly_once()def charge(customer, amount, idempotency_key=None):    return stripe.Charge.create(customer=customer, amount=amount,                                idempotency_key=idempotency_key).id
  • A duplicate that arrives while the first call is still running waits for its result (up to wait=30 seconds, then InFlightError).

  • Results must be JSON-serializable (return ids or dicts, not SDK objects).

  • RedisStore needs pip install redis.

When you want a dashboard, audit trail, human approval or circuit breaking on top, point the same calls at an AgentRaaS server with the Client below.

LangChain / LangGraph: exactly-once tool calls

pip install "agentraas[langchain]", then wrap the tools that have side effects. Works with LangChain agents, create_react_agent and ToolNode.

python
from agentraas.langchain import protect_tool
tools = [protect_tool(charge_card), protect_tool(send_email), search]agent = create_react_agent(model, tools)

When the model calls a protected tool again with the same arguments, or the graph re-runs the tool node after a crash or retry, the stored result comes back instead of a second charge. Takes the same store=, key= and ttl= options as @exactly_once above (e.g. store=RedisStore(...) for several workers, key=lambda order_id, **_: order_id). Tool results must be JSON-serializable.

CrewAI: exactly-once tool calls

pip install "agentraas[crewai]" (CrewAI needs Python 3.10+), then wrap the tools that have side effects, either BaseTool subclasses or @tool functions:

python
from agentraas.crewai import protect_tool
agent = Agent(role="Billing", goal="...", backstory="...",              tools=[protect_tool(ChargeCardTool()), protect_tool(send_email)])

When the agent calls a protected tool again with the same arguments, or a crew is kicked off again after a crash, the stored result comes back instead of a second charge. Same store=, key= and ttl= options as above. The original tool object is left unchanged.

MCP wrap: exactly-once tool calls for any MCP server

Put agentraas wrap -- in front of an MCP server's command. Everything passes through unchanged, except that an identical call to a write tool (same tool, same arguments) inside the dedup window gets the first call's result back instead of running again. An agent that retries or loops can't send the same email or open the same issue twice. Every tool call is appended to an audit log.

Claude Desktop / Cursor config:

json
{  "mcpServers": {    "github": {      "command": "uvx",      "args": ["agentraas", "wrap", "--", "npx", "-y", "@modelcontextprotocol/server-github"]    }  }}
  • Read-only tools are never deduplicated, so lookups stay fresh. The server's readOnlyHint annotation decides, falling back to names like get_*, list_*, search_*. Override with --dedupe TOOL / --no-dedupe TOOL.
  • A failed call (JSON-RPC error or isError: true) is not cached, so a retry runs for real.
  • Default window: 10 minutes (--ttl 600). State lives in ~/.agentraas/mcp-dedup.db, the log in ~/.agentraas/mcp-audit.jsonl (--db, --log).
  • A deduplicated result carries _meta: {"agentraas/deduplicated": true}.

MCP safety scan: which tools can act on the real world

bash
agentraas scan                                    # every server in your Claude Desktop, Cursor, Claude Code configsagentraas scan -- npx -y @modelcontextprotocol/server-githubagentraas scan --config .mcp.json --fail-on high  # CI: exit 1 on a high-risk tool

Starts each stdio server the way your client does, sends only initialize and tools/list, and sorts the tools: moves money, deletes, runs code, sends (high), writes (medium), reads (low), from their readOnlyHint/destructiveHint annotations and the words in their names. Only scan configs you trust: it runs their commands. --json for machine-readable output. https://agentraas.io/mcp-scan

GitHub Actions:

yaml
- uses: agentraas/agentraas/src/scan-action@main  with:    config: .mcp.json   # or command: "npx -y @modelcontextprotocol/server-github"; fail-on: high | medium | none

Chaos tester: find the calls your agent would run twice

agentraas-chaos sits between your code and an API. The first time each distinct write request (POST/PUT/PATCH/DELETE) arrives, it lets the request execute and then drops the response, the network failure that turns a retry into a double charge. Then it reports every action that executed more than once.

bash
pip install agentraas
# Safe: a built-in mock answers every call, nothing real is touchedagentraas-chaos --mock -- python my_agent.py
# Against a real API: use TEST-mode keysagentraas-chaos --upstream https://api.stripe.com -- pytest

Your command gets AGENTRAAS_CHAOS_URL (e.g. http://127.0.0.1:8787); use it as the API base URL. Without a command it runs until Ctrl-C, so you can point an n8n workflow or any other tool at it by hand.

agentraas-chaos: 6 write requests, 3 responses dropped after execution
  DUPLICATES: 1 action(s) executed more than once
    2x  POST /v1/charges  (body sha256 623f14d1b00d)  ...  Protected by an idempotency key: 2 retries

It exits with code 1 when it finds a duplicate, so it can fail CI. --fault error-after-commit returns a 502 instead of dropping the connection. A retry that repeats an Idempotency-Key it has already seen is counted as protected, not executed again.

In GitHub Actions:

yaml
- uses: actions/setup-python@v5  with: { python-version: "3.12" }- uses: agentraas/agentraas/src/chaos-action@main  with:    run: python my_agent.py

Keep rules in Git: agentraas apply

Describe a server's dedup rules, validation rules, action policies and spend caps in YAML, review them like code, and apply them from CI:

bash
pip install "agentraas[apply]"
yaml
# agentraas.yamlapiVersion: agentraas.io/v1alpha1kind: DedupRulemetadata: {name: charge-once, org: org_acme}spec: {service: stripe, action: charges.create, fields: [customer, amount], ttlSeconds: 300}---apiVersion: agentraas.io/v1alpha1kind: SpendCapmetadata: {org: org_acme}spec: {service: stripe, action: refunds.create, window: day, maxCalls: 100, onExceed: block}
bash
export AGENTRAAS_URL=https://agentraas.example.com [email protected] AGENTRAAS_PASSWORD=...agentraas apply -f agentraas.yaml --dry-run   # print the planagentraas apply -f agentraas.yaml             # create what's missing, replace what changedagentraas apply -f agentraas.yaml --prune     # also delete rules the file doesn't list

Kinds: DedupRule, ValidationRule, ActionPolicy, SpendCap. Spec keys are the API's fields in camelCase. Running it twice changes nothing.

Local tunnel: test webhooks against your laptop

agentraas tunnel prints a public URL and replays every request sent to it against a local port, so you can point Stripe, GitHub or n8n webhooks at code you haven't deployed. Needs a free AgentRaaS account (an agent API key).

bash
pip install "agentraas[tunnel]"agentraas tunnel --port 3000 --org org_acme --agent agent_1 --key ar_live_...

One tunnel per org, 2-hour sessions, 30-second local response timeout.

Send one action from the shell: agentraas call

Every command also runs under the short name agtrs. call sends one action through an AgentRaaS server and prints the answer as JSON: the same dedup, policies, approvals and audit as the Client. Handy for scripts and for checking a rule by hand.

bash
export AGENTRAAS_KEY=ar_live_... AGENTRAAS_ORG=org_acme AGENTRAAS_AGENT=agent_1export AGENTRAAS_URL=https://agentraas.io      # default http://localhost:13000agtrs call stripe charge.create '{"amount": 4999, "currency": "usd"}'echo '{"text": "hi"}' | agtrs call slack message.post -

--key, --org, --agent, --url and --idempotency-key override the environment. A rejected call prints the error and its hints and exits 1.

Approve held calls from the shell

The same list as the dashboard's Waiting for approval, for any org you can write to. Logs in like apply (AGENTRAAS_EMAIL / AGENTRAAS_PASSWORD against AGENTRAAS_URL, default https://agentraas.io).

bash
agtrs approvals                  # req id, service, action, agent, payloadagtrs approve req_abc123         # runs the call; asks first (--yes to skip)agtrs deny req_abc123

approve exits 1 if the call ran and failed (it is then in Failed requests). Without a terminal it refuses unless --yes is passed, so a script never approves by accident.

Read the audit log from the shell

Every call in the orgs you belong to, newest first, with the same login as approvals:

bash
agtrs audit                      # last 50: time, status, service action, agent, org, duration, req id, erroragtrs audit -n 200 --json        # adds run/step ids, dedup hash, redacted payload preview (max 1,000)agtrs audit --csv > audit.csv    # the dashboard's CSV export (newest 10,000)

Failed calls from the shell

Calls that failed and were kept (the dashboard's Failed requests), with the same login as approvals:

bash
agtrs dlq                        # id, time, service action, agent, org, req id, erroragtrs dlq replay 42              # sends the call again with the same idempotency key; asks first (--yes to skip)agtrs dlq dismiss 42             # drop it without sending

replay exits 1 if the service fails again; the entry stays in the list.

Move dashboard rules into Git

agtrs rules prints the rules already on the server as a file apply accepts, so applying it right away changes nothing:

bash
agtrs rules --org org_acme > agentraas.yamlagtrs apply -f agentraas.yaml --dry-run   # no changes

Quickstart

  1. Connect an agent from your AgentRaaS dashboard (+ Connect Agent) — this gives you an agentraas_key, plus your org_id and agent_id.
  2. Add credentials for the service you're calling (Credentials panel) — AgentRaaS forwards to the real API using those, you never pass a raw upstream API key through this SDK.
python
import agentraas
client = agentraas.Client(    agentraas_key="ar_live_...",    org_id="acme-corp",    agent_id="billing-bot",    base_url="http://localhost:13000",  # or your Cloud/self-hosted URL)
result = client.call("stripe", "charge.create", {"amount": 5000, "currency": "usd"})

Or with dot-notation sugar:

python
stripe = client.service("stripe")result = stripe.charge.create({"amount": 5000, "currency": "usd"})

Calling a Custom Action you've registered:

python
result = client.custom("my-internal-webhook", {"foo": "bar"})

Why org_id / agent_id matter

Omit them and every untagged SDK caller shares one unenforced identity server-side — your per-agent rate limit and audit trail won't tell your traffic apart from anyone else's. Set them once you've connected an agent from the dashboard; it takes two extra kwargs.

Retries are safe

AgentRaaS claims an atomic dedup slot server-side before forwarding anything. If client.call(...) raises because of a timeout or a dropped connection, calling it again with the same payload is safe — it either completes normally or returns the cached result from the call that actually went through. This SDK doesn't retry automatically; your own retry logic (or your agent framework's) can be as aggressive as you want.

One case is different: if the provider doesn't answer AgentRaaS in time, you get a 504 with "outcome": "unknown", and identical calls get a 409 until it's resolved. Retrying won't run it, on purpose, since it may already have gone through. Check with the provider, then replay or dismiss it from Failed Requests in the dashboard (steps). If you're sure it did not run, resend it as a new action with your own key:

python
client.call("stripe", "charge.create", payload, idempotency_key="order-1042-retry-1")

Record locks

When two agents change the same customer or order at once, the second gets a 409 (how it works). To wait for the record instead (up to 5 seconds, first come first served), or to lock an id of your own choosing:

python
client.call("stripe", "refund.create", payload, lock_wait_ms=2000)client.call("custom", "update_order", payload, resource_id="order-1042")

Record and replay

Run an agent once against the real providers, then replay it (in a test, in CI, after a prompt change) without calling them again:

python
recorder = Client(agentraas_key, org_id, agent_id, record="refund-flow")# ... run the agent with recorder ...
replayer = Client(agentraas_key, org_id, agent_id, replay="refund-flow", run_id="ci-42")# each call is answered from the recording, in order; nothing reaches the provider

Each replayed answer carries replay: {recording, position, payload_matches}; a call the recording doesn't have raises a 404. A new run_id starts from the top. Details: agentraas.io/docs#record-replay.

Error handling

python
from agentraas import AgentRaaSError
try:    client.call("stripe", "charge.create", {"amount": 5000, "currency": "usd"})except AgentRaaSError as err:    print(err.status_code, err.req_id, str(err))    if err.status_code == 504:        pass  # outcome unknown: don't retry blindly, resolve it first

A payload that fails a validation rule raises a 422 with every failing field in err.validation_errors (field, rule, message, hint). Nothing was sent, and str(err) lists each hint, so an agent shown the error can fix them all in one retry:

text
[422] amount must be number, got string (reqId=...)- amount: Send "amount" as a JSON number: 49.99, without quotes.- currency: Send "usd" (exact spelling) in "currency".Nothing was sent. Fix every field listed in validation_errors, following each hint, and send the call again.

License

MIT — see LICENSE. (The AgentRaaS server core is MIT too, its Team/Enterprise features source-available; see the main repo.)

来源:src/sdk/README.md,提交 66c74ab

工具

0
SourceWeft 曾在隔离沙箱中以无凭据方式启动该软件包一次,以列出其工具,但未能完成:服务器未能启动。

版本历史

6
  1. v0.16.0最新Oct 31, 2026
  2. v0.15.1Oct 30, 2026
  3. v0.15.0Oct 29, 2026
  4. v0.14.0Oct 22, 2026
  5. v0.13.0Oct 22, 2026
  6. v0.12.1Oct 21, 2026

评分

已满足适用检查项的 40%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分

    请在仓库或注册中心条目中声明许可证。