mcp-opa-authz について
mcp-opa-authzは、ローカルのRego評価またはAuthZEN 1.0 PDPを使って認可を確認するMCPサーバーです。ポリシーのデバッグやPDPの判断確認に向け、拒否・未定義・リクエスト失敗を区別します。
主な機能
- 01Regoポリシーのローカル評価
- 02定義状態と戻り値の確認
- 03PDPへの単件・一括判定
- 04許可された主体・リソース・操作の検索
- 05PDPエンドポイントの検出
- 06サンドボックスでのポリシー実行
活用シーン
- 01入力データを使ったRegoポリシーのデバッグ
- 02PDPに対する認可判断の確認
- 03許可されたリソースや主体の一覧表示
- 04PDPの機能とエンドポイントの確認
MCP 対応
ローカルRego評価、AuthZENの判定・検索、PDP検出を行う5種類の認可ツールをMCPクライアントに公開します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
docker run -i --rm -e AUTHZEN_PDP_URL -e AUTHZEN_PDP_TOKEN -e AUTHZEN_PDP_TIMEOUT -e MCP_OPA_EVAL_TIMEOUT -e MCP_OPA_ALLOW_NETWORK_BUILTINS ghcr.io/kanywst/mcp-opa-authz:0.6.2AUTHZEN_PDP_URLシークレットDefault AuthZEN Access Evaluation endpoint, e.g. https://pdp.example.com/access/v1/evaluation. Only evaluate_policy works without it.AUTHZEN_PDP_TOKENシークレットAuthorization header value for the PDP. A value with no scheme is sent as "Bearer <token>".AUTHZEN_PDP_TIMEOUTシークレットPer-request timeout for PDP calls, as a Go duration. Default 10s.MCP_OPA_EVAL_TIMEOUTWall-clock limit on a single Rego evaluation, as a Go duration. Default 5s.MCP_OPA_ALLOW_NETWORK_BUILTINSRe-enable http.send, net.lookup_ip_addr and opa.runtime inside evaluated policies. Off by default: policy source evaluated here comes from a model and runs inside the server process.ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ghcr.io/kanywst/mcp-opa-authz:0.6.2stdioツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
mcp-opa-authz
エージェントに認可を推測させるのはやめましょう。 これは、実際のポリシーコード、つまり渡した Rego、またはシステムを実際に統制する OpenID AuthZEN 1.0 PDP に基づいて、「これは許可されているか?」に回答する MCP サーバーです。
モデルに「Alice はそのドキュメントを削除してよいか」と尋ねると、自信に満ちた、もっともらしく、反証できない答えを返します。これらのツールを与えれば、答えはポリシーに基づくものになります。
brew install kanywst/tap/mcp-opa-authz
# or, without Homebrew:
go install github.com/kanywst/mcp-opa-authz@latest
claude mcp add opa-authz -- mcp-opa-authz
これで evaluate_policy を使うには十分です。PDP を指定すると、残りのツールも使えるようになります。
claude mcp add opa-authz \
--env AUTHZEN_PDP_URL=http://localhost:8181/access/v1/evaluation \
-- mcp-opa-authz
2 つのレイヤー、同じ問い
| ツール | 回答内容 | 必要なもの |
|---|---|---|
evaluate_policy | 「この Rego は何を示していますか?」OPA によってプロセス内で評価されます。 | 外部のものは不要 |
authzen_evaluate | 「このシステムを統制する PDP は何を示していますか?」 | 接続可能な PDP |
authzen_evaluate_batch | 同じ問いをリストに対して行います。対象のうち、サブジェクトがアクセスできるのはどれですか? | 接続可能な PDP |
authzen_search | 「誰が…できるか」「どのリソースに…できるか」「何が…できるか」――PDP が許可されているものを一覧表示します。 | Search API を備えた PDP |
authzen_discover | 「この PDP が提供するエンドポイントはどれですか?」 | 接続可能な PDP |
ソースが手元にあるポリシーの作成やデバッグには evaluate_policy を使います。判断をチャットに貼り付けたポリシーではなく、本番環境から得る必要がある場合は authzen_evaluate を使います。サーバーの MCP インストラクションもモデルに同じことを伝えるため、通常はモデル自身が適切なツールを選びます。
シェルツールでの opa eval との違い
シェルへのアクセスを与えれば、エージェントはすでに opa eval を実行できます。しかし、信頼してよい回答を得ることはできません。
- 未定義は false ではありません。 一致するルールもデフォルトもない Rego クエリは
[]を返します。すべてのモデルはこれを deny と解釈します。evaluate_policyはvalueとともにdefinedも返すため、「ポリシーが拒否した」と「ポリシーに判断がない」が同じ回答として扱われなくなります。 - 回答しなかった PDP は deny ではありません。 AuthZEN では
decisionは必須メンバーです。これを欠くレスポンスを Go のboolにデコードするとfalseになり、壊れた PDP が厳格な PDP のように見えてしまいます。このサーバーはdecisionがない場合、deny ではなく失敗として扱います。401 も同様です。これはサブジェクトが拒否されたのではなく、このサーバー の認証に失敗したことを意味し、エラーでその旨を示します。 - ポリシーはサンドボックス内で実行されます。 MCP サーバーに渡される Rego は、ウェブページ由来かもしれないテキストをもとにモデルが作成したものです。OPA の
http.sendを使えば、そのポリシーからノートパソコン上で任意の HTTP リクエストを送信でき、opa.runtime()を使えば環境を渡してしまいます。どちらもコンパイル時に除外されています。セキュリティを参照してください。 - 一括判定にはインデックスが付与されます。
permit_on_first_permitが送信した数より少ない判定を返すのは正当な動作です。配列を順に結合すると、判定が誤ったリソースに紐付けられてしまいます。 - 検索結果が空でも検索失敗ではありません。
results: []は許可されたものがないことを意味します。resultsメンバーのないレスポンス、またはエンティティタイプが誤った結果はエラーです。
デモ
本来は拒否されないはずのポリシーが拒否している場合のデバッグ:
> Why is bob getting denied on doc-1? Here's the policy and the input.
evaluate_policy(rego=…, query="data.rbac.allow", input_json=…, trace=true)
{
"defined": true,
"value": false,
"printed": ["checking roles for", "bob"],
"trace": [
"Enter data.rbac.allow",
"| Eval some role in roles[input.user]",
"| Fail roles[\"bob\"]",
…
]
}
Bob has no entry in `roles` at all — the rule never reaches the permission
check. Adding "bob": {"viewer"} fixes it.
次に、実際に実行されている PDP に対して確認します。
> Does production agree?
authzen_evaluate(subject={"type":"user","id":"bob"}, …)
{ "decision": false, "context": { "reason": "no role binding" },
"request_id": "3f9c…", "pdp_url": "https://pdp.internal/access/v1/evaluation" }
ツール
evaluate_policy
| Param | Required | Description |
|---|---|---|
rego | はい | package 宣言を含む Rego ソースです。 |
query | はい | Rego クエリです。例:data.example.allow |
input_json | いいえ | JSON エンコードされた input ドキュメントです。 |
data_json | いいえ | data 名前空間用の、JSON エンコードされたベースドキュメントです。 |
rego_version | いいえ | v1(デフォルト)または、OPA 1.0 より前の構文用の v0 です。 |
trace | いいえ | 整形された評価トレースを返します。詳細な出力です。上限は4000イベント、200行、1行あたり1 KiBです。 |
defined、value、OPA の生の result_set(エンコード後に256 KiBを超える場合は省略され、result_set_omitted が返されます)、print() の出力(200行、1行あたり1 KiB)、および要求された場合はトレースを返します。
authzen_evaluate
| Param | Required | Description |
|---|---|---|
subject | はい | JSON オブジェクトです。AuthZEN では type と id が必須です。 |
action | はい | JSON オブジェクトです。AuthZEN では name が必須です。 |
resource | はい | JSON オブジェクトです。AuthZEN では type と id が必須です。 |
context | いいえ | 実行時コンテキスト(IP、時刻、MFA の強度)を含む JSON オブジェクトです。 |
pdp_url | いいえ | この呼び出しで AUTHZEN_PDP_URL を上書きします。 |
decision、PDP の context(存在する場合)、応答した pdp_url、および X-Request-ID として送信された request_id を返します。これにより、トランスクリプト内の判断を PDP のログで検索できます。
authzen_evaluate_batch
同じ引数に加えて、evaluations(各エントリがトップレベルのデフォルトを上書きする JSON 配列)と evaluations_semantic(execute_all、deny_on_first_deny、permit_on_first_permit)を指定します。1回の呼び出しにつき最大100件です。pdp_url を指定しない場合、エンドポイントには、PDP がメタデータで通知する access_evaluations_endpoint を使用します。通知がない場合は、AUTHZEN_PDP_URL のルート配下にある /access/v1/evaluations を使用します。これは authzen_search と同じ解決方法、キャッシュ、同一オリジンのルールに従います。結果の endpoint_source に、使用したエンドポイントが示されます。
{
"subject": "{\"type\":\"user\",\"id\":\"alice\"}",
"action": "{\"name\":\"read\"}",
"evaluations": "[{\"resource\":{\"type\":\"doc\",\"id\":\"1\"}},{\"resource\":{\"type\":\"doc\",\"id\":\"2\"}}]"
}
authzen_search
AuthZEN Search API です。search で一覧表示するエンティティを選択します。そのエンティティには type のみを指定します。
search | 尋ねる内容 | subject | action | resource |
|---|---|---|---|---|
subject | このリソースに対して、誰が操作できますか? | type のみ | 必須 | type と id |
resource | このタイプのリソースのうち、subject が操作できるものはどれですか? | type と id | 必須 | type のみ |
action | subject は resource に対して何をできますか? | type と id | 省略必須 | type と id |
context、pdp_url、page_limit、page_token は任意です。pdp_url を指定しない場合は、仕様で定められているとおり、PDP がメタデータで通知するエンドポイント(search_subject_endpoint など)を使用します。有効なメタデータがない場合は、AUTHZEN_PDP_URL のルート配下にあるデフォルトパス(/access/v1/search/{subject,resource,action})にフォールバックします。メタデータは PDP ごとに5分間キャッシュされ、結果の endpoint_source に使用したエンドポイントが示されます。通知されたエンドポイントは PDP 自身のオリジン上になければなりません。PDP のトークンはリクエストとともに送信されるためです。別オリジンのエンドポイントは、pdp_url として明示的に渡さない限り拒否されます。results、has_more、next_page_token を返します。次のページを取得するには、ほかのすべての引数を変更せずに、トークンを page_token として渡してください。page オブジェクトに next_token がないレスポンスはエラーです。仕様の例には next_token がありますが、これがなければリストが完了しているかどうかを判断できません。
{
"search": "resource",
"subject": "{\"type\":\"user\",\"id\":\"alice\"}",
"action": "{\"name\":\"read\"}",
"resource": "{\"type\":\"document\"}"
}
authzen_discover
PDP のルートから /.well-known/authzen-configuration を取得します。pdp_url にはルートまたは評価エンドポイントを指定できます。既知の AuthZEN パスのサフィックスは取り除かれます。プレフィックス配下にマウントされた PDP の場合、RFC 8615 と仕様の規定どおり、ホストとプレフィックスの間に well-known 文字列が入ります(https://gw.example.com/.well-known/authzen-configuration/pdp)。この形式が404を返した場合は、以前の形式(…/pdp/.well-known/authzen-configuration)も試します。policy_decision_point が取得元のルートと一致しないドキュメントは、仕様の規定どおり拒否されます。
標準への準拠
Authorization API 1.0 を実装しています。これは2026年1月に OpenID 最終仕様として承認されました。
| セクション | ステータス |
|---|---|
アクセス評価(POST /access/v1/evaluation) | authzen_evaluate |
アクセス評価、一括(POST /access/v1/evaluations) | authzen_evaluate_batch |
PDP メタデータ(GET /.well-known/authzen-configuration) | authzen_discover |
| Subject/Action/Resource 情報モデル | リクエスト送信前に必須メンバーを検証します |
X-Request-ID による相関 | すべての呼び出しで送信し、結果に含めて返します |
| 検索 API(Subject/Resource/Action、ページネーション対応) | authzen_search |
関連情報として知っておくとよいのは、AuthZEN ワーキンググループの COAZ プロファイルが AuthZEN を MCP ツール呼び出し自体に結び付ける点です。これにより、ゲートウェイはツールの inputSchema で宣言された x-authzen-mapping を使って tools/call を認可できます。これは同じ問題の強制側にあたります。このサーバーは検査側であり、両者を組み合わせて利用できます。
設定
| 変数 | デフォルト | 説明 |
|---|---|---|
AUTHZEN_PDP_URL | — | デフォルトのアクセス評価エンドポイントです。 |
AUTHZEN_PDP_TOKEN | — | Authorization ヘッダーの値です。スキームのない値は Bearer <token> として送信されます。 |
AUTHZEN_PDP_TIMEOUT | 10s | リクエストごとのタイムアウトです。 |
AUTHZEN_PDP_MAX_RESPONSE_BYTES | 1048576 | レスポンスの読み取り上限です。 |
MCP_OPA_EVAL_TIMEOUT | 5s | 1 回の Rego 評価に対する実時間の上限です。 |
MCP_MAX_ARG_BYTES | 1048576 | 引数ごとのサイズ上限です。 |
MCP_OPA_ALLOW_NETWORK_BUILTINS | false | ネットワーク組み込み関数を再度有効にします。詳細は以下をご覧ください。 |
不正な値が設定されている場合、デフォルト値に黙って置き換えるのではなく、サーバーの起動を停止します。オペレーターが設定されていると考えている制限は、実際に有効でなければなりません。
セキュリティ
evaluate_policy は、モデルが生成した Rego をこのプロセス内でコンパイルして実行します。そのため、3 つの OPA 組み込み関数を機能セットから削除しています。
| 組み込み関数 | 理由 |
|---|---|
http.send | サーバーが実行されている場所(ラップトップや CI ランナーなど)から、その背後にあるあらゆるネットワーク境界内へ任意の HTTP リクエストを送信できます。SSRF の攻撃対象領域そのものであり、このツール自身の説明とも矛盾します。 |
net.lookup_ip_addr | 到達可能なポートがなくても、DNS ラベルを 1 つずつ使って input を外部に送信できます。 |
opa.runtime | プロセス環境や、そこに含まれるすべての認証情報を含むランタイム設定を返します。 |
時間、JWT、UUID、乱数の組み込み関数はそのまま利用できます。これらは実際の認可ポリシーで使われます。削除された組み込み関数を使用するポリシーは、その名前を示すメッセージとともにコンパイルに失敗します。本当に必要な場合に備えて、MCP_OPA_ALLOW_NETWORK_BUILTINS も案内されます。
PDP クライアントにも制約を設けています。pdp_url はホストを持つ絶対 http(s) URL で、userinfo を含めることはできません。Authorization ヘッダーを付けたままリダイレクトを追跡するのではなく、リダイレクトを拒否します。レスポンスはバイト数の上限を設けて読み込み、PDP のエラーボディーはモデルのコンテキストに渡す前に切り詰めます。
脆弱性の報告については、SECURITY.md をご覧ください。
実行方法
ソースから
make smoke
バイナリをビルドし、偽の AuthZEN PDP を起動して、実際の MCP stdio セッションを通じて 5 つすべてのツールを実行し、それぞれが応答したことを検証します。http.send が引き続き拒否されることも含みます。MCP クライアントも実際の PDP も必要ありません。
コンテナー
docker run -i --rm \
-e AUTHZEN_PDP_URL=https://pdp.example.com/access/v1/evaluation \
ghcr.io/kanywst/mcp-opa-authz
Cursor およびその他の MCP クライアント
{
"mcpServers": {
"opa-authz": {
"command": "mcp-opa-authz",
"env": { "AUTHZEN_PDP_URL": "http://localhost:8181/access/v1/evaluation" }
}
}
}
:8181 で実行するローカルの opa-authzen-plugin を PDP として利用できます。Topaz、Cerbos、実験的な AuthZEN サポートを備えた Keycloak、または相互運用性リストに掲載されているその他のサービスも利用できます。
例
examples/ には、evaluate_policy 用の Rego ポリシーの参考例があります。
rbac.rego— ロールと権限のマッピングabac.rego— クリアランスレベルの比較k8s_admission.rego— アドミッション制御:必須ラベル
ディレクトリ構成
意図的にフラットな構成にしています。単一バイナリの MCP サーバーに cmd/、internal/、pkg/ は必要ありません。
main.go server bootstrap, CLI, tool registration
config.go environment, bounds, defaults
args.go tool argument decoding
tool_opa.go evaluate_policy
opa_capabilities.go the Rego sandbox
authzen.go AuthZEN 1.0 wire types and PDP client
tool_authzen.go authzen_evaluate, _batch, _discover
tool_authzen_search.go authzen_search
scripts/smoke.sh end-to-end MCP session
リリースの検証
リリースには、cosign で署名されたチェックサムファイル(GitHub OIDC による Sigstore のキーレス署名)と、アーカイブごとの CycloneDX SBOM が含まれています。署名と証明書は、*-checksums.txt.sigstore.json という 1 つの Sigstore バンドルにまとめられています。
TAG=v0.3.0
gh release download "$TAG" -R kanywst/mcp-opa-authz -p '*-checksums.txt*'
cosign verify-blob \
--bundle "mcp-opa-authz-${TAG#v}-checksums.txt.sigstore.json" \
--certificate-identity-regexp 'https://github.com/kanywst/mcp-opa-authz/.github/workflows/release.yml@refs/tags/' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
"mcp-opa-authz-${TAG#v}-checksums.txt"
次に、ダウンロードしたアーカイブをそのファイルと照合します。
sha256sum -c "mcp-opa-authz-${TAG#v}-checksums.txt" --ignore-missing
貢献
Issue やプルリクエストを歓迎します。CONTRIBUTING.md をご覧ください。最初の貢献に適したものとして、別のポリシー例、このプロジェクトでまだ試していない PDP、AuthZEN の仕様との差異への対応などがあります。
このリポジトリは、以前の 0-draft/mcp-opa と 0-draft/mcp-authzen を統合したものです。両方の履歴はここに引き継がれています。
ライセンス
MIT です。LICENSE をご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。