mcpField
P
Provenza

Provenza

本地服务
stickstock.lol安全51 天前更新

关于 Provenza

Provenza 为 AI Agent 操作提供治理层,包含 Python SDK 和网关,可检查权限与策略并生成签名审计记录。它面向需要审批工具访问和追踪调用的团队;MCP 客户端可经网关访问管理员批准的工具。

主要功能

  1. 01根据 Agent 权限和策略检查调用
  2. 02生成可验证的签名审计记录
  3. 03将调用暂挂以等待人工审批
  4. 04将独立模式调用限制在允许的工具内
  5. 05治理 HTTP 请求和 AI 提供商请求
  6. 06通过 MCP 暴露获批工具

适用场景

  1. 01要求 Agent 执行敏感操作前先经审核
  2. 02追踪并验证 Agent 工具调用记录
  3. 03将 Agent 限定为使用组织批准的工具
  4. 04通过策略检查的访问路径连接 MCP 客户端

MCP 相关

MCP 客户端可连接 Provenza 网关,访问经管理员批准、调用经过策略检查并记录的工具。`provenza-mcp` 命令通过 stdio 为启动本地进程的客户端提供网关。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"kironovlaziz-del-provenza": {
"command": "uvx",
"args": [
"provenza"
],
"env": {
"PROVENZA_URL": "<PROVENZA_URL>",
"PROVENZA_TOKEN": "<PROVENZA_TOKEN>",
"PROVENZA_AGENT_NAME": "<PROVENZA_AGENT_NAME>"
}
}
}
}
启动命令uvx provenza
需要配置的环境变量
PROVENZA_URLYour self-hosted Provenza, e.g. https://provenza.example.com
PROVENZA_TOKEN密钥One-time enrollment token (Agents -> New agent); needed on the first start only
PROVENZA_AGENT_NAMEAgent name on this machine (default: mcp)

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypiprovenza0.2.1

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

Provenza Python SDK

为 AI Agent 提供受治理、已签名且可审计的操作。

pip install provenza
from provenza import Agent

agent = Agent("support-bot")   # reads PROVENZA_URL and PROVENZA_TOKEN

@agent.tool(name="zendesk.read")
def open_tickets(status: str = "open") -> list:
    return zendesk.tickets.list(status=status)

open_tickets()   # checked by Provenza, run, recorded and signed

调用时会发生什么

在连接模式下(设置了 PROVENZA_URL 时):

  1. SDK 会向服务端询问是否可以执行此次调用。服务端会检查 Agent 的权限、组织策略、工具注册表、 行为以及断路器。

  2. 只有在调用获准后,工具才会运行。否则:

    • 被拒绝的调用会引发 ProvenzaDenied(一个 PermissionError);
    • 需要人工决策的调用会引发 ProvenzaApprovalRequired。

    两种情况下,尝试都会被记录。有人批准暂缓的调用后,完全相同 的调用只需重新执行一次:它会在一小时内运行。

    try:
        send_report(to="[email protected]")
    except ProvenzaApprovalRequired as held:
        if agent.wait_for_approval(held.action_id)["decision"] == "approved":
            send_report(to="[email protected]")      # the same call: runs once
    
  3. 结果会被记录,并使用 Agent 自己的密钥签名。Provenza 会将其封存到已签名的审计日志中,因此你可以下载一份可离线验证的回执。

SDK 会默认拒绝:如果无法连接服务端,工具不会运行,SDK 会引发 ProvenzaUnavailable。传入 fail_open=True,即可继续运行,并在本地将调用记录为未经检查。

在独立模式下(没有服务端),调用会运行,并写入本地的 签名哈希链审计日志。你可以通过 allowed_tools=[...] 限制可用工具。

本地审计日志只会写入参数和结果的哈希值, 不会写入内容。

获取身份

管理员会在 Provenza 中签发一次性注册令牌(Agents → New agent)。Agent 的密钥会在其自己的机器上生成,只有公钥会发送到服务端:

export PROVENZA_URL=https://provenza.example.com
export PROVENZA_TOKEN=pvz_enr_...      # used once; afterwards the identity file is enough

身份信息存储在 ~/.config/provenza/agents/<name>.json(权限模式 600)中。如果其他用户可以读取该文件,SDK 会拒绝加载。tools/provenza_sign.py enroll 写入的也是同一个 文件,因此你可以使用 CLI 注册,然后使用 SDK 运行。

若要改为将私钥存储在操作系统钥匙串中:

pip install 'provenza[keychain]'
Agent("bot", key_store="keychain")

若要使用后量子混合密钥(Ed25519 + ML-DSA-65):

pip install 'provenza[pq]'
Agent("bot", hybrid=True)

agent.fingerprint 是你提供给签名验证者的值。

更多信息

with agent.chain(chain_id):            # act inside a delegation chain
    open_tickets()

agent.delegate(other_agent_id, "summarize Q3", ["read"], tools=["db.read"], expires_in=600)

chk = agent.check("files.delete", {"path": p})   # ask for something that is not a decorated tool
if chk.allowed:
    delete(p)
    agent.record(chk, {"deleted": True})

异步工具的用法相同(async def)。如果调用已运行,但无法在服务端记录(服务端在调用期间宕机),SDK 不会 隐藏结果。它会在本地审计日志中写入一条已签名的缺口记录,并发出 ProvenzaWarning。

延迟

受治理的调用耗时包括 SDK 自身的处理时间,以及与服务端的往返通信。 SDK 自身的处理时间是在进程内服务端(无网络)上于 2026-10-11 测得的:

record_mode工具返回前的往返次数中位数p95
"sync"(默认)2(检查、记录)0.42 ms0.59 ms
"background"1(检查)0.15 ms0.33 ms

再加上网络往返时间(×2 或 ×1)以及服务端的检查时间。

使用 "sync" 时,工具返回时记录已写入服务端。

使用 "background" 时,记录会按顺序从队列发送。发送失败时, 会在本地审计日志中生成一条已签名的缺口记录,与同步模式相同。 flush() / aflush() 会等待队列处理完毕,close() 和解释器 退出时也会清空队列。进程若被强制终止,尚在队列中的内容会丢失;这就是不等待的代价。

拒绝调用总会在引发异常前记录,因此 ProvenzaDenied.action_id 会立即可用。

自动插桩

import provenza.auto
provenza.auto.instrument(agent)        # httpx (sync and async) and requests

此进程直接向 AI 提供商发出的每个调用都会成为受治理的操作。这涵盖 OpenAI、Anthropic、Mistral、Cohere 和 Gemini SDK、LangChain 的提供商客户端,以及普通 HTTP。提供商主机来自组织的 AI 域名目录(影子 AI),由服务端决定每次调用的处理方式:

目录状态结果
blocked拒绝;事件为 ai_domain_blocked
allowed发送,除非策略拒绝
未分类发送,除非策略拒绝;记录下来供管理员分类

记录的内容仅包括主机、方法、不含查询字符串的路径,以及请求正文的哈希和大小。提示词绝不会被记录。

拒绝会以 HTTP 响应返回:状态码 403,包含 OpenAI 风格的错误正文,并带有 x-should-retry: false。因此,提供商 SDK 会按常规抛出权限错误,其中包含 Provenza 给出的原因,且不会重试。如果无法连接服务端,则不会发送任何内容(503)。其他主机以及对 Provenza 本身的调用不受影响。provenza.auto.uninstrument() 会恢复所有设置。

出站代理

在 Provenza 出站代理(仓库中的 proxy/)后,Agent 有两种选择:发送自己的密钥,由代理检查每个请求;或者自行检查请求,再发送检查 ID:

body = json.dumps({"amount": 1000}).encode()
chk = agent.proxy_check("stripe", "POST", "/v1/charges", body=body)
if chk.allowed:
    httpx.post("http://127.0.0.1:8443/stripe/v1/charges", content=body, headers=chk.proxy_headers)

path、query 和 body 必须与实际上网发送的内容完全一致。代理会拒绝任何与该检查不符的请求。代理会记录请求,因此不会将其传递给 record()。

agent.proxy_request_headers(...)(参数相同)会返回要发送的请求头:检查对应的请求头,或者在无法连接 Provenza 时,仅返回 Agent 的签名请求。强制执行已签名策略的代理会在本地紧急停用开关将其停止之前,仅依据已签名的发布版本进行判断;Provenza 恢复后会记录请求(docs/pvp/edge.md,第 6 节)。

通过 Provenza 使用 HTTP 工具

在 Provenza 中注册的 API(网关 → HTTP 工具)通过 Provenza 调用,Agent 无需持有其密钥。调用会在一个步骤中完成检查、执行和记录。需要凭据的工具通过持有该凭据的出站代理调用;Provenza 本身不持有任何凭据:

agent = Agent("billing-bot", egress_proxy="http://127.0.0.1:8443")   # or PROVENZA_EGRESS_PROXY
out = agent.invoke("crm.set_tier", {"id": "42", "tier": "gold"})
out["status"], out["body"]          # a refusal raises ProvenzaDenied
agent.http_tools()                  # names, descriptions and input schemas, for the model

通过代理发送时,HTTP 请求本身也会签名(X-Provenza-Request),强制模式下的代理要求每个路径都必须带有此签名。对于无法签名的客户端(标准 OpenAI 或 MCP 客户端),请使用此身份文件在 Agent 旁运行代理的 Agent 模式(provenza-proxy -agent-identity …,proxy/README.md)。

出站自检

此主机是否仅能通过 Provenza 出站代理访问外部?请在启动时运行检查,然后定期检查。启用要求限制出站流量后,Agent 仅在最近一次检查结果为 confined 时运行。请参阅 docs/egress-lockdown.md。

agent.egress_selfcheck()     # {"verdict": "confined" | "open", ...}

工具许可凭证

允许的检查会附带由组织签名的许可凭证。Agent 会随调用一并发送:

chk = agent.check("crm.update", payload)
if chk.allowed:
    httpx.post("https://crm-tool.internal/update", json=payload, headers=chk.permit_headers)
    agent.record(chk, output)

工具在未获得针对该调用的有效许可凭证时不会执行任何操作:

from provenza.permit import PermitMiddleware, PermitVerifier, require_permit

verifier = PermitVerifier("https://provenza.example.com", org="acme")
app = PermitMiddleware(app, verifier, tool="crm.update")   # any ASGI app: FastAPI, Starlette, ...

@require_permit(verifier, "db.read")                         # or a plain function
def read(query: str): ...

验证器会根据组织的 JWKS 检查签名、工具、JSON 正文的哈希(必须与已检查的输入一致)以及有效期。随后,它会向 Provenza兑付许可凭证,确保该凭证在该工具的所有副本间只能使用一次。如果无法连接 Provenza,则会拒绝。

集成

每个框架都是可选的附加项。SDK 不依赖任何框架:crewai 和 autogen-core 甚至需要彼此冲突的 protobuf 版本。

通过 Provenza 的网关。 调用会经过服务端,由服务端持有提供方凭据,因此无论 Agent 的 代码如何操作,都会强制执行策略。

# pip install 'provenza[openai]'
from provenza.integrations.openai import gateway_client, wrap
client = gateway_client(agent)              # an openai.OpenAI pointed at the LLM gateway, with the agent's key
client = wrap(existing_client, agent)       # or a copy of one you already configured

# MCP: no extra needed. Point any MCP client at Provenza instead of at the servers.
from provenza.integrations.mcp import connection, client_config
conn = connection(agent)                    # {"url": ".../api/v1/mcp", "headers": {...}}

启动本地命令的 MCP 客户端(Claude Desktop、Claude Code、 Cursor、Windsurf、Gemini CLI、VS Code):provenza-mcp 是通过 stdio 提供的同一网关。 在 Provenza 中创建注册令牌(Agents → New agent),然后添加:

{"mcpServers": {"provenza": {
  "command": "uvx", "args": ["provenza-mcp"],
  "env": {"PROVENZA_URL": "https://provenza.example.com", "PROVENZA_TOKEN": "pvz_enr_..."}}}}

首次启动时,Agent 会注册:它的密钥会在该机器上生成,之后即可移除令牌。客户端只能看到管理员批准的工具,而且每次调用都会根据组织的策略进行检查并记录。设置 PROVENZA_AGENT_NAME,即可在一台机器上运行多个 Agent。

通过 LLM 网关,服务端会检查允许使用的模型和提供方、策略及限制;它不会存储提示词或回答。组织已路由的所有模型(OpenAI、Anthropic、Azure、……)都可通过这一个兼容 OpenAI 的端点访问。目前尚不支持流式传输。

工具包装器。 这些包装器会保留工具的名称、描述和参数架构,因此模型看到的内容不会有差异:

# pip install 'provenza[langchain]'
from provenza.integrations.langchain import govern_tools
tools = govern_tools(agent, [search, read_file])        # a refusal reaches the model as the tool's answer

# pip install 'provenza[autogen]'
from provenza.integrations.autogen import govern_tools
tools = govern_tools(agent, [FunctionTool(lookup, description="...")])

# pip install 'provenza[crewai]'
from provenza.integrations.crewai import govern_tools
researcher = crewai.Agent(role="...", goal="...", tools=govern_tools(agent, [search_tool]))

prefix= 会为策略所见的名称添加命名空间,因此 prefix="kb." 会将 search 转换为 kb.search。对于其他情况,可使用 agent.call(name, arguments, lambda: ...) 或 await agent.acall(...) 管控单次调用。

这是什么,以及它不是什么

SDK 在 Agent 的进程内运行。它是 Agent 的如实记录和协作式强制执行机制:同一进程中的代码可以绕过它调用工具,也可以读取 Agent 的密钥。不依赖 Agent 代码的强制执行由 Provenza 的网关(LLM、MCP、A2A)提供,网关持有凭据,因此 Agent 永远不会持有这些凭据。

使用 provenza.audit_log.verify(path, public_key) 验证本地审计日志。 使用 tools/provenza_audit.py receipt 验证服务端回执。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。