Skip to main content
Version: Dev

Client Authentication

An MCP client reaches AISIX at one of two entries: the aggregated /mcp endpoint, which serves every registered server's tools under <server>__<tool> names, and /mcp/{server}, which serves one server's tools under their original names. This guide covers how a caller proves who it is at those entries.

Client authentication is independent of upstream authentication: the credential a client sends to AISIX identifies the caller to AISIX, and the credential AISIX sends to an upstream MCP server is held gateway-side and never forwarded.

Three modes are available, and an environment can combine them:

ModeThe client sendsUse it for
Gateway API keyAuthorization: Bearer <api key>The default. Machine-to-machine callers and agents you issue keys to.
OAuth sign-inAn access token from your identity providerStandard MCP clients that discover the sign-in flow themselves.
AnonymousNothingClients on trusted networks that cannot present a credential.

Whatever the mode, the caller resolves to an API key principal. Its tool grant determines what it can list and call. Configured rate limits and guardrails can govern tool calls, while usage remains attributed to the principal. In AISIX Cloud, matching budgets also apply. Anonymous callers therefore remain subject to the same controls as authenticated callers.

Prerequisites

Before starting, prepare the following:

  • Complete Set Up MCP Gateway for AISIX Cloud or an open-source AISIX gateway, and retain the AISIX_PROXY and AISIX_MCP_KEY values used at the end of that guide.
  • For the AISIX Cloud configuration examples, also retain the AISIX_CP, AISIX_TOKEN, and ENV_ID values from the AISIX Cloud Quickstart. To request Hybrid Cloud access, contact API7.
  • cURL for the request examples.

Gateway API Key

This is the default and needs no configuration. A client sends its key on every request:

curl -sS -X POST "$AISIX_PROXY/mcp" \
-H "Authorization: Bearer $AISIX_MCP_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

The key's grant decides which tools the caller sees and can call. See Control Tool Access for scoping a key to specific tools, whole servers, or every tool, and MCP Access Policies for granting at the environment or team level.

x-api-key: <api key> is accepted as an alternative header.

OAuth Sign-In

Standard MCP clients such as desktop assistants can sign a user in instead of asking them to paste a key. They do it by reading the WWW-Authenticate header on a 401, fetching the protected resource metadata it points at, and running the OAuth flow against the authorization server named there.

AISIX publishes that metadata once an environment has both:

  • a canonical MCP resource URL — the public URL clients use to reach this environment's /mcp endpoint; and
  • at least one enabled OIDC trust provider, which is the authorization server tokens must come from.

With both configured, GET /.well-known/oauth-protected-resource (and its /.well-known/oauth-protected-resource/mcp sibling) returns the resource identity, the issuers tokens may come from, and the scopes they must carry. Without them the routes return 404 and 401 responses carry no challenge, exactly as before the feature existed.

Access tokens must include the resource URL in their audience claim. This is the most common configuration mistake: a token minted for a different audience is rejected at the gateway even though sign-in succeeded.

AISIX Cloud

Set the resource URL on the environment:

curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mcp_resource_url": "https://gateway.example.com/mcp"
}'

The URL must be an absolute http or https URL whose path is exactly /mcp, with no query or fragment, and no embedded credentials — it is published on an unauthenticated endpoint. Send null to clear it and turn discovery off.

In the dashboard, the same setting lives on the environment's MCP Access page, which also warns when an enabled provider's audiences do not include the URL.

Open-Source AISIX Gateway

Set resource_url on the singleton mcp_auth_settings entry, creating it if absent, and keep any anonymous settings unchanged. Add corp-sso to oidc_providers:

resources.yaml (OAuth discovery)
mcp_auth_settings:
- resource_url: https://gateway.example.com/mcp

oidc_providers:
- name: corp-sso
issuer: https://sso.example.com/realms/agents
audiences:
- https://gateway.example.com/mcp
required_scopes:
- mcp:tools

At most one mcp_auth_settings entry may exist. A second one is rejected at load, and if a duplicate ever reaches a running gateway the discovery surface stays off rather than picking one.

Anonymous Access

Anonymous access lets clients that present no credential reach entries you open for them. It exists for fleets migrating from a gateway that never required a credential, where changing every client is not practical.

An anonymous request still resolves to an API key principal you choose. Its tool grants determine what it can list and call. Configured rate limits and guardrails can govern tool calls, while usage remains attributed to the principal. In AISIX Cloud, matching budgets also apply. Only the credential check changes.

caution

Anyone who can reach the gateway from the allowed networks can call the permitted tools without a credential, and the usage counts against the environment. Treat the source network allowlist as the access control it is, and keep the principal's tool grant as narrow as the clients actually need.

What Anonymous Is Not

It is not a downgrade path. A request that presents a credential is authenticated normally, and an invalid, expired, disabled or malformed one is rejected with 401. Only a request that presents nothing at all takes the anonymous path. A wrong authentication scheme or an empty header value counts as presenting something, so a client that tries to authenticate and gets it wrong fails rather than quietly succeeding with a different identity.

It is not visible to callers who are not allowed in. Every refusal — source outside the allowlist, a server not offered anonymously, the principal deleted or disabled, anonymous access off — answers the same 401 the entry gives without anonymous access at all. Callers cannot tell those apart, nor tell a registered MCP server from one that does not exist. Operators see the reason on the gateway's aisix_auth_decisions_total metric.

Configuration

Anonymous access is configured per environment:

FieldMeaning
api_key_idThe API key anonymous traffic runs as.
source_cidrsClient source networks allowed in. Required and non-empty.
serversMCP servers anonymous callers may reach. Required and non-empty.
aggregate_entryWhether the aggregated /mcp endpoint also serves anonymous callers. Off by default.
enabledSet to false to close anonymous access while keeping the configuration. Defaults to true.

Two of these deserve more than a one-line description.

The Server List Is a Ceiling

servers is not only the list of /mcp/{server} entries to open — it is the limit on what the principal can reach anywhere, including through the aggregated endpoint. Without that, a principal whose own tool grant is wider than the list could name <server>__<tool> on the aggregated endpoint and reach a server whose per-server entry is closed.

So the effective grant of an anonymous caller is the listed servers' tools intersected with the principal's own grant. Both tools/list and tools/call follow it, which is why an anonymous caller never sees a tool it could not call.

A newly registered MCP server is never anonymous by default. Reaching anonymous callers is always a name added to this list.

The Principal Needs Its Own Grant

In AISIX Cloud, the principal must carry its own mcp_access block. A key without one is rejected, because it would take whatever the environment and team layers leave — so a later policy change could widen anonymous access without anyone revisiting this setting. A key with its own block is bounded by its own allow list whatever those layers do.

In an open-source gateway configured with a resources file the same block is the principal's only layer, since the file has no policy collection. The servers list remains an additional ceiling on it.

Configure in AISIX Cloud

Export the ID of the API key that anonymous traffic should run as. The key must belong to the environment and carry the MCP grant described above:

export ANON_KEY_ID="YOUR_ANONYMOUS_PRINCIPAL_API_KEY_ID"

Set the block on the environment:

curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mcp_anonymous": {
"api_key_id": "'"$ANON_KEY_ID"'",
"source_cidrs": ["10.0.0.0/8"],
"servers": ["everything"],
"aggregate_entry": false
}
}'

❶ The API key principal that anonymous traffic runs as. It must belong to this environment and carry its own mcp_access block.

❷ Matched against the source address AISIX resolves through its real-IP configuration, never a header the client supplies. Use 10.0.0.1/32 for a single address.

❸ Approved servers exposed to this environment. Anonymous callers reach /mcp/everything and nothing else.

❹ Leave the aggregated endpoint on gateway credentials. See Anonymous Access and OAuth Sign-In before turning it on.

Send "mcp_anonymous": null to turn anonymous access off. The change reaches running gateways without a restart.

In the dashboard, the same settings live on the environment's MCP Access page, where enabling anonymous access requires an explicit risk acknowledgement.

Configure in an Open-Source Gateway

Add anonymous-mcp to api_keys. In the singleton mcp_auth_settings entry, add anonymous; create the entry if it is absent. Keep resource_url, the everything server, and the other resources unchanged. The ID below is derived from anonymous-mcp:

resources.yaml (anonymous MCP access)
api_keys:
- display_name: anonymous-mcp
key_env: ANONYMOUS_MCP_KEY
allowed_models: []
mcp_access:
allow:
- everything__*

mcp_auth_settings:
- anonymous:
api_key_id: d6869ae7-741a-598e-8213-16672e922546
source_cidrs:
- 10.0.0.0/8
servers:
- everything
aggregate_entry: false

Set ANONYMOUS_MCP_KEY in the gateway process environment before loading the file. If you use a different API key display name, replace api_key_id with that entry's deterministic derived ID. The resource_url field for OAuth discovery lives on the same mcp_auth_settings entry; the two settings are independent, and either can be configured without the other.

Anonymous Access and OAuth Sign-In

An environment can run both, and for most deployments the natural split is: existing clients that cannot present a credential use the per-server entries anonymously, while standard MCP clients sign in through the aggregated /mcp.

Turning on aggregate_entry in an environment that also publishes OAuth discovery changes that. A no-credential request to /mcp then succeeds instead of returning the 401 that carries the discovery hint, so OAuth-capable clients never start the sign-in flow and stay on the anonymous grant. The per-server entries are unaffected.

Verify

Confirm the mode you configured behaves as intended.

An anonymous call to a listed entry succeeds with no credential:

curl -sS -X POST "$AISIX_PROXY/mcp/everything" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

The response lists the tools the principal's grant allows on that server, under their original names.

A bad credential is still rejected, rather than served anonymously:

curl -sS -o /dev/null -w '%{http_code}\n' -X POST "$AISIX_PROXY/mcp/everything" \
-H "Authorization: Bearer not-a-real-key" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

The gateway returns 401.

Observability

Anonymous traffic is attributable. Usage events carry the principal's API key id like any other request, plus auth_type: anonymous, which distinguishes traffic that inherited the principal from an entry from traffic that presented that key's own credential. Authentication decisions, including refusals and their reasons, are counted on aisix_auth_decisions_total.

Limitations

Anonymous access is designed for trusted networks. Two capacity protections that authenticated deployments can rely on are not yet in place for it:

  • Per-source-IP rate limiting is not available. A single anonymous client can consume the principal's whole quota, since all anonymous traffic shares one principal.
  • The initialize, ping and tools/list methods are not metered. Only tools/call passes the rate-limit gate and checks applicable AISIX Cloud budgets.

The mandatory source network allowlist is what keeps this bounded. Do not expose anonymous entries to untrusted networks.

Next Steps

  • Control tool access: scope a key — including an anonymous principal — to specific tools or whole servers.
  • Rate limits and budgets: apply caller rate limits and use AISIX Cloud budgets that cover the caller API key.
  • Guardrails: inspect MCP tool arguments and results.
  • Observability: find MCP traffic in logs, metrics and usage.