mcpField
P
Provenza

Provenza

ローカル
stickstock.lolセキュリティ51 日前に更新

Provenza について

Provenzaは、AIエージェントの操作を統制するPython SDKとゲートウェイで、権限とポリシーを確認し、署名付きの監査記録を作成します。ツール利用の承認と追跡が必要なチーム向けで、MCPクライアントはゲートウェイ経由で管理者承認済みのツールにアクセスできます。

主な機能

  1. 01エージェントの権限とポリシーに基づく呼び出し確認
  2. 02検証可能な署名付き監査記録
  3. 03人の承認を待つ呼び出しの保留
  4. 04スタンドアロン時の許可ツールへの制限
  5. 05HTTPとAIプロバイダーのリクエスト統制
  6. 06MCP経由での承認済みツール公開

活用シーン

  1. 01エージェントの機密操作に事前審査を要求
  2. 02エージェントのツール呼び出し記録を追跡・検証
  3. 03組織が承認したツールだけにエージェントを制限
  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 エージェントのための、ガバナンスが適用され、署名され、監査可能なアクションです。

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 は、この呼び出しを実行してよいかサーバーに問い合わせます。サーバーは、 エージェントの権限、組織のポリシー、Tool Registry、 動作、およびサーキットブレーカーを確認します。

  2. 呼び出しが許可された場合にのみ、ツールが実行されます。許可されない場合:

    • 拒否された呼び出しは ProvenzaDenied(PermissionError)を発生させます。
    • 人による判断が必要な呼び出しは ProvenzaApprovalRequired を発生させます。

    どちらの場合も、試行は記録されます。保留中の呼び出しを担当者が承認したら、 まったく同じ呼び出しをもう一度実行してください。1 時間以内に 1 回実行されます。

    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. 結果は記録され、エージェント自身の鍵で署名されます。Provenza は 署名付き監査ログに封印するため、オフラインで検証できる レシートをダウンロードできます。

SDK はフェイルクローズ方式です。サーバーに接続できない場合、ツールは実行されず、 SDK は ProvenzaUnavailable を発生させます。fail_open=True を渡すと、 ツールを実行し、未チェックの呼び出しとしてローカルに記録します。

スタンドアロンモード(サーバーなし)では、呼び出しが実行され、 署名付きのハッシュチェーン監査ログにローカルで書き込まれます。 allowed_tools=[...] を使って実行を制限できます。

ローカル監査ログに書き込まれるのは、引数と結果のハッシュのみであり、 内容そのものは記録されません。

ID の取得

管理者が Provenza(Agents → New agent)でワンタイム登録トークンを発行します。エージェントの鍵は自身のマシン上で 生成され、公開鍵のみがサーバーに送信されます。

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

ID は ~/.config/provenza/agents/<name>.json(モード 600)に保存されます。他のユーザーが読み取り可能な場合、SDK はその読み込みを拒否します。これは tools/provenza_sign.py enroll が書き込むファイルと同じなので、CLI で登録して SDK で実行できます。

秘密鍵を OS のキーチェーンに保存するには、次のようにします。

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 ドメインカタログ(Shadow AI)から取得され、各呼び出しをサーバーが判定します。

カタログのステータス結果
blocked拒否されます。インシデント ai_domain_blocked が記録されます
allowed送信されます。ただし、ポリシーによって拒否される場合を除きます
未分類送信されます。ただし、ポリシーによって拒否される場合を除きます。管理者が分類できるよう記録されます

記録されるのはホスト、メソッド、パス(クエリ文字列を除く)、および本文のハッシュとサイズのみです。プロンプトは記録されません。

拒否は HTTP の応答として返されます。ステータスコードは 403 で、OpenAI 形式のエラー本文と x-should-retry: false が含まれます。そのため、プロバイダー SDK は通常の権限エラーを Provenza の理由とともに発生させ、再試行しません。サーバーに接続できない場合、何も送信されず(503)、その他のホストと Provenza 自体への呼び出しには影響しません。provenza.auto.uninstrument() を実行すると、すべて元に戻ります。

エグレスプロキシ

Provenza のエグレスプロキシ(リポジトリ内の proxy/)を介する場合、エージェントには 2 つの選択肢があります。キーを送信してプロキシにすべてのリクエストを検査させるか、エージェント自身でリクエストを検査して検査 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 に接続できない間はエージェントの署名付きリクエストのみ)を返します。署名付きポリシーを適用するプロキシは、ローカルのキルスイッチで停止されるまで、署名付きリリースのみを基準にリクエストを判定します。Provenza は復旧後にリクエストを記録します(docs/pvp/edge.md のセクション 6)。

Provenza 経由の HTTP ツール

Provenza に登録された API(Gateways → HTTP tools)は Provenza 経由で呼び出されるため、エージェントがキーを保持することはありません。呼び出しは検査、実行、記録が一度に行われます。認証情報を必要とするツールはエグレスプロキシ経由で呼び出され、認証情報はプロキシが保持します。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 クライアントなど、署名できないクライアントの場合は、この ID ファイルを使ってエージェントのそばでプロキシのエージェントモードを実行してください(provenza-proxy -agent-identity …、proxy/README.md)。

エグレスの自己検査

このホストは Provenza のエグレスプロキシに制限され、唯一の外部接続手段になっていますか? 起動時と、その後も定期的に検査を実行してください。Require confined egress が有効な場合、エージェントは最新の検査結果が confined のときにのみ動作します。docs/egress-lockdown.md を参照してください。

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

ツール用許可証

許可された検査には、組織が署名した許可証が含まれます。エージェントは呼び出しとともにこれを送信します。

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 のゲートウェイ経由。 呼び出しはサーバー経由で行われ、サーバーがプロバイダーの認証情報を保持するため、エージェントのコードの動作にかかわらず適用されます。

# 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_..."}}}}

初回起動時にエージェントが登録されます。キーはそのマシン上で生成されるため、その後トークンを削除できます。クライアントに表示されるのは管理者が承認したツールのみで、すべての呼び出しは組織のポリシーに照らして確認され、記録されます。1 台のマシンで複数のエージェントを実行するには、PROVENZA_AGENT_NAMEを設定します。

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 はエージェントのプロセス内で実行されます。これはエージェントの正確な記録であり、協調的な適用手段です。同じプロセス内のコードは SDK を介さずにツールを呼び出すことも、エージェントのキーを読み取ることもできます。エージェントのコードに依存しない適用は、Provenza のゲートウェイ(LLM、MCP、A2A)によって行われます。ゲートウェイが認証情報を保持するため、エージェントがそれらを持つことはありません。

provenza.audit_log.verify(path, public_key)でローカルの監査ログを検証します。 tools/provenza_audit.py receiptでサーバーのレシートを検証します。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。