跳到主要内容

mcp-tools-acl

mcp-tools-acl 插件用于控制每个消费者在 openapi-to-mcp 路由上可以调用或发现哪些 MCP 工具。该插件提供两种限制方式:

  • tools/call 拦截 — 拒绝消费者调用被禁止的工具,返回 HTTP 错误响应。
  • tools/list 过滤 — 从返回给客户端的工具列表中移除被禁止的工具,使 MCP 客户端感知不到这些工具的存在。此过滤同时适用于 JSON 响应和 SSE(Server-Sent Events)流式响应。

该插件采用基于规则的配置方式,每条规则指定白名单或黑名单,并可选配表达式条件。规则按顺序执行——第一条条件匹配的规则生效,其余规则跳过。

此插件自 API7 企业版 3.9.8 起可用。

示例

前提条件

使用此插件前,请确保:

  1. 路由上已启用 openapi-to-mcp 插件。
  2. 路由上已配置身份认证插件(例如 key-auth)。如果请求中没有经过身份认证的消费者,mcp-tools-acl 会原样放行所有流量。

以下示例展示了如何在不同场景下使用 mcp-tools-acl 插件。

使用白名单限制工具访问

以下示例展示了如何通过白名单配置,只允许消费者调用指定的 MCP 工具。

创建消费者 alice

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "alice"
}'

alice 创建 key-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/alice/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-alice-key-auth",
"plugins": {
"key-auth": {
"key": "alice-key"
}
}
}'

在消费者 alice 上配置 mcp-tools-acl 插件:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "alice",
"plugins": {
"mcp-tools-acl": {
"rules": [
{
"allow_tools": ["getPetById", "getUserByName"]
}
]
}
}
}'

❶ 仅允许消费者 alice 调用 getPetByIdgetUserByName。其他所有工具都将被阻止,也不会出现在工具列表中。

提示

mcp-tools-acl 应配置在消费者(或消费者组)上,以实现按消费者粒度的工具访问控制。路由上只需配置 openapi-to-mcp 和认证插件。

当消费者和路由上同时配置了该插件时,消费者配置优先生效,路由级配置对该消费者不生效。若消费者未配置 mcp-tools-acl,则以路由上的配置作为兜底。

创建启用了 openapi-to-mcpkey-auth 的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "mcp-tools-acl-route",
"uri": "/mcp",
"methods": ["GET", "POST"],
"plugins": {
"openapi-to-mcp": {
"transport": "streamable_http",
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json",
"base_url": "https://petstore3.swagger.io/api/v3",
"headers": {
"Authorization": "special-key"
}
},
"key-auth": {}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"petstore3.swagger.io:443": 1
}
}
}'

以消费者 alice 的身份发送 tools/list 请求:

curl -s "http://127.0.0.1:9080/mcp" \
-H "apikey: alice-key" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}'

响应中应该只包含 getPetByIdgetUserByName,其他所有工具均已被过滤。

调用允许的工具:

curl -i "http://127.0.0.1:9080/mcp" \
-H "apikey: alice-key" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "getPetById",
"arguments": {
"pathParameters": {
"petId": 1
}
}
}
}'

你应该会看到包含 Petstore 宠物数据的 HTTP/1.1 200 OK 响应。

调用不在白名单中的工具:

curl -i "http://127.0.0.1:9080/mcp" \
-H "apikey: alice-key" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "deletePet",
"arguments": {
"pathParameters": {
"petId": 1
}
}
}
}'

你应该看到 HTTP/1.1 403 Forbidden 响应,表明该工具调用被拦截。

使用黑名单限制工具访问

以下示例展示如何通过黑名单配置,禁止消费者调用特定工具,其余工具均可正常访问。

基于上一个示例,为消费者 bob 配置黑名单:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "bob",
"plugins": {
"mcp-tools-acl": {
"rules": [
{
"deny_tools": ["deletePet"]
}
]
}
}
}'

❶ 禁止消费者 bob 调用 deletePet,其他工具仍可访问。

bob 创建 key-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/bob/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-bob-key-auth",
"plugins": {
"key-auth": {
"key": "bob-key"
}
}
}'

以消费者 bob 的身份发送 tools/list 请求:

curl -s "http://127.0.0.1:9080/mcp" \
-H "apikey: bob-key" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}'

你应该会看到除 deletePet 之外的所有工具。

调用被禁止的工具:

curl -i "http://127.0.0.1:9080/mcp" \
-H "apikey: bob-key" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "deletePet",
"arguments": {
"pathParameters": {
"petId": 1
}
}
}
}'

你应该看到 HTTP/1.1 403 Forbidden 响应。

基于路由条件应用不同规则

以下示例展示了如何使用表达式条件(expr),根据请求上下文(如访问的路由)应用不同的 ACL 规则。

此示例适用于 API7 企业版 3.9.8 及更高版本。

创建消费者 grace,配置条件规则:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "grace",
"plugins": {
"mcp-tools-acl": {
"rules": [
{
"expr": [["route_id", "==", "route-pets"]],
"allow_tools": ["getPetById"]
},
{
"allow_tools": ["getUserByName"]
}
]
}
}
}'

❶ 规则 1:当请求命中路由 route-pets 时,仅允许调用 getPetById

❷ 规则 2:一条兜底规则(没有 expr),对于其他所有路由,仅允许调用 getUserByName。仅当规则 1 不匹配时,才会执行此规则。

grace 创建 key-auth 凭证:

curl "http://127.0.0.1:9180/apisix/admin/consumers/grace/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-grace-key-auth",
"plugins": {
"key-auth": {
"key": "grace-key"
}
}
}'

创建两个配置了 openapi-to-mcpkey-auth 的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "route-pets",
"uri": "/mcp",
"methods": ["GET", "POST"],
"plugins": {
"openapi-to-mcp": {
"transport": "streamable_http",
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json",
"base_url": "https://petstore3.swagger.io/api/v3",
"headers": { "Authorization": "special-key" }
},
"key-auth": {}
},
"upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "petstore3.swagger.io:443": 1 } }
}'
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "route-inventory",
"uri": "/mcp2",
"methods": ["GET", "POST"],
"plugins": {
"openapi-to-mcp": {
"transport": "streamable_http",
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json",
"base_url": "https://petstore3.swagger.io/api/v3",
"headers": { "Authorization": "special-key" }
},
"key-auth": {}
},
"upstream": { "type": "roundrobin", "scheme": "https", "pass_host": "node", "nodes": { "petstore3.swagger.io:443": 1 } }
}'

grace 调用 route-pets 时,规则 1 匹配,因此仅允许调用 getPetById

curl -i "http://127.0.0.1:9080/mcp" \
-H "apikey: grace-key" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "getPetById",
"arguments": {
"pathParameters": {
"petId": 1
}
}
}
}'

你应该会看到包含 Petstore 宠物数据的 HTTP/1.1 200 OK 响应。

grace 调用 route-inventory 时,规则 1 不匹配(route_id 不同),因此兜底规则 2 生效,仅允许调用 getUserByName

curl -i "http://127.0.0.1:9080/mcp2" \
-H "apikey: grace-key" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "getUserByName",
"arguments": {
"pathParameters": {
"username": "user1"
}
}
}
}'

你应该会看到包含 Petstore 用户数据的 HTTP/1.1 200 OK 响应。

备注

规则从上到下依次匹配。第一条匹配的规则生效,后续规则均被跳过。应将更具体的规则(带 expr)放在前面,将范围更广的兜底规则(不带 expr)放在后面。

如果没有任何规则匹配(所有规则都设置了 expr 条件且均未求值为 true),插件不执行任何访问控制——所有工具均直接放行。

故障排除

插件不生效

请检查同一路由上是否启用了 openapi-to-mcp,并确认已配置身份认证插件。如果请求中没有经过身份认证的消费者,mcp-tools-acl 会按设计原样放行所有流量。

tools/call 返回 400

请求体是合法的 JSON,但 params 字段缺失或 params.name 不是字符串,插件会返回 {"message": "Invalid MCP tools/call request"} 和 HTTP 400。这与配置的 rejected_code(针对被拒绝工具)不同,表明 MCP 客户端发送了格式错误的请求。

allow_tools: [] 导致所有工具均被拒绝

空白名单符合 Schema,但会拒绝所有工具。每个 tools/call 请求都会被拒绝,tools/list 将返回空列表。如果希望消费者访问任何工具,请确保 allow_tools 数组不为空。