Presidio Hardened X402 Mcp

io.github.presidio-v由 GitHub 帳號 presidio-v 發布v0.4.0更新於 Nov 8, 2026

Pre-payment safety gate for x402 agents: PII screening, spend policy, replay checks before signing.

已驗證STDIO僅桌面金融安全與監控

概覽

AI 產生的概覽

本機 MCP 付款前置閘門:在代理簽署 x402 付款前篩檢中繼資料中的個人識別資訊、執行消費限額並偵測重複付款。

可以做什麼
  • 篩檢並遮蔽付款中繼資料(資源 URL、描述、原因)中的個人識別資訊,可限定實體類型
  • 依單筆、滾動視窗與單一端點的美元上限檢查消費政策,成功時記錄該筆支出
  • 以標準欄位的 HMAC 指紋偵測重複付款,狀態可存於記憶體或 Redis
  • 在設定金鑰與路徑後輸出簽章的付款決策紀錄與 HMAC 鏈式稽核日誌
適用情境
適用於代理會簽署 x402 付款,且希望在金流或中繼資料離開主機前,對載荷中的個人資訊、預算超支與重複付款做預設拒絕檢查的情境。它用來與付款執行、端點安全類伺服器搭配,而非取代它們。
執行需求
需要 Python 3.10 以上版本,透過 uvx 從 PyPI 在本機執行。所有環境變數皆為選用,預設提供無網路、無配額、不儲存個人資訊的行程內模式。限額、重放 TTL、Redis 位址、稽核路徑、遠端篩檢位址與 API 金鑰、簽章金鑰透過 PRESIDIO_X402_MCP_* 與 PRESIDIO_X402_* 變數設定。
安裝前請注意
政策與重放工具在每次成功呼叫時都會記錄狀態,只檢查而未實際付款會虛增每日額度帳本,應在付款前各呼叫一次。簽章與鏈金鑰(PRESIDIO_X402_EVIDENCE_KEY 或金鑰檔、PRESIDIO_X402_CHAIN_KEY、PRESIDIO_X402_FINGERPRINT_KEY)屬於機密,需妥善保護。HTTP 代理模式會把付款中繼資料送往遠端篩檢主機。這些閘門看不到代理實際送出的請求內容。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Presidio Hardened X402 Mcp,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

presidio-hardened-x402-mcp

[PyPI version] [Python] [GitHub release] [License: MIT] [CI] [OpenSSF Scorecard] [OpenSSF Best Practices]

Pre-payment safety gate for x402 — agents call screen_payment_metadata(...), check_payment_policy(...), and check_payment_replay(...) before signing, catching PII, budget overruns, and duplicate payments before metadata or money leaves the agent host.

Part of the presidio-hardened-* toolkit family. Thin MCP (Model Context Protocol) adapter over the presidio-hardened-x402 library, pinned to parent 0.13.x (presidio-hardened-x402>=0.13.0,<0.14.0). 0.13.0 is the first parent that can record a control as NOT_EVALUATED, which signed decision evidence needs; it also includes the 0.11.1 fix for the percent-encoded PII redaction bypass, which remains a security floor.

Why this exists

x402 agentic payments routinely carry user-supplied free text — descriptions, memos, query-string parameters — straight through to merchants and facilitators. When an LLM agent generates that text, it can include PII the user never intended to share. Once the merchant logs it, retention is their decision, not yours.

This MCP server gives agents a small default-deny gate before payment leaves the agent host. Three tools expose the parent library's stable pre-payment controls: PII redaction, spending policy, and replay detection. Since 0.3.0 each decision can also be emitted as a signed payment-decision@1 record that a third party verifies offline (see Signed decision evidence). The tools are designed to compose with payment-execution and endpoint-safety MCP servers (x402station, Coinbase x402, Sardis, ...), while other parent-library surfaces — evidence-ref@1 verification of inbound evidence, the v0.9.1 SLO broker, the v0.10.0 settlement-ref@1 treasury binding, and the v0.11.0 CapabilityEnforcer — stay in the Python library unless an MCP tool explicitly wraps them later.

Install & configure

Requires Python ≥ 3.10. Distributed on PyPI; recommended invocation via uvx (no global install).

Claude Desktop / Claude Code

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent on your platform:

json
{  "mcpServers": {    "presidio-x402": {      "command": "uvx",      "args": ["presidio-hardened-x402-mcp"]    }  }}

Cursor / Windsurf / Continue

Same shape — every MCP host accepts command / args / env. See your editor's MCP-server docs for the config-file path.

Environment variables

All optional. Defaults give a zero-config in-process mode with no quota, no network, and no PII storage.

VariablePurposeDefault
PRESIDIO_X402_MCP_MODEregex (zero-setup) or nlp (needs [nlp] extra + a spaCy model)regex
PRESIDIO_X402_MCP_MAX_PER_CALL_USDMax USD per single payment (policy gate)unset → no limit
PRESIDIO_X402_MCP_DAILY_LIMIT_USDMax USD per rolling window (policy gate)unset → no limit
PRESIDIO_X402_MCP_PER_ENDPOINT_JSONPer-endpoint cap, e.g. '{"api.foo.com": 5.00}'unset
PRESIDIO_X402_MCP_WINDOW_SECONDSRolling window for the daily limit86400
PRESIDIO_X402_MCP_AGENT_IDLabel written into audit recordsunset
PRESIDIO_X402_MCP_REPLAY_TTLFingerprint cache TTL (seconds)300
PRESIDIO_X402_MCP_REDIS_URLUse Redis for replay state instead of in-memoryunset
PRESIDIO_X402_MCP_AUDIT_PATHAppend-only JSON-L audit log path; omit to disableunset
PRESIDIO_X402_MCP_LOG_LEVELDEBUG / INFO / WARNING / ERRORINFO
PRESIDIO_X402_MCP_REMOTE_BASE_URLEnable HTTP-proxy mode for tool 1 — see Modes. Must be https://; plain http:// is accepted only for loopback and otherwise refuses to startunset
PRESIDIO_X402_MCP_REMOTE_API_KEYAPI key for the remote screening serviceunset
PRESIDIO_X402_FINGERPRINT_KEY32-byte hex key for cross-process replay detectionunset (per-process)
PRESIDIO_X402_CHAIN_KEY32-byte hex key for cross-process audit-chain HMACunset (per-process)
PRESIDIO_X402_REQUIRE_FINGERPRINT_KEYFail startup if replay key is absent or invalidunset
PRESIDIO_X402_REQUIRE_CHAIN_KEYFail startup if audit-chain key is absent or invalidunset
PRESIDIO_X402_MCP_EVIDENCE_KEY_FILEFile holding the decision-signing key (preferred; wins over the env key)unset
PRESIDIO_X402_EVIDENCE_KEYDecision-signing key (the parent library's variable): Ed25519 private key as 64 hex chars, or an HMAC secretunset
PRESIDIO_X402_MCP_DECISION_PATHAppend-only JSON-L file for signed payment-decision@1 recordsunset
PRESIDIO_X402_MCP_EVIDENCE_ALGORITHMed25519 or hmac-sha256ed25519
PRESIDIO_X402_MCP_EVIDENCE_SIGNERSigner identity; the trust-store key verifiers look uppresidio-hardened-x402-mcp
PRESIDIO_X402_MCP_EVIDENCE_KEY_IDOptional key id written into each record (for rotation)unset
PRESIDIO_X402_MCP_REQUIRE_EVIDENCE_KEYFail startup unless signed evidence is fully configured and the key signsunset

Generate cross-process keys with openssl rand -hex 32.

Tools

screen_payment_metadata(resource_url, description, reason, entities?)

Detects and redacts PII in payment metadata. No side effects — safe to call repeatedly.

jsonc
// Input{  "resource_url": "https://api.foo.com/u/[email protected]",  "description": "monthly fee for [email protected]",  "reason": ""}
// Output{  "redacted_resource_url": "https://api.foo.com/u/<EMAIL_ADDRESS>",  "redacted_description": "monthly fee for <EMAIL_ADDRESS>",  "redacted_reason": "",  "entities_found": [    { "entity_type": "EMAIL_ADDRESS", "field": "resource_url", "count": 1 },    { "entity_type": "EMAIL_ADDRESS", "field": "description", "count": 1 }  ],  "mode": "in_process"  // + "decision_ref": "<64 hex>" when signed decision evidence is enabled}

entities (optional list of Presidio entity types) narrows detection to a whitelist. Field-length caps mirror the screening-api wire contract that remains stable through parent 0.7.x: resource_url ≤ 2048, description ≤ 4096, reason ≤ 4096 characters. Oversized inputs raise ValueError.

check_payment_policy(resource_url, amount_usd, prior_decision_refs?)

Spending-policy gate. Records the spend on success — call exactly once, immediately before payment. Skipping the actual payment after a successful check inflates the daily-limit ledger until the window rolls over.

The URL is screened first and only the redacted URL reaches the policy engine, so no raw URL lands in the parent's logs. Per-endpoint limits match on that redacted URL; keep PII out of configured endpoint prefixes. If screening fails, the gate denies without recording spend.

jsonc
// Input{ "resource_url": "https://api.foo.com/x", "amount_usd": 1.50 }
// Output (allowed){ "allowed": true }
// Output (denied — over per-call limit of $5.00){ "allowed": false, "reason": "...", "limit_usd": 5.00, "amount_usd": 6.00 }

With signed evidence enabled, both outputs also carry decision_ref. prior_decision_refs (optional, up to 8) links refs this server returned earlier for the same payment — typically the one from screen_payment_metadata — into the signed record; a ref this process did not issue is refused before any spend is recorded.

check_payment_replay(resource_url, pay_to, amount, currency, deadline_seconds, prior_decision_refs?)

Duplicate-payment gate via HMAC-SHA256 fingerprint of the canonical fields. Records the fingerprint on success — call exactly once, immediately before payment.

amount is a string to preserve precision. Cross-process detection requires PRESIDIO_X402_FINGERPRINT_KEY (and optionally PRESIDIO_X402_MCP_REDIS_URL); otherwise each MCP server process keeps its own in-memory store.

jsonc
// Input{  "resource_url": "https://api.foo.com/x",  "pay_to": "0xabc...",  "amount": "1.50",  "currency": "USDC",  "deadline_seconds": 1700000000}
// Output (first seen){ "is_replay": false, "fingerprint": "29aaf60f..." }
// Output (duplicate within TTL){ "is_replay": true, "fingerprint": "29aaf60f..." }

decision_ref and prior_decision_refs behave as for check_payment_policy.

Signed decision evidence

The audit log (PRESIDIO_X402_MCP_AUDIT_PATH) is HMAC-chained: tamper-evident to whoever holds PRESIDIO_X402_CHAIN_KEY, and to nobody else. From 0.3.0 every tool decision — allow and block alike — can also be written as a signed payment-decision@1 record, built and signed by the parent library (build_payment_decision_content, build_decision_evidence) and checked by anyone with the public key (verify_decision_ref). The audit log is still written; the records go alongside it, never instead of it.

bash
# One-time: an Ed25519 key pair for the signer (hex private key, 0600).python - <<'PY'from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKeyfrom cryptography.hazmat.primitives.serialization import Encoding, PublicFormatsk = Ed25519PrivateKey.generate()open("evidence.key", "w").write(sk.private_bytes_raw().hex())print(sk.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw).hex())  # -> trust storePYchmod 600 evidence.key
json
"env": {  "PRESIDIO_X402_MCP_EVIDENCE_KEY_FILE": "/etc/presidio/evidence.key",  "PRESIDIO_X402_MCP_DECISION_PATH": "/var/log/presidio/x402-mcp-decisions.jsonl",  "PRESIDIO_X402_MCP_REQUIRE_EVIDENCE_KEY": "1"}

Verify offline with the parent's CLI against a trust store that pins the public key under the signer name:

bash
echo '{"presidio-hardened-x402-mcp": {"alg": "ed25519", "public_key": "<public hex>"}}' > trust.jsonpython -m presidio_x402.decision_ref /var/log/presidio/x402-mcp-decisions.jsonl trust.json

Without a key the server behaves exactly as 0.2.x — audit log only — and logs one WARNING at startup saying signed evidence is disabled. A key without PRESIDIO_X402_MCP_DECISION_PATH, an unreadable key file, or a key the signer rejects is logged at ERROR and also leaves evidence off. Set PRESIDIO_X402_MCP_REQUIRE_EVIDENCE_KEY=1 to refuse to start in any of those cases instead. Once running, a failed write is logged and the gate's answer stands: a record of a decision never reverses the decision.

What a record says. payment-decision@1 always carries all five controls (pii → trusted_wallet → policy → replay → mpa). Each record holds real verdicts only for what its tool ran and NOT_EVALUATED for the rest: every tool screens the URL (pii), check_payment_policy adds policy, check_payment_replay adds replay; trusted_wallet and mpa are never evaluated here. NOT_EVALUATED never fails a decision and never claims a pass, so the controls block alone says which gate decided. Chain the three with prior_decision_refs to get one linked set per payment.

What it never contains. Raw resource_url, description, or reason; only the URL's scheme and host, the entity-type labels found, and hashes (policy snapshot, replay fingerprint, payment details). The gates see PII in the URL they are handed but pay it unchanged, so their PII verdict is PII_WARNED; screen_payment_metadata returns redacted strings and records PII_REDACTED. Fields an MCP tool never sees — payer wallet, network, the raw 402 offer — are recorded as unspecified / not-presented. The records carry no capability-chain parents, so the ADR-0002 top-level parents field is never set.

Modes

In-process (default). Wraps the local presidio-hardened-x402 library in the same process as the MCP server. No network, no API key, no quota. PII never leaves the agent host. Use this unless you have a specific reason not to.

HTTP-proxy. When both PRESIDIO_X402_MCP_REMOTE_BASE_URL and PRESIDIO_X402_MCP_REMOTE_API_KEY are set, screen_payment_metadata calls /v1/screen on the configured host (e.g. https://screen.presidio-group.eu) for centralized audit. On auth / quota / network failure, returns a structured { "error": "auth_error" | "rate_limit" | "unavailable", "detail": ..., "mode": "remote" } — never silently falls back to in-process. Tools 2 and 3 always stay in-process.

Composability

Designed to slot into agent flows alongside payment-execution and endpoint-safety MCP servers:

agent intent: pay https://api.foo.com/x with 1.50 USDC    │    ├─ x402station    preflight(url)            ← is the ENDPOINT safe? (decoys, dead, traps)    │    ├─ presidio-x402  screen_payment_metadata   ← is the PAYLOAD safe? (PII)    ├─ presidio-x402  check_payment_policy      ← within budget?    ├─ presidio-x402  check_payment_replay      ← not a duplicate?    │    └─ pay()

screen_payment_metadata is read-only and safe to interleave anywhere. The policy and replay gates record state on call — sequence them immediately before payment.

What none of these gates can see: a request body the agent made up. The three tools screen the 402 challenge's metadata and the spend; they never see the body the agent sends to a POST route. Independent measurement of the x402 and MPP catalogues (probe402, MCRI #001, 1 September 2026) found 1,521 of 8,056 listed POST routes — 18.9% — publish no usable request example, and 72% of those still return a payable quote at the wall. A route like that is listed, priced, and not machine-executable from the published contract. An agent that fills the gap by synthesising a body is guessing, and a guessed body is where user data enters the request unscreened. Posture: if the catalogue entry carries no request example or schema, stop at the 402 quote and surface it; do not invent a body to get past the wall. Put that rule in the agent's instructions — it is a decision the agent makes before any of these tools run.

Combined snippet: preflight → screen → pay

Endpoint-safety and payload-safety are independent signals — calling both is what you actually want before signing. Configure the two MCP servers side-by-side:

json
{  "mcpServers": {    "x402station":   { "command": "npx", "args": ["-y", "x402station-mcp"],                       "env": { "AGENT_PRIVATE_KEY": "0x…" } },    "presidio-x402": { "command": "uvx", "args": ["presidio-hardened-x402-mcp"] }  }}

Agent flow before signing a payment (pseudocode — each step is one MCP tool call):

python
# 1. endpoint safety: is the URL trustworthy? (x402station-mcp)pf = preflight(url)if not pf["ok"]:    abort(reason=pf["warnings"])  # decoy / zombie / dead / price-trap
# 2. payload safety: redact PII before it leaves the host (presidio-x402)s = screen_payment_metadata(resource_url=url, description=description, reason="")url, description = s["redacted_resource_url"], s["redacted_description"]
# 3. spend gates: record-on-success, call exactly once each (presidio-x402)if not check_payment_policy(url, amount_usd)["allowed"]:    abort(reason="policy")if check_payment_replay(url, pay_to, amount, currency, deadline_seconds)["is_replay"]:    abort(reason="replay")
# 4. sign + paypay(url, amount, description=description)

The two servers are developed independently, on purpose — keeping the signals uncorrelated is the point. See x402station-mcp for the preflight tool's full output schema and warning catalog.

Notes for developers

  • Logs go to stderr (MCP clients capture stderr). stdout is reserved for JSON-RPC frames.
  • The package is a thin adapter. All security logic lives in presidio-hardened-x402 — read its docs for the entity-type catalog, policy semantics, evidence-ref verification, SLO broker, and audit-chain details.
  • This MCP release exposes the same three tools as 0.1.1. 0.3.0 adds signed payment-decision@1 emission from those tools and an optional prior_decision_refs argument on the two gates; the rest of the parent SLO/evidence/capability surface is not promoted into MCP.
  • When testing via mcp-inspector --cli, bare numeric --tool-arg amount=1.50 is auto-coerced to a float and rejected by the schema. Real MCP clients send proper JSON types; the tool's amount argument is a string to preserve precision.
  • Local dev: uv venv && uv pip install -e ".[dev]" && pytest tests/.

License

MIT. See LICENSE.

Links


SDLC

This repository is on the open-source baseline of the PRESIDIO hardened-family SDLC (report · PDF). The controls measured for it, and any open gaps, are its row in the applicability matrix.

Roadmap (next 12 months)

  • Now / in flight — OpenSSF Best Practices silver and a Scorecard above 7: governance docs, a real CodeQL job alongside Bandit, least-privilege workflow tokens, and Atheris fuzzing of the configuration validators. Closing the remaining findings in SECURITY-AUDIT.md.
  • Next — hash-pinned CI dependencies, ideally as a family-wide change rather than in this repo alone.
  • Later (under evaluation) — signed releases with build provenance; tracking the MCP specification as it stabilises; exposing the parent library's capability-grant@1 enforcement as a fourth tool, if agent demand justifies the added surface.

Governance, Architecture, Security

  • Governance — roles, decision process, and how to become a maintainer.
  • Architecture — components, trust boundaries, and the core processing path.
  • Assurance case — the security claims and the evidence backing each one.
  • Security policy — supported versions and how to report a vulnerability.
  • Contributing — review bar, test policy, and verification commands.
  • Stability guarantees — what counts as the public API and what may not change.

來源:README.md,提交 911cfcd

工具

3

screen_payment_metadata

Screen x402 payment metadata for PII before signing the payment. Call BEFORE sending the payment request. Detects emails, phone numbers, SSNs, names, and other PII in the resource URL, description, and reason fields and returns redacted strings plus per-field entity counts. No side effects. Runs in one of two modes: - in_process (default): wraps the local presidio_x402 PIIFilter. - remote: when both PRESIDIO_X402_MCP_REMOTE_BASE_URL and ..._REMOTE_API_KEY are set, POSTs to /v1/screen on that host for centralized audit. On remote failure, returns a structured error dict instead of silently falling back — the caller must decide whether to retry, accept reduced screening, or abort. Args: resource_url: x402 resource URL the agent is about to pay (max 2048 chars). description: Human-readable description (max 4096 chars). reason: Reason / memo string (max 4096 chars). entities: Optional whitelist of Presidio entity types to detect. If None, all configured entities are scanned. Returns: On success: dict with keys redacted_resource_url, redacted_description, redacted_reason, entities_found (list of {entity_type, field, count}), and mode (one of "in_process", "remote"); plus decision_ref when signed decision evidence is enabled (pass it to the gates as prior_decision_refs). On remote failure: dict with keys error (one of "auth_error", "rate_limit", "unavailable"), detail, optional retry_after (for rate_limit), and mode ("remote").

輸入參數reasonentitiesdescriptionresource_url必填

check_payment_policy

Check whether a payment is allowed by the configured spending policy. WARNING: this records the spend against rolling time-window ledgers. Call exactly once, immediately before submitting the payment. If you call this and then do not pay, the spend window will be inflated until it rolls over. Configure limits at server startup via PRESIDIO_X402_MCP_* env vars. Args: resource_url: x402 resource URL being paid. Screened first; only the redacted URL reaches the policy engine (per-endpoint limits match on it, so keep PII out of configured endpoint prefixes). amount_usd: Payment amount in USD-equivalent. prior_decision_refs: Optional decision_ref values this server returned earlier for the same payment (e.g. from screen_payment_metadata); linked into the signed record. Max 8. Returns: {"allowed": true} on success, or {"allowed": false, "reason": str, "limit_usd": float, "amount_usd": float}; plus decision_ref when signed decision evidence is enabled.

輸入參數amount_usd必填resource_url必填prior_decision_refs

check_payment_replay

Check whether this exact payment has been seen recently (replay protection). WARNING: this records the fingerprint. Call exactly once, immediately before submitting the payment. Cross-process detection requires PRESIDIO_X402_FINGERPRINT_KEY (and optionally PRESIDIO_X402_MCP_REDIS_URL); otherwise each MCP server process has its own ephemeral in-memory store. Args: resource_url: x402 resource URL. pay_to: Recipient address. amount: Amount as string (preserves precision). currency: Currency symbol (e.g. "USDC"). deadline_seconds: Payment deadline as epoch seconds. prior_decision_refs: Optional decision_ref values this server returned earlier for the same payment; linked into the signed record. Max 8. Returns: {"is_replay": false, "fingerprint": "<hex>"} on first seen, or {"is_replay": true, "fingerprint": "<hex>"} on duplicate; plus decision_ref when signed decision evidence is enabled.

輸入參數amount必填pay_to必填currency必填resource_url必填deadline_seconds必填prior_decision_refs

版本歷史

3
  1. v0.3.0Oct 18, 2026
  2. v0.2.0Sep 30, 2026
  3. v0.1.1Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分