Trust Gate

io.github.CWNApps由 GitHub 帳號 CWNApps 發布v0.2.0更新於 Nov 9, 2026

Post-quantum, tamper-evident receipts for agent actions. Ed25519 + ML-DSA-65, offline verify.

已驗證Streamable HTTP可網頁執行安全與監控商業與電商AI 與機器學習

概覽

AI 產生的概覽

為代理程式動作簽發並驗證防竄改、抗量子的簽章回執,並提供以名稱為基礎的 ALLOW/DENY/ESCALATE 決策閘門。

可以做什麼
  • 為 CRM 紀錄變更簽發簽章回執,新舊值以 SHA-256 雜湊形式攜帶
  • 為任意具後果的代理程式動作簽發簽章回執,可附上呼叫端提供的歸因欄位
  • 僅憑憑證離線驗證回執,並可釘選預期的簽署者金鑰
  • 執行兩階段決策閘門:先預覽裁決,再提交並簽發簽章回執
  • 掃描資料樣本中的敏感標記並標示被阻擋的對外傳送資料
  • 依最壞後悔程度排序呼叫端提供的 MCP 工具清單,並執行供應商退場就緒演練
適用情境
適用於代理程式會執行具後果操作、且需要一份可獨立驗證的簽章決策紀錄的情境,也適合需要一個會將未知名稱升級處理的動作前閘門的團隊。常用於圍繞 CRM 變更與工具呼叫的稽核或監督留痕。
執行需求
可使用所列主機的遠端端點,或透過 pip 安裝 trust-gate-mcp 以 stdio 方式在本機執行;選用的原生抗量子後端來自一個需要原生 liboqs 函式庫的附加元件。九個唯讀 API 檢視在設定 TRUST_GATE_API_URL、TRUST_GATE_API_KEY 與 TRUST_GATE_TENANT_ID 之前不會啟用。退場演練要求已設定本機 Ollama 端點。
安裝前請注意
閘門是以名稱為基礎的啟發式判斷,本身不會阻擋任何操作;程式碼必須把操作送進它並遵守結果,ALLOW 並不代表操作安全。動作與資源會以明文寫入回執,不要放入機密或個人資料。任何能連上開放部署的人都能取得以其金鑰簽發的回執;請設定 TRUST_GATE_BEARER_TOKEN 與 TRUST_GATE_ALLOWED_ORIGINS。預設抗量子簽章腿所用的函式庫其自身說明稱不適用於密碼學用途,stdio 模式下簽章金鑰以未加密形式儲存。API 檢視會把提供的紀錄連同 bearer 憑證傳送給第三方服務。

安裝

在 SourceWeft 中

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

Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。

交給代理程式安裝

把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。

閱讀 https://sourceweft.com/mcp/io.github.CWNApps%2Ftrust-gate-mcp/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。

檢視代理程式所依據的安裝指南

其他 MCP 客戶端

把它新增到你客戶端的 mcpServers 設定中。

{
  "mcpServers": {
    "trust-gate": {
      "type": "http",
      "url": "https://trust-gate-mcp.onrender.com/mcp"
    }
  }
}

README

Trust Gate MCP

Tamper-evident receipts for consequential agent actions, as an MCP server, with a decision gate that returns ALLOW, DENY or ESCALATE.

Sixteen tools: seven local ones on one shared signing primitive, the open-source OpenAgentOntology mint_receipt, plus nine optional read-only views over a Trust Gate API (see "Read-only API views" below).

What actually gets signed depends on what you install -- OAO detects its backend at import time, so this is worth stating plainly rather than advertising the best case:

InstallLegsNotes
pip install trust-gate-mcpEd25519 + ML-DSA-65Default. The ML-DSA leg comes from dilithium-py, a pure-Python library whose own README says it must not be used for cryptographic applications and that it is not constant-time. It keeps receipts tamper-evident and satisfies PQ-required mode, but treat that leg as unhardened.
pip install "trust-gate-mcp[slh]"Ed25519 + ML-DSA-65 (native backend)Installs liboqs-python, which needs the native liboqs library; the signing primitive then prefers liboqs for ML-DSA-65. It adds a hash-based leg only if that liboqs still ships SPHINCS+-SHA2-128s-simple (a pre-standard variant, not byte-compatible with the final FIPS 205 standard). liboqs 0.16.0, the only release liboqs-python currently targets, removed SPHINCS+, so as of 2026-09-29 this extra gives the native ML-DSA backend and no hash-based leg (not verified with liboqs installed). If liboqs cannot be imported the primitive silently falls back to dilithium-py; run_exit_drill names the active backend and whether the hash-based leg is available. Use this install if the post-quantum legs matter to you.

PQ-required verify (the default) demands at least one verified post-quantum leg. That shows a post-quantum signature is present and valid over the same bytes. It does not say whose key made it (see "What a valid receipt proves"), and it does not make the default backend production-grade.

ToolWhat it does
mint_receipt_for_record_changeMints a receipt for a CRM record change. Works with any CRM (open-core Relaticle, hosted CRMs via their own MCP, custom). Old/new values are SHA-256 hashes (unsalted, so a low-entropy value can be guessed from its hash).
audit_my_agent_inventoryRanks a CALLER-PROVIDED list of MCP tools by worst-regret if they act (a name-based heuristic that weights a name's first word most: delete_file ranks above file_delete). Read-only: it mints no receipt. Cannot auto-discover other servers -- MCP protocol does not allow that. A row that is not an object is an error, never silently skipped.
mint_action_receiptReceipt for any consequential agent action. Attestation values (triggered_by_*, decision_model) are caller claims: limited to safe characters, signed, not verified. Decision values that contain a gate verdict word (allow, deny, escalate, grant, permit, approve, withheld, committed), operation names with gate as a word, and the gate's own policy id are refused. That check is best effort: to accept a receipt as a gate verdict, pin the signer and check the signed issuer_tool (see below).
verify_receiptVerify a receipt from the certificate alone -- offline, no DB. Refuses unsigned receipts, checks the kid, and accepts expected_kid to pin the signer (counted only when that key's own Ed25519 signature verifies). Defaults to PQ-required mode. When it says ok it returns a verified block (decision, evidence hash, signed time, issuer_tool, operation and the whole verified ontology manifest, including the action and resource): read those values, not your own parse of the receipt.
gate_decisionTwo-phase decision gate with a real verdict. PREVIEW returns ALLOW, DENY or ESCALATE with the risk tier and reasons, without acting. COMMIT re-evaluates and mints a signed receipt for the verdict. Only ALLOW returns a GRANTED permit; DENY returns DENIED; ESCALATE returns WITHHELD_PENDING_HUMAN and a human decides. See below.
check_egressFlags sensitive markers in a data sample (a finite list of keywords, SSN and card-number shapes, and common credential formats, including NAME=value assignments) as NO_MARKERS_FOUND / INTERNAL / CONFIDENTIAL / RESTRICTED. Credential-shaped values and personal identifiers are RESTRICTED and set blocked: true; credential keywords alone are CONFIDENTIAL. A harmless sample that looks like an assignment of a key or password can be flagged too. It cannot block anything itself: your code must read blocked and obey it. NO_MARKERS_FOUND is not clearance to send. Returns classification + retention info + receipt.
run_exit_drillVendor exit readiness drill. Checks the local signing key (names the post-quantum backend and whether the hash-based leg is available) and that a local model endpoint is configured (Ollama; it is not contacted, and a remote host is not counted). Returns step-by-step results + receipt. Informational; it signs one receipt, which creates the signing key on a host that has none yet.

Read-only API views (optional, off by default)

Nine tools show what a Trust Gate API computes from records YOU supply. They do nothing until you set TRUST_GATE_API_URL (https; http only for localhost), TRUST_GATE_API_KEY (a bearer credential issued for one tenant) and TRUST_GATE_TENANT_ID. The seven local tools above need none of these and never call out.

ToolShows
inspect_oversight_caseReadiness report for one oversight case
propose_role_questionQuestions routed to a role for a case. It proposes; it asks no one
get_intervention_evidenceEvidence on whether an intervention could be shown to have taken effect
compare_qualification_changeStatus of each proposed retest after a change: current, not current or unbound
export_acceptance_packAcceptance-pack export, optionally mapped to one control id and version you name
get_receipt_evidenceEvidence view of one receipt, with what the service could and could not check
get_decision_evidenceEvidence view, verdict and open questions for a decision and its facts
replay_decisionReplay of a decision's evidence path over supplied records. It executes nothing
propose_requalificationImpact and a requalification proposal. It never runs a retest

Each takes one object, request, forwarded as the call body. Rules every one follows:

  • Read-only. Nothing is written, signed, executed or authorized. The answer is built from the records you pass in; their claims are yours, not verified facts.
  • The tenant is configuration. request may not name a tenant at its top level, and a tenant key at any depth (tenant, tenant_id, tenant-id, TenantId, in any case) must equal TRUST_GATE_TENANT_ID, otherwise the request is refused before any call. Only TRUST_GATE_TENANT_ID is ever sent as the tenant.
  • Fail closed. A missing setting, a 404 (the surface is off or not deployed), a rate limit, a server error, a transport error or an answer of the wrong shape returns status: "UNAVAILABLE" with a reason. A refusal from the API returns REFUSED with its short code. Data is never filled in or defaulted.
  • The credential is never logged or returned, and no exception text is passed on.
  • A mapping or readout is not a compliance finding. Every result says so.
  • Version match. The receipt, decision, replay, propose and requalification views (get_receipt_evidence, get_decision_evidence, replay_decision, propose_requalification, compare_qualification_change) and the case, question, evidence and pack views need a Trust Gate API version that serves them. Against an older server, or one with the surface switched off, they return UNAVAILABLE (surface_not_available) until it does.
  • Requests are capped at 64 KiB; answers are read up to 1 MiB (error bodies up to 4 KiB) and never further. 10 second timeout, no redirects, and proxy environment variables are ignored.

What the gate does and does not do

  • Scope. It applies only to actions your code routes through gate_decision. It does not observe, intercept or block anything an agent does, and it does not check afterward whether an action happened. Your code (a hook, a wrapper) must ask first and must obey the answer.
  • ALLOW is a closed list. An action gets ALLOW only when its name is a known read verb (read, get, list, search, query, find, show, view, inspect, describe) followed only by words from a small built-in vocabulary of nouns (for example read_file, list_files, search_files, list_dir, get_user, describe_table), the name is a plain identifier, and the resource is built only from words of that vocabulary, a few ordinary document words (readme, guide, changelog, ...) and source or prose file types (md, txt, py, ...), with digits allowed between words (docs/2024/notes.md). A name that contains any other word escalates to a human, because the gate has not seen it. This is deliberately narrow: most real file names escalate. Widening it means adding words to the vocabulary in the source, which is a visible change.
  • Structural rules escalate as well. A hidden path (.env, .ssh, .git, ..), an absolute path, a URL, a host name as the first part of a path (example.com/x, localhost), a network address in any of its usual spellings (four dotted numbers of any width, hexadecimal, octal such as 0177.1, one long integer, 0; short dotted numbers such as 1.2.3 stay versions unless the last number is too large for a version or the first is 0 or 127), a resource that starts with -, a phrase of three or more words, anything containing characters other than letters, digits, spaces and _ . - / (after Unicode compatibility folding), and a file whose real type is configuration, data, key, state or archive (a rotation counter such as .1 is ignored when judging the type; a listed data or archive type earlier in a dotted name, such as users.csv.txt, counts too). A resource that carries a command escalates: a listed mutating word (alter, merge, flush, load, ...), a critical verb glued to a word (deleteall), or any multi-word resource after a query verb.
  • DENY is for a critical lead verb (payments, deletion, deployment, code execution, privilege changes). A risky word elsewhere in the name, or in the resource, escalates so that a human decides; so do the high-risk lead verbs (format, remove, reset, release, escalate) and a file name that contains a risky word (test_delete_user.py).
  • Risky and sensitive words are listed, and the lists are finite. Listed secret and regulated-data words (password, token, key, pass, config, ssn, diagnosis, ... in their glued, plural and digit-swapped forms) give the HIGH tier a specific reason. The lists are not what keeps a name from being allowed (a sensitive name on no list still escalates, because ALLOW is closed). history is not a read noun. Matching runs across word boundaries, so some harmless names show the sensitive reason (api/index.md contains "pii"). A lookup such as list_users is a read like any other: the gate does not judge how much personal data it returns. Common read tools whose names contain a word that is also a risky verb (get_email, list_messages) escalate.
  • It is a name-based heuristic, not a proof. ALLOW does not mean the action is safe: an agent that calls a dangerous tool read_file is not caught, because the gate sees names, not behaviour. context is recorded in the receipt as a hash and is not used to decide. There is no operator override in this package.
  • Read the verdict from the receipt, and check who issued it. receipt.decision (and receipt.evidence.ontology.verdict) are signed. The top-level verdict and permit fields of the response are not; verify_receipt lists the unsigned keys of any receipt it checks. A receipt is a gate verdict from your server only if verify_receipt with expected_kid set to your server's kid returns signer_pinned: true AND verified.issuer_tool is gate_decision AND verified.operation is decision_gate_commit; every other tool signs its own issuer_tool, and without the pin those fields are only claims made by whoever signed.
  • No permit without a receipt this server would accept. COMMIT issues GRANTED only if the receipt was minted and signed, and verifies under this server's own policy (in PQ-required mode that includes a valid post-quantum signature).
  • Action and resource are recorded in clear text in the signed receipt. Do not put secrets or personal data in them.
  • A receipt is evidence of a verdict, not a log entry. atom_id is derived from the content (40 bits of the evidence hash), so identical decisions share one and different decisions can too; key on evidence_hash and signed_at. The server keeps no log of the receipts it signs: store the ones you need. There is no replay or freshness check: compare evidence.ontology.action and resource with what you are about to do.
  • 0.2.1 returned GRANTED for every action. Upgrade to 0.3.0 or later. See the changelog.

What a valid receipt proves

verify_receipt returning ok: true means the evidence is unchanged since it was signed, the receipt carries a signature, any kid it carries matches the key it carries, and (in the default PQ-required mode) at least one post-quantum signature verified over the same bytes.

It does not mean the receipt came from a server you trust: anyone can generate keys and sign a receipt. To check who signed, pass expected_kid (the kid of the Ed25519 key you trust, learned out of band; 32 hexadecimal characters, case and surrounding spaces ignored, a blank or malformed pin is refused). A pin counts only when that key's own Ed25519 signature verifies, and signer_pinned: true says it did (a signature verifying shows that the key signed those bytes, not that anyone holds its private key: Ed25519 accepts a few special public keys that verify for any message, which cannot affect a pin on a key you trust); ok: true with signer_pinned: false is an integrity result only, and kid is reported only when the Ed25519 signature verified. A receipt that names an Ed25519 signer (key or kid) without a valid signature from it is refused: those two values are public and can be copied into a receipt signed with other keys.

On stdio the signing key is stored unencrypted under the user's home directory, so an agent running as that user can read it: a pin does not protect against the agent you are gating. The kid fingerprints the Ed25519 key only. The ML-DSA and hash-based keys inside a receipt are not covered by it, so a pinned check is only as strong against a quantum attacker as Ed25519. Results can also depend on which post-quantum backends the verifying host has installed (a leg it cannot check is reported unverifiable).

Hardening

  • H1 key persistence + bootstrap with FAIL-CLOSED kid-drift check (container deploy; the bootstrap checks the Ed25519 key only)
  • H2 per-IP token-bucket rate limit (FIFO eviction). It parses the request body exactly as the MCP transport does, from the raw bytes (a byte-order mark, UTF-16 and UTF-32 are read too), and charges the tool it names; the signing tools share the signing budget. A body it cannot parse, or one over 64 KiB, is charged to the signing budget; a request is refused with 413 as soon as its body exceeds 1 MiB (at most 1 MiB is buffered). Signing (about 70 ms per call with the default backend) and verification (about 20 ms) run on the event loop and the budgets are per client, so there is no overall cap on that work. Clients are identified by the connection address as uvicorn resolves it: set TRUST_GATE_FORWARDED_ALLOW_IPS to your proxy's address, or any client can choose its own identity with an X-Forwarded-For header.
  • H3 PQ-required verify: refuses a receipt with no verified post-quantum signature (and any unsigned receipt)
  • H4 128-bit kid on every minted receipt, recomputed from the canonical key bytes and checked on verify
  • Optional bearer auth and a narrowed CORS allowlist via TRUST_GATE_BEARER_TOKEN + TRUST_GATE_ALLOWED_ORIGINS
  • The test suite pins every listed verb, noun and sensitive word individually (from an independent copy of the lists) and tests their inflected, plural, glued, digit-swapped and compatibility-character forms, plus adversarial cases for receipt forgery and PQ stripping; real MCP requests are posted through the whole HTTP stack

Deploying over HTTP

The HTTP entrypoint (server_http.py) is written for the container image, where its modules sit side by side; with a pip install, use the stdio server. Bearer auth is off by default and CORS is * in that mode. Anyone who can reach an open deployment can obtain receipts signed with its key, including "ALLOW" receipts for read-only names, and a receipt from an open deployment says nothing about who asked. If you host it, set TRUST_GATE_BEARER_TOKEN and TRUST_GATE_ALLOWED_ORIGINS.

The HTTP entrypoint counts ?via=<label> visits as one log line (label, kind, user-agent family). Only three built-in labels plus those named in TRUST_GATE_CHANNELS (comma separated) are recorded; the host's own access log also records request lines, including client addresses.

DNS-rebinding protection is off and there is no switch for it: on a local HTTP server without bearer auth, any web page you visit can call it. Put it behind a proxy that checks the Host header, or set TRUST_GATE_BEARER_TOKEN.

Install (stdio)

bash
pip install trust-gate-mcptrust-gate-mcp

Add [slh] for the native ML-DSA backend (see the table above). From a checkout, pip install -e ".[dev]" then python -m trust_gate_mcp.

Container deploy (Smithery / any container host)

bash
docker build -t trust-gate-mcp .docker run -p 8081:8081 -v trust-gate-data:/data/oao trust-gate-mcp

The volume mount on /data/oao is required for production: without it the signing key changes on every container restart, receipts signed before a restart still verify from their own certificate, but a pinned kid stops matching new ones. The persistent key_metadata.json holds the signer's kid; the bootstrap step refuses to start if it drifts. The image installs dilithium-py by default; see the table above.

License

Apache-2.0 (full text in LICENSE). Copyright 2026 Cyber Warrior Network. Built on the open-source OpenAgentOntology primitive.

來源:README.md,提交 5e38cf0

工具

7

mint_receipt_for_record_change

Mint a signed receipt (Ed25519, plus ML-DSA-65 when the post-quantum backend is available) for one CRM record change. Old/new values are carried as SHA-256 hashes. Works with any CRM (Relaticle, hosted CRMs, custom).

輸入參數field必填policytenantnew_value必填old_value必填record_id必填object_type必填changed_by_agent必填

audit_my_agent_inventory

Rank a CALLER-PROVIDED list of MCP tools by worst-regret if they act (a name-based heuristic that weights a name's first word most). Read-only: it mints no receipt. Cannot auto-discover the inventory -- MCP does not allow that; the caller must pass it in.

輸入參數notesinventory必填

mint_action_receipt

Mint a signed receipt (Ed25519, plus ML-DSA-65 when the post-quantum backend is available) for an arbitrary consequential agent action. Optional attestation: triggered_by_type (human/agent/script), triggered_by_source (api/cli/cron), decision_model (the LLM model used). Attestation values are caller claims: allowlisted to safe characters, signed, not verified. Decisions that contain a gate verdict word are reserved for gate_decision.

輸入參數inputspolicytarget必填agent_id必填decisionoperation必填decision_modeltriggered_by_typetriggered_by_source

verify_receipt

Verify a Trust Gate receipt from the certificate alone (offline). ok=true means unchanged since signing, signed, kid consistent with the embedded key, and (require_pq default on) at least one post-quantum leg verified; unsigned receipts fail. It does not prove who signed: pass expected_kid to pin the signer's Ed25519 key; a pin counts only when that key's own signature verifies (see signer_pinned). The post-quantum keys in a receipt are not covered by the kid.

輸入參數receipt必填require_pqexpected_kid

gate_decision

Two-phase decision gate with a real verdict. PREVIEW returns ALLOW, DENY or ESCALATE with the risk tier and reasons, plus a preview_id, without acting. COMMIT re-evaluates the same inputs and mints a signed receipt for the verdict. Only ALLOW returns a GRANTED permit; DENY returns DENIED; ESCALATE returns WITHHELD_PENDING_HUMAN and a human must decide outside this tool. Applies only to actions the caller routes through it: it does not observe or block what an agent does. Verb-tier heuristic on the action name and resource, not a proof. Stateless. Optional attestation: triggered_by_type, triggered_by_source, decision_model.

輸入參數phaseaction必填context必填resource必填preview_iddecision_modeltriggered_by_typetriggered_by_source

check_egress

Egress classification check. Scans a data sample for a finite list of sensitivity markers and classifies as NO_MARKERS_FOUND / INTERNAL / CONFIDENTIAL / RESTRICTED. RESTRICTED sets blocked=true; this tool cannot block anything itself, and NO_MARKERS_FOUND is not clearance to send. Returns classification, retention info, and a tamper-evident receipt.

輸入參數provider必填data_sample必填destination必填

run_exit_drill

Vendor exit readiness drill. Checks local signing key, local model access (Ollama). Returns step-by-step results and a tamper-evident receipt. Informational; it signs one receipt, which creates the signing key on a host that has none yet.

無需輸入參數。

版本歷史

1
  1. v0.2.0最新Sep 16, 2026

評分

已滿足適用檢查項的 100%

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

  • 近 30 天內可連通必需25 分
  • 已宣告認證方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分