Control Tool Access
For MCP traffic, the caller API key is the tool-access boundary. A key cannot list or call an MCP tool until access is granted explicitly.
Configure tool access when different clients should reach different upstream tools through the same gateway. This guide explains how AISIX names aggregated tools, how to create or update a key with tool access, and how enforcement behaves when a caller lists or calls tools.
Prerequisites
Before starting, prepare the following:
- For AISIX Cloud, an environment, a registered MCP server, and a write-scoped admin token. For On-Premises, follow the AISIX Cloud Quickstart. To request Hybrid Cloud access, contact API7.
- For an open-source AISIX gateway, a caller API key and registered MCP server in
resources.yaml. Set Up MCP Gateway provides a working configuration and the validation and reload workflow. - cURL and jq for the AISIX Cloud examples.
How Tool Access Works
Tool access is stored on the caller API key in mcp_access, an object with an allow list and an optional deny list. The block is the key's own layer of the tool ACL: in AISIX Cloud it is intersected with the environment and team MCP access policies, so the key can narrow what those layers allow but never widen it.
When the block is omitted the key adds no constraint of its own. That means it takes whatever the policy layers leave — and with no policy configured anywhere, no MCP tool access at all. Access is always granted explicitly.
AISIX names each exposed tool in the <server>__<tool> form. The <server> segment is the registered MCP server's name; the <tool> segment is the upstream tool name. For example, github__create_issue calls the upstream create_issue tool on the registered github server.
Each entry in allow is matched against the prefixed tool name:
| Entry | Grants | Example |
|---|---|---|
| Exact name | One specific tool. | github__create_issue allows only that tool. |
<server>__* | Every tool on one registered server. | github__* allows github__create_issue, github__list_repos, and any other github tool. |
* | Every tool on every registered server. | * allows all current and future tools. |
Choose exact names for the narrowest access. Use a per-server wildcard when a caller may use every tool on one server, and use * only for a key that should narrow nothing — which is what you send alongside deny when the key only means to subtract tools. An empty allow list leaves the key no MCP access at all.
Entries are single-asterisk globs, so the wildcard can appear outside the trailing per-server form. For example, *__search grants a tool named search on every registered server. Prefer per-server or exact grants unless you specifically need a cross-server pattern.
deny uses the same patterns and always wins: a tool matched there is unavailable however the key or any policy layer allows it.
A per-key block is the narrowest control. In AISIX Cloud, use Manage MCP Access with Policies to grant access at the environment or team level. Keys that add no block of their own then follow the shared layer, including tools registered later when a matching wildcard covers them.
Configure Tool Access
Configure tool access using the management path for your deployment.
AISIX Cloud
Use the Admin API to create a caller API key with tool access or update the tool grant on an existing key.
Create a Key
Export the control-plane URL, admin token, and environment ID:
export AISIX_CP="http://localhost:8080/api"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
Create the caller API key that the MCP client uses. This example grants every tool on one server plus one specific tool on another server:
curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/api_keys" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"display_name": "mcp-caller",
"allowed_models": [],
"mcp_access": { "allow": ["github__*", "runbooks__search"] }
}' > api_key.json
export API_KEY_ID=$(jq -r '.api_key.id' api_key.json)
export CALLER_KEY=$(jq -r '.plaintext' api_key.json)
❶ Use an empty model allowlist when the key is only for MCP traffic.
❷ This layer allows every tool on the github server plus the single runbooks__search tool, and nothing else. In AISIX Cloud the key still only reaches what the environment and team layers also allow.
The response returns the plaintext bearer in plaintext exactly once. Store it on the client side immediately; subsequent reads return only key metadata. The MCP client sends this value as Authorization: Bearer <plaintext> on gateway requests.
Update Tool Access
Update the caller API key when its tool grant changes. The update is partial: only the fields you send are changed, and mcp_access is replaced as a whole block:
curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/api_keys/$API_KEY_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mcp_access": { "allow": ["github__create_issue"] }
}'
This update replaces the previous block with one allowing github__create_issue only. The key's model access and other settings are untouched because the request does not include them.
To revoke all MCP tool access for a key, send "mcp_access": {"allow": []}. The key keeps its model access and other settings but can no longer list or call any MCP tool, whatever the policy layers allow. Sending "mcp_access": null instead removes the key's layer, which is different: the key then follows the environment and team layers again.
Open-Source AISIX Gateway
Set mcp_access on the caller entry in resources.yaml:
api_keys:
- display_name: mcp-caller
key_env: MCP_CALLER_KEY
allowed_models: []
mcp_access:
allow:
- github__*
- runbooks__search
Set MCP_CALLER_KEY in the gateway process environment. This caller can use every tool registered under github and only the search tool registered under runbooks. Other caller settings, including model and A2A access, remain on the same entry.
A resources file has no policy layers, so the key's own block is the only one — a caller entry without mcp_access therefore has no MCP tool access.
To change the grant, edit the complete block, validate resources.yaml, and reload the gateway. Set allow: [] to revoke all MCP tool access while retaining the key's other permissions. See Set Up MCP Gateway for the validation and reload commands.
How Enforcement Works
When an MCP client lists tools, AISIX aggregates tools from every enabled server, then filters the list by the caller's effective grant — the intersection of every layer that applies to the key. The client sees only permitted tools.
When the client calls a tool, AISIX checks the effective grant again before contacting the upstream server. A tool the caller cannot access is rejected with a neutral MCP error and is never routed upstream. The rejection does not reveal whether the tool or server exists.
The same grant applies at a per-server endpoint. AISIX evaluates each tool in namespaced <server>__<tool> form, then normally presents permitted tools under their original names. For example, a grant for github__create_issue presents create_issue at /mcp/github but grants nothing at another server's endpoint.
AISIX Cloud Control Plane
Tool access can also be configured from the control plane user interface instead of the API calls shown above. The same grant model applies: a caller API key can be scoped to individual tools, to every tool on a server, or to every MCP tool available in the environment. This workflow is available with both AISIX Cloud control-plane deployment options: On-Premises and Hybrid Cloud.
Next Steps
You have now scoped which MCP tools each caller API key can list and call. Use these guides to add runtime controls or review the shared caller-key settings:
- Rate limits and budgets: apply request and concurrency limits, and configure AISIX Cloud budgets for MCP tool calls.
- Guardrails: inspect MCP tool arguments and results.
- Caller API Keys: review the shared key settings that also govern model and A2A traffic.