Repository navigation
true
v1.8.0
🚀 Get started
New to AISIX? Get the gateway running and route your first LLM request in minutes:
- 📖 Documentation — https://docs.api7.ai/ai-gateway/
- ⚡ Gateway quickstart (one container, declarative
resources.yaml) — https://docs.api7.ai/ai-gateway/getting-started/gateway-quickstart
📦 Download
Pull the container image from the GitHub Container Registry:
docker pull ghcr.io/api7/aisix:1.8.0The rolling latest tag and the docker.io/api7/aisix mirror for private/offline deployments are listed on the package page.
AISIX 1.8.0 lets MCP servers act on the caller's behalf, accepts PROXY protocol headers from trusted load balancers, and moves budget decisions onto the gateway itself, so a control-plane outage no longer turns into a blanket refusal. An idle gateway now needs a fraction of the memory it used to.
- MCP servers can act on the caller's behalf (#1361, #1362): relay the caller's own token upstream, or exchange it for a downstream token through the Microsoft Entra ID On-Behalf-Of grant. A new
x-aisix-api-keyheader carries the gateway key soAuthorizationstays free for the caller's own token. - PROXY protocol v1 and v2 from trusted load balancers (#1374), on every proxy listener, detected automatically.
- Budgets are decided on the gateway (#1366) from budget state the control plane pushes with the configuration. A control-plane or database outage no longer refuses traffic.
- Every proxy route emits every per-request metric family that applies to it (#1367), and access logs carry token counts on every endpoint (#1365).
- Unknown startup-config keys are ignored with a warning instead of stopping the gateway (#1368).
- Idle memory drops from about 120 MiB to under 10 MiB (#1370).
Control-plane, console and AISIX Enterprise / AISIX Cloud changes in this release (two-factor sign-in, password policy, control-plane API and Helm aisix-cp changes) are described in the AISIX release notes.
⚠️ Breaking changes
See Upgrade notes for what to update.
- Debug response headers on
/v1/chat/completionsare off by default (#1364).x-aisix-call-id,x-aisix-served-by,x-aisix-route,x-aisix-cache,x-aisix-cache-layerandx-aisix-cache-similarityare no longer sent unlessproxy.expose_debug_headers: trueis set in the gateway config (Helm chartaisix:config.proxy.expose_debug_headers). The same facts are in usage events, access logs, metrics and traces.x-aisix-request-id,server,x-ratelimit-*andretry-afterare still sent. - Four access-log fields take their usage-event names (#1365):
status→status_code,error_kind→error_class,model→requested_model,latency_ms→downstream_latency_ms. Only the new names are written. aisix_llm_spend_micro_usd_totalis removed (#1367). Only Realtime ever put a value on it. Read spend fromcost_usdon usage events, or the control plane's recorded cost. A config that still lists it underobservability.metrics.labelsboots and warns.- One inbound credential rule on every entry (#1383). An empty
x-aisix-api-key,Authorizationorx-api-keyheader counts as an offered credential and is a401; it is no longer skipped, so an MCP client using anonymous access that sends one of them empty is now refused instead of served anonymously. Ongateway_keypassthrough routes, anAuthorizationthat is present but not a usableBearercredential no longer falls back tox-api-key; it gets401. - A connection whose first bytes are
PROXYis read as a PROXY v1 header (#1374) and closed unless the peer is inproxy.real_ip.trusted_proxies. It used to get an HTTP400. - Dual-stack (
[::]) listeners report and match IPv4 clients as plain IPv4 (#1374) instead of::ffff:a.b.c.d, in allowlists, usage events, OTLPclient.addressand logs.
🧩 MCP and gateway credentials
- New gateway credential header
x-aisix-api-key(#1361, #1383). When present it takes precedence overAuthorizationandx-api-keyfor gateway authentication, so a caller can send its gateway key there and keepAuthorizationfor its own upstream token. It is accepted on every/v1/*endpoint,/mcp,/mcp/{server},/a2a, the/v1/realtimehandshake andgateway_keypassthrough routes, and is never forwarded upstream. An empty value is a401, with no fall-through to the next header. - Inbound credentials follow one rule (#1383).
bearer <key>andBEARER <key>are accepted on every entry (the key itself is case-sensitive), and a401for an empty or malformedx-aisix-api-keyorx-api-keynow names that header instead ofAuthorization. - New MCP server auth type
oauth_delegate(#1361), formcpandopenapiservers: the gateway relays the caller's ownAuthorizationto the upstream, but only when that header was not the gateway credential (the gateway key came inx-aisix-api-key). Only servers the caller's MCP access rules reach receive it. - New MCP server auth type
oauth2_token_exchangewithtoken_exchange_profile: entra_obo(#1361, #1362): the gateway exchanges the caller's token, verified by a JWT trust provider, through the Microsoft Entra ID On-Behalf-Of grant and sends only the minted token upstream. Tokens are cached until shortly before expiry and re-exchanged once on an upstream401; the exchange is bounded by the server'stimeout_ms. On/mcp/{server}failures have distinct statuses (401token_exchange_subject_missing/token_exchange_subject_rejected,500token_exchange_misconfigured,503token_exchange_unavailable), and an Entra Conditional Access step-up reaches the client as aninsufficient_claimschallenge. On the aggregated/mcp, a failing server only drops its own tools.
💰 Budgets
- Hard-stop budgets are decided on the gateway (#1366) from budget state the control plane pushes with the configuration; the gateway no longer asks the control plane on each request. Raising or lowering a limit takes effect immediately, a block lifts at the period boundary even while the control plane is unreachable, and a control-plane or database outage no longer refuses traffic after about 10 minutes.
provider_keybudgets act per upstream credential (#1366): an exhausted provider key removes only the routing targets that use it, so a Model Group with another target keeps serving. It does not consume a fallback slot. When every candidate is excluded the caller still gets429 budget_exceeded. MCP, A2A and gateway-internal calls are not subject to it.- Budget enforcement is
stickyorclosed(#1366).sticky(default) keeps enforcing the last pushed state through an outage.closed(strict) refuses, once usage reporting has not reached the control plane for the grace period (budget_closed_grace_seconds, default 600 s, 60–86400), only the keys and upstreams a budget covers, with503 budget_unverified; everything else keeps serving, and the next successful report lifts it. - New metric
aisix_usage_delivery_unhealthy_seconds(#1366): how long usage events have been waiting without reaching the control plane. - The etcd watch uses HTTP/2 keepalive (#1366), so a silently dropped connection is detected and recovered in about 20 s instead of missing configuration updates indefinitely.
📊 Observability
- Every client-facing proxy route emits every per-request metric family that applies to it (#1367):
aisix_request_e2e_latency_secondson all routes except/v1/realtime, time to first token on streamed audio, streamed/a2aand opaque passthrough streams, token families on/a2a, deployment families on video follow-ups, realtime and files / batches / fine-tuning, rate-limit remaining gauges at the quota gate, and401/403counted on every route including/mcp. - Access logs carry token counts on every endpoint (#1365):
prompt_tokens/completion_tokens/total_tokenson non-streamed/v1/messages,/v1/embeddings,/v1/responses,/v1/completions,/v1/rerank, images, audio,/v1/decisionsand/a2alines, and the/v1/realtimesession-close line carries the session totals. - Realtime usage events record
error_class(transport,timeout) when the upstream ends a session (#1365).
⚙️ Deployment and configuration
- PROXY protocol v1 and v2 on every proxy listener, plaintext and TLS (#1374). A header is honoured only from a socket peer in
proxy.real_ip.trusted_proxies; from any other peer the connection is closed with a WARN. Detection is automatic, connections without a header keep working on the same port, and the address the header carries is what usage events, access logs,allowed_cidrs, source allowlists, MCPsource_cidrsand client-IP hash routing see. No new config key. - IPv4 CIDRs match IPv4 clients on
[::]listeners (#1374) intrusted_proxies,allowed_cidrs, source allowlists and MCPsource_cidrs. - The startup config no longer refuses keys it does not know (#1368): a misspelled or retired key is ignored and named in a startup WARN (written to stderr when the log level hides warnings). A config that fails to load for another reason also lists the ignored keys in its error.
- Resource-schema validation memory drops from about 115 MiB to about 4 MiB per gateway process (#1370); an idle gateway now sits under 10 MiB of allocated memory.
- The TLS library is updated to a patched
rustlsrelease (#1376).
⬆️ Upgrade notes
These notes apply when you upgrade from 1.7.1 or earlier.
- Turn debug headers back on if you read them. Set
proxy.expose_debug_headers: true, or read the same facts from usage events, access logs, metrics or traces. - Update access-log parsers. Anything that parses the
proxy request completedline by field name must usestatus_code,error_class,requested_modelanddownstream_latency_ms. - Stop reading
aisix_llm_spend_micro_usd_total, and remove it fromobservability.metrics.labels. - Metric labels change on a few routes. The two
/.well-known/oauth-protected-resourceroutes get their ownendpointlabel instead ofother, and A2A agent-card fetches move fromendpoint="/a2a"to/a2a/{agent}/.well-known/agent-card.json, so they no longer count as agent calls.aisix_component_entries{component="budget_cache"}is no longer reported. - Check the startup WARN lines after editing the config. A misspelled key no longer stops the gateway; it is ignored. The retired
observability.metrics.otlp,observability.tracingandobservability.usage_eventblocks are removed: a config that still carries them boots and warns, so delete them.AISIX_DP_BUDGET_STALE_MAX_SECONDSis gone as well; a gateway that still sets it boots and warns. - Rewrite
::ffff:a.b.c.dallowlist entries on[::]listeners as plain IPv4 (trusted_proxies,allowed_cidrs, passthrough source allowlists, MCPsource_cidrs), and expect client IPs in usage events, OTLPclient.addressand logs in the IPv4 form. - Behind an L4 load balancer that sends PROXY headers, add the balancer's addresses to
proxy.real_ip.trusted_proxies. - MCP clients using anonymous access must not send an empty
x-aisix-api-key,Authorizationorx-api-keyheader; it is now a401. - On
gateway_keypassthrough routes, send the gateway key inx-aisix-api-keyand keepAuthorizationfor the upstream. A request whoseAuthorizationis present but not a usableBearercredential no longer falls back tox-api-key. - Budget enforcement mode. Organizations whose mode was
openare switched tosticky;openis no longer accepted. Instickymode, a 1.7.1 gateway answered every request with429once the control plane had been unreachable for more than 600 s; a 1.8.0 gateway blocks only requests whose budget is already exhausted. Inclosedmode, after the grace period (budget_closed_grace_seconds, default 600) only requests subject to a budget get503 budget_unverified, and the trigger is now usage delivery failing. provider_keybudgets change meaning on 1.8.0 gateways. A hard-stopprovider_keybudget now removes only the upstreams that use that key, instead of refusing every request on keys the provider key serves.- Mixed-version environments. Until a gateway is upgraded to 1.8.0 it keeps using the previous per-request budget check, including refusing whole keys for
provider_keybudgets and the outage behaviour above. In environments with hard-stop budgets or strict mode, a 1.6.x or 1.7.x gateway counts the new budget documents inaisix_config_unknown_kind_resources; its reload status is unaffected.
What's Changed
- feat(mcp): x-aisix-api-key gateway credential header, oauth_delegate and Entra OBO token exchange by @jarvis9443 in #1361
- fix(mcp): bound OBO token exchange by the server timeout; record a failed re-exchange as dispatched by @jarvis9443 in #1362
- fix(obs): prune automatic heap dumps before counting the dump by @jarvis9443 in #1363
- feat(proxy): make chat debug response headers opt-in via proxy.expose_debug_headers by @jarvis9443 in #1364
- fix(obs)!: fill access-log token counts on every endpoint; adopt usage-event field names by @jarvis9443 in #1365
- feat(budget)!: decide budgets from pushed documents; strict mode; etcd watch keepalive by @jarvis9443 in #1366
- feat(metrics)!: every proxy route emits every per-request metric family by @jarvis9443 in #1367
- feat(config)!: ignore unknown startup-config keys with a warning, drop retired tombstones by @jarvis9443 in #1368
- feat(proxy): honour PROXY protocol v1/v2 headers from trusted peers by @jarvis9443 in #1374
- build(deps): bump @hono/node-server from 2.1.1 to 2.1.5 in /tools/mcp-conformance by @dependabot[bot] in #1371
- build(deps): bump qs from 6.16.0 to 6.17.1 in /tools/mcp-conformance by @dependabot[bot] in #1372
- build(deps): bump undici from 7.30.0 to 7.30.1 in /tools/mcp-conformance by @dependabot[bot] in #1373
- build(deps): bump rustls, undici and conformance-harness deps to patched versions by @jarvis9443 in #1376
- perf(core): bump jsonschema to 0.60 so the resource validators stop holding ~115 MiB by @xz-dev in #1370
- fix(auth): one inbound credential rule: empty headers are offered, no fall-through, case-insensitive Bearer by @jarvis9443 in #1383
New Contributors
Full Changelog: v1.7.1...v1.8.0