
Provenza
io.github.kironovlaziz-del由 GitHub 帳號 kironovlaziz-del 發布v0.2.1更新於 Oct 26, 2026
Governed MCP gateway: approved tools only, each call policy-checked and recorded per agent
概覽
本機 stdio MCP 閘道,只揭露管理員核准的工具,每次呼叫都依代理身分做政策檢查並記錄。
- 可以做什麼
- 把 MCP 用戶端連到自架的 Provenza 執行個體,只看到管理員已核准的工具。
- 每次工具呼叫前,依代理權限、組織政策、工具登錄表與斷路器進行檢查。
- 將結果記錄並以代理金鑰簽章,寫入 Provenza 稽核日誌,可下載可離線驗證的收據。
- 首次啟動時完成代理註冊,金鑰在本機產生,身分檔案保存在本機。
- 透過設定不同的代理名稱,在同一台機器上執行多個代理。
- 適用情境
- 適用於組織已自架 Provenza 伺服器,並希望 AI 助理只能存取經過審核的工具、且每次呼叫都可管控、可稽核的情境。它本身不是通用工具伺服器,沒有 Provenza 執行個體就沒有可管控的內容。
- 執行需求
- 透過 uvx 從 provenza 的 PyPI 套件以本機程序方式執行。需要 PROVENZA_URL 指向自架的 Provenza 執行個體,首次啟動還需要管理員簽發的一次性註冊權杖 PROVENZA_TOKEN。可選 PROVENZA_AGENT_NAME 指定代理名稱(預設 mcp)。需要能連線到 Provenza 伺服器的網路。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Provenza,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
Provenza Python SDK
Governed, signed and auditable actions for AI agents.
What happens on a call
In connected mode (when PROVENZA_URL is set):
-
The SDK asks the server whether this call may run. The server checks the agent's rights, your organization's policies, the Tool Registry, behaviour, and the circuit breaker.
-
The tool runs only if the call is allowed. Otherwise:
- a denied call raises
ProvenzaDenied(aPermissionError); - a call that needs a human decision raises
ProvenzaApprovalRequired.
In both cases the attempt is recorded. Once a person approves the held call, make exactly the same call again: it runs once, within an hour.
- a denied call raises
-
The result is recorded and signed with the agent's own key. Provenza seals it into its signed audit log, so you can download a receipt for it that is verifiable offline.
The SDK fails closed: if the server cannot be reached, the tool does not
run and the SDK raises ProvenzaUnavailable. Pass fail_open=True to run
anyway and log the call locally as unchecked.
In standalone mode (no server), calls run and are written to a local,
signed, hash-chained audit log. You can restrict them with
allowed_tools=[...].
Only hashes of arguments and results are written to the local audit log, never the content.
Getting an identity
An admin issues a one-time enrollment token in Provenza (Agents → New agent). The agent's keys are generated on its own machine, and only the public key goes to the server:
The identity is stored in ~/.config/provenza/agents/<name>.json (mode
600). The SDK refuses to load it if other users can read it. It is the same
file tools/provenza_sign.py enroll writes, so you can enroll with the CLI
and run with the SDK.
To keep the private keys in the OS keychain instead:
For post-quantum hybrid keys (Ed25519 + ML-DSA-65):
agent.fingerprint is the value to give whoever verifies the agent's
signatures.
More
Async tools work the same way (async def). If a call ran but could not be
recorded on the server (the server went down mid-call), the SDK does not
hide the result. It writes a signed gap entry to the local audit log and
emits a ProvenzaWarning.
Latency
A governed call costs the SDK's own work plus round-trips to the server. The SDK's own work was measured against an in-process server (no network) on 2026-10-11:
Add your network round-trip (×2 or ×1) and the server's checks.
With "sync", the record is on the server when the tool returns.
With "background", records are sent from a queue, in order. A failure
becomes a signed gap in the local audit log, the same as in sync mode.
flush() / aflush() wait for the queue, and close() and interpreter
exit drain it. A process that is killed loses whatever is still
queued; that is the price of not waiting.
Refusals are always recorded before the exception is raised, so
ProvenzaDenied.action_id is known at once.
Auto-instrumentation
Every direct call from this process to an AI provider becomes a governed action. That covers the OpenAI, Anthropic, Mistral, Cohere and Gemini SDKs, LangChain's provider clients, or plain HTTP. The provider hosts come from your organization's AI domain catalog (Shadow AI), and the server decides each call:
Only the host, method, path (without the query string), and the hash and size of the body are recorded. The prompt is never recorded.
A refusal comes back as an HTTP answer: 403 with an OpenAI-style error
body and x-should-retry: false. Provider SDKs therefore raise their usual
permission error with Provenza's reason and do not retry. With the server
unreachable, nothing is sent (503). Other hosts, and calls to Provenza
itself, are untouched. provenza.auto.uninstrument() puts everything back.
Egress proxy
Behind a Provenza egress proxy (proxy/ in the repository) the agent has
two options. It can send its key and let the proxy check every request, or
it can check a request itself and send the check id:
path, query and body must be exactly what goes on the wire. The proxy
refuses any other request under that check. The proxy records the request,
so it is not passed to record().
agent.proxy_request_headers(...) (same arguments) returns the headers to
send: the check's, or, while Provenza is unreachable, only the agent's
signed request. A proxy that enforces the signed policy then judges it by
the signed release alone until its local kill switch stops it, and Provenza
records the request when it is back (docs/pvp/edge.md, section 6).
HTTP tools through Provenza
An API registered in Provenza (Gateways → HTTP tools) is called through Provenza, and the agent never holds its key. The call is checked, made and recorded in one step. A tool that takes a credential is called through the egress proxy, which holds it - Provenza itself holds no credential:
Through a proxy the HTTP request itself is signed too (X-Provenza-Request),
which a proxy in enforce mode requires on every path. For clients that cannot
sign (a stock OpenAI or MCP client) run the proxy's agent mode next to the
agent with this identity file (provenza-proxy -agent-identity …,
proxy/README.md).
Egress self-check
Is this host confined to the Provenza egress proxy, its only way out? Run
the check at start-up and then periodically. With Require confined egress
on, an agent acts only while its latest check is confined. See
docs/egress-lockdown.md.
Permits for tools
An allowed check carries a permit signed by the organization. The agent sends it with the call:
The tool runs nothing without a valid permit for exactly this call:
The verifier checks the signature against the organization's JWKS, the tool, the hash of the JSON body (it must be the checked input) and the expiry. It then redeems the permit with Provenza, so it is used once across every replica of the tool. If Provenza cannot be reached, it refuses.
Integrations
Each framework is an optional extra. The SDK never requires one: crewai
and autogen-core even need conflicting protobuf versions.
Through Provenza's gateways. The call goes through the server, which holds the provider credentials, so it is enforced whatever the agent's code does.
MCP clients that start a local command (Claude Desktop, Claude Code,
Cursor, Windsurf, Gemini CLI, VS Code): provenza-mcp is the same gateway
over stdio. Issue an enrollment token in Provenza (Agents → New agent)
and add:
On the first start the agent enrolls: its keys are made on that machine,
and the token can then be removed. The client sees only the tools an
administrator approved, and every call is checked against the
organization's policies and recorded. Set PROVENZA_AGENT_NAME to run more
than one agent on a machine.
Through the LLM gateway, the server checks allowed models and providers, policies and limits; it stores no prompt or answer. Every model the organization has routed (OpenAI, Anthropic, Azure, …) is reached through this one OpenAI-compatible endpoint. Streaming is not supported yet.
Tool wrappers. These keep the tool's name, description and argument schema, so the model sees no difference:
prefix= namespaces the names policies see, so prefix="kb." turns
search into kb.search. For anything else, govern a single call with
agent.call(name, arguments, lambda: ...) or await agent.acall(...).
What this is, and what it is not
The SDK runs inside your agent's process. It is the agent's honest record and cooperative enforcement: code in the same process could call a tool around it, and could read the agent's keys. Enforcement that does not depend on the agent's code comes from Provenza's gateways (LLM, MCP, A2A), which hold the credentials so the agent never has them.
Verify a local audit log with provenza.audit_log.verify(path, public_key).
Verify a server receipt with tools/provenza_audit.py receipt.
來源:sdk/python/README.md,提交 55affdc
工具
0版本歷史
1- v0.2.1最新Oct 26, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分