mcpField
M
mcp-opa-authz

mcp-opa-authz

本地服务
github.com安全13 天前更新

关于 mcp-opa-authz

mcp-opa-authz 是用于通过本地 Rego 求值或 AuthZEN 1.0 PDP 检查授权的 MCP 服务,适合调试策略及核验 PDP 决策,并区分拒绝、未定义结果和请求失败。

主要功能

  1. 01本地求值 Rego 策略
  2. 02查看定义状态与返回值
  3. 03查询单项及批量 PDP 决策
  4. 04搜索获准的主体、资源和操作
  5. 05发现 PDP 端点
  6. 06在沙箱中运行策略

适用场景

  1. 01结合输入数据调试 Rego 策略
  2. 02向 PDP 核验授权决策
  3. 03列出获准的资源或主体
  4. 04检查 PDP 功能与端点

MCP 相关

向 MCP 客户端提供五类授权工具:本地 Rego 求值、AuthZEN 决策查询与搜索,以及 PDP 发现。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"kanywst-mcp-opa-authz": {
"command": "docker",
"args": [
"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.2"
],
"env": {
"AUTHZEN_PDP_URL": "<AUTHZEN_PDP_URL>",
"AUTHZEN_PDP_TOKEN": "<AUTHZEN_PDP_TOKEN>",
"AUTHZEN_PDP_TIMEOUT": "<AUTHZEN_PDP_TIMEOUT>",
"MCP_OPA_EVAL_TIMEOUT": "<MCP_OPA_EVAL_TIMEOUT>",
"MCP_OPA_ALLOW_NETWORK_BUILTINS": "<MCP_OPA_ALLOW_NETWORK_BUILTINS>"
}
}
}
}
启动命令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.2
需要配置的环境变量
AUTHZEN_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+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
ocighcr.io/kanywst/mcp-opa-authz:0.6.2

工具

还没有获取到工具列表

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

详细介绍

mcp-opa-authz

ci Go Reference Go Report Card License: MIT

别再让 Agent 猜测授权结果。 这是一个 MCP 服务,可根据实际策略代码回答“是否允许?”——策略代码可以是你提供的 Rego,也可以是实际管理你系统的 OpenID AuthZEN 1.0 PDP。

询问模型 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

两层能力,同一个问题

工具回答的问题所需条件
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 指令也会告诉模型这一点,因此模型通常会自行正确选择。

与 Shell 工具中的 opa eval 有何不同

拥有 Shell 访问权限的 Agent 已经可以运行 opa eval。但它无法得到一个可以信赖的答案:

  • 未定义不等于 false。 Rego 查询没有匹配规则且没有默认值时,会返回 []。所有模型都会将其理解为拒绝。evaluate_policy 会同时返回 defined 和 value,因此“策略拒绝了”和“策略没有给出意见”不再是同一个答案。
  • PDP 未作答不等于拒绝。 AuthZEN 要求必须包含 decision 成员。缺少该成员的响应会被解码为 Go bool 类型的 false——有问题的 PDP 看起来就像严格的 PDP。此服务会将缺少 decision 视为失败,而不会视为拒绝。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
参数必填描述
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 KiB。

返回 defined、value、原始 OPA result_set(编码后超过 256 KiB 时省略,并返回 result_set_omitted)、任何 print() 输出(200 行,每行 1 KiB),以及在请求时返回的跟踪信息。

authzen_evaluate
参数必填描述
subject是JSON 对象。AuthZEN 要求包含 type 和 id。
action是JSON 对象。AuthZEN 要求包含 name。
resource是JSON 对象。AuthZEN 要求包含 type 和 id。
context否包含运行时上下文的 JSON 对象(IP、时间、MFA 强度)。
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)。每次调用最多 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 搜索 API。search 用于选择要列出的实体;该实体只携带其 type。

search问题subjectactionresource
subject谁可以对该资源执行此操作?仅 type必填type 和 id
resource主体可以对哪些此类型的资源执行操作?type 和 id必填仅 type
action主体可以对该资源执行什么操作?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 缓存五分钟,结果中的 endpoint_source 会说明使用了哪个端点。公布的端点必须与 PDP 同源,因为 PDP 令牌会随请求发送;除非通过 pdp_url 显式传入,否则会拒绝跨源端点。返回 results、has_more 和 next_page_token;将该令牌作为 page_token 传回,并保持其他参数不变,即可获取下一页。如果响应的 page 对象没有 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,well-known 字符串会放在主机与前缀之间,符合 RFC 8615 和规范中的位置要求(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_TIMEOUT10s单次请求超时时间。
AUTHZEN_PDP_MAX_RESPONSE_BYTES1048576响应读取上限。
MCP_OPA_EVAL_TIMEOUT5s单次 Rego 评估的总时限。
MCP_MAX_ARG_BYTES1048576单个参数的大小上限。
MCP_OPA_ALLOW_NETWORK_BUILTINSfalse重新启用网络内置函数。见下文。

值格式错误时,服务会在启动时停止,而不会静默替换为默认值——操作人员认为已生效的限制,就应该确实生效。

安全性

evaluate_policy 会在此进程内编译并运行模型生成的 Rego。因此,有三个 OPA 内置函数会从能力集中移除:

内置函数原因
http.send可从服务运行所在的任何位置(笔记本电脑或 CI 运行器)发起任意 HTTP 请求,进入该位置所处的网络边界。这构成了完整的 SSRF 攻击面,也与该工具自身的描述相矛盾。
net.lookup_ip_addr即使没有可访问的端口,也足以一次一个 DNS 标签地外传 input。
opa.runtime会返回运行时配置,包括进程环境及其中的所有凭据。

时间、JWT、UUID 和随机数内置函数不受影响——这些函数会出现在实际的授权策略中。使用已移除内置函数的策略会编译失败,并显示指出该函数的消息;对于确实需要启用它的情况,消息还会提示 MCP_OPA_ALLOW_NETWORK_BUILTINS。

PDP 客户端也受到约束:pdp_url 必须是包含主机且不带用户信息的绝对 http(s) URL;客户端会拒绝重定向,而不会携带 Authorization 标头跟随重定向;响应会通过字节数上限读取;PDP 错误正文会在传入模型上下文前截断。

报告漏洞:参见 SECURITY.md。

运行

从源代码运行
make smoke

此流程会构建二进制文件,启动一个模拟 AuthZEN PDP,通过完整的五个工具运行一次真实的 MCP stdio 会话,并断言每个工具都已响应——包括 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 策略参考:

目录结构

刻意采用扁平结构。单二进制文件的 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。签名及其证书会一起包含在一个 Sigstore bundle 中,文件名为 *-checksums.txt.sigstore.json。

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

贡献

欢迎提交问题和拉取请求 — 请参阅 CONTRIBUTING.md。适合初次贡献的方向:添加另一种示例策略、尝试一个尚未测试过的 PDP,或补齐 AuthZEN 文本中的缺漏。

此仓库合并了原先的 0-draft/mcp-opa 和 0-draft/mcp-authzen。两者的历史记录均在此保留。

许可证

MIT。请参阅 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

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

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