跳到主要内容

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 起可用。

示例​

前提条件​

  • 在同一路由上启用 openapi-to-mcp。

  • 在路由上配置身份认证插件,例如 key-auth。如果请求中没有通过身份认证的消费者,mcp-tools-acl 会原样放行所有流量。

  • 对于 Admin API 标签页,请设置 Dashboard 地址和网关组,然后输入 Dashboard Token:

    export API7_ADMIN_URL="https://localhost:7443"
    export API7_GATEWAY_GROUP_ID="default"
    printf "Dashboard Token:"
    read -rs API7_ADMIN_KEY && export API7_ADMIN_KEY && echo

    这些示例中的 -k 标志会接受本地 Dashboard 的自签名证书。使用客户端信任的证书时,请移除此标志。

  • 对于 ADC 标签页,请选择 api7ee 后端,并配置相应的 Dashboard 地址、Token 和网关组。

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

使用白名单限制工具访问​

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

创建消费者 alice:

curl -k "${API7_ADMIN_URL}/apisix/admin/consumers/alice?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"username": "alice"
}'

为 alice 创建 key-auth 凭证:

curl -k "${API7_ADMIN_URL}/apisix/admin/consumers/alice/credentials/cred-alice-key-auth?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "cred-alice-key-auth",
"plugins": {
"key-auth": {
"key": "alice-key"
}
}
}'

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

curl -k "${API7_ADMIN_URL}/apisix/admin/consumers/alice?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"username": "alice",
"plugins": {
"mcp-tools-acl": {
"rules": [
{
"allow_tools": ["getPetById", "getUserByName"]
}
]
}
}
}'

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

提示

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

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

创建一个以 Petstore API 为上游的服务:

curl -k "${API7_ADMIN_URL}/apisix/admin/services/mcp-tools-acl-service?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "mcp-tools-acl-service",
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": [
{
"host": "petstore3.swagger.io",
"port": 443,
"weight": 1
}
]
}
}'

在该服务中创建一条启用了 openapi-to-mcp 和 key-auth 的路由:

curl -k "${API7_ADMIN_URL}/apisix/admin/routes/mcp-tools-acl-route?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "mcp-tools-acl-route",
"service_id": "mcp-tools-acl-service",
"paths": ["/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": {}
}
}'

以消费者 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"
}'

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

调用允许的工具:

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 -k "${API7_ADMIN_URL}/apisix/admin/consumers/bob?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"username": "bob",
"plugins": {
"mcp-tools-acl": {
"rules": [
{
"deny_tools": ["deletePet"]
}
]
}
}
}'

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

为 bob 创建 key-auth 凭证:

curl -k "${API7_ADMIN_URL}/apisix/admin/consumers/bob/credentials/cred-bob-key-auth?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "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 -k "${API7_ADMIN_URL}/apisix/admin/consumers/grace?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-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 -k "${API7_ADMIN_URL}/apisix/admin/consumers/grace/credentials/cred-grace-key-auth?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "cred-grace-key-auth",
"plugins": {
"key-auth": {
"key": "grace-key"
}
}
}'

创建一个以 Petstore API 为上游的服务,或复用第一个示例中的服务:

curl -k "${API7_ADMIN_URL}/apisix/admin/services/mcp-tools-acl-service?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "mcp-tools-acl-service",
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": [
{
"host": "petstore3.swagger.io",
"port": 443,
"weight": 1
}
]
}
}'

下方的 route-pets 路由使用 /mcp 路径。如果你在前面的示例中创建了 mcp-tools-acl-route,请先将其删除,因为 Dashboard 会拒绝服务中与另一条路由匹配相同路径的路由:

curl -k "${API7_ADMIN_URL}/apisix/admin/routes/mcp-tools-acl-route?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X DELETE \
-H "X-API-KEY: ${API7_ADMIN_KEY}"

在该服务中创建两条启用了 openapi-to-mcp 和 key-auth 的路由:

curl -k "${API7_ADMIN_URL}/apisix/admin/routes/route-pets?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "route-pets",
"service_id": "mcp-tools-acl-service",
"paths": ["/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": {}
}
}'
curl -k "${API7_ADMIN_URL}/apisix/admin/routes/route-inventory?gateway_group_id=${API7_GATEWAY_GROUP_ID}" -X PUT \
-H "X-API-KEY: ${API7_ADMIN_KEY}" \
-H "Content-Type: application/json" \
-d '{
"name": "route-inventory",
"service_id": "mcp-tools-acl-service",
"paths": ["/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": {}
}
}'

当 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 数组不为空。