Review and Approve MCP Servers
AISIX Cloud OnlyAvailable with AISIX CloudAn MCP server registry entry gives agents a gateway-managed tool surface backed by an upstream MCP server or REST API. Publishing the entry lets agents invoke remote operations with caller-supplied arguments. AISIX Cloud therefore separates registration from publication: every MCP server carries an approval_status, and only an approved server is sent to the gateways.
A server that is waiting for review, or that was rejected, has no presence on the gateway at all. It does not appear in tools/list and its tools cannot be called, even by a caller API key that explicitly allowlists them. Approval is required for publication; the enabled flag then controls whether the approved server can serve tools.
This separation lets a member propose an MCP server without being able to publish it. It also prevents a different configuration from inheriting an approval: a change either comes from someone who can approve it, or waits for review. A live server keeps serving its approved configuration while a proposed change waits, so the review causes no downtime.
Prerequisites
Before starting, prepare the following:
- An AISIX Cloud organization and environment.
- An admin token with write scope for the review and approval examples.
- cURL and jq.
For On-Premises, the AISIX Cloud Quickstart creates the organization, environment, and write-scoped admin token. Export the values used by the examples:
# AISIX_CP includes /api and has no trailing slash.
# The local On-Premises quickstart uses http://localhost:8080/api.
export AISIX_CP="http://localhost:8080/api"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"
How the Review Workflow Works
approval_status | On the gateways | Reached by |
|---|---|---|
pending_review | Not projected | Submitting a server, or revising a proposal. |
approved | Projected to allowed_environments | Approving it, or registering it with POST /mcp_servers. |
rejected | Not projected | Rejecting it. |
A change proposed to a server that is already live does not move it out of approved. The change waits in a separate pending_change field while every other field keeps describing what the gateways are serving. See Submit a Change to a Live Server.
Servers registered before this feature was introduced are approved, so upgrading does not interrupt tool traffic.
Configure Reviewer Permissions
Approving is the same permission as registering: write on mcp_servers. Owners and admins hold it. A user with this permission can already publish a server directly, so a separate review would not add control. This also lets an organization with a single administrator approve its own submissions.
The separable half is a second permission, write on mcp_server_submissions. A custom role that holds it without write on mcp_servers can propose servers, revise proposals, and propose changes to servers that are already live, but cannot publish anything. That is the role to give a team that integrates its own tooling.
Submit a Server for Review
Submit the server with POST /mcp_server_submissions. The body is the same as POST /mcp_servers:
curl -sS -X POST "$AISIX_CP/mcp_server_submissions" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "runbooks",
"url": "https://mcp.example.com/runbooks",
"auth_type": "none",
"allowed_environments": ["'"$ENV_ID"'"]
}'
The server is registered but unpublished:
{
"mcp_server": {
"id": "6f64f080-17d7-44d9-b995-6a353e71f6bc",
"name": "runbooks",
"url": "https://mcp.example.com/runbooks",
"enabled": true,
"allowed_environments": ["YOUR_ENVIRONMENT_ID"],
"approval_status": "pending_review",
"submitted_at": "2026-07-29T09:30:00Z"
}
}
❶ enabled and allowed_environments describe the configuration that will take effect after approval.
❷ pending_review keeps the server unpublished, so no gateway can reach it yet.
In the dashboard, the MCP servers page shows a Pending review badge on the row and a band at the top of the page listing how many servers are waiting.
Review a Pending Server
List what is waiting by reading approval_status from GET /mcp_servers:
curl -sS "$AISIX_CP/mcp_servers" \
-H "Authorization: Bearer $AISIX_TOKEN" \
| jq '.data[] | select(.approval_status == "pending_review") | {id, name, url}'
Review the server before approving it:
- Confirm that the name is not a near-copy of an existing server's name and that the URL identifies the intended upstream.
- Check
allowed_environmentsandenabledto confirm where the server will be available after approval. - Check the authentication mode and verify the credential's provenance through your submission process. Stored credentials are write-only and cannot be inspected from the API or dashboard; replace the credential through the approver route if its provenance is uncertain.
- For an OpenAPI-backed server, review the generated tool names and the stored document. See Review the Generated Tools in AISIX Cloud.
Approve it, and it is published to the environments in allowed_environments:
export MCP_SERVER_ID="YOUR_MCP_SERVER_ID"
curl -sS -X POST "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/approve" \
-H "Authorization: Bearer $AISIX_TOKEN"
Reject it with a reason instead. The note is returned on the server, so whoever proposed it can see what to change:
curl -sS -X POST "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/reject" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"review_notes": "Not on the trusted registry. Use the internal mirror."}'
Approving an already-approved server, or rejecting an already-rejected one, returns 400. A server carrying a staged change is the exception; see Submit a Change to a Live Server.
Revise a Pending Submission
PATCH /mcp_server_submissions/{id} corrects a submission and puts it back in the queue:
curl -sS -X PATCH "$AISIX_CP/mcp_server_submissions/$MCP_SERVER_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://mcp.internal.example.com/runbooks"}'
On a server that is not published yet, the change is applied to the row and the server stays in the queue. On a server that is already live, the same call stages the change instead of applying it.
Submit a Change to a Live Server
A role holding only write on mcp_server_submissions cannot publish, so its patch to a live server cannot take effect on its own. It must not take the server down while it waits either, so PATCH /mcp_server_submissions/{id} stages it:
curl -sS -X PATCH "$AISIX_CP/mcp_server_submissions/$MCP_SERVER_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://mcp.internal.example.com/runbooks"}'
The response is the server as it still stands, with the proposal alongside it:
{
"mcp_server": {
"id": "6f64f080-17d7-44d9-b995-6a353e71f6bc",
"name": "runbooks",
"url": "https://mcp.example.com/runbooks",
"approval_status": "approved",
"pending_change": {
"changes": { "url": "https://mcp.internal.example.com/runbooks" },
"submitted_by": "YOUR_USER_ID",
"submitted_at": "2026-07-30T09:30:00Z"
}
}
}
❶ Fields outside pending_change describe what the gateways are serving. Agents keep listing and calling the server's current tools throughout the review window.
❷ pending_change contains the proposed replacement values and submission metadata.
A proposal is validated when it is made, so an invalid change is refused at that point rather than at approval time. A proposed credential is encrypted at rest exactly like the live one and is never returned; pending_change.secret_set reports that the proposal sets one. Only one proposal is staged at a time, so patching again replaces it.
Review a Change to a Live Server
Approving applies the staged change and publishes it in a single step:
curl -sS -X POST "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/approve" \
-H "Authorization: Bearer $AISIX_TOKEN"
The environments a proposal names are checked again at that point, so a change proposed for an environment that was deleted while it waited is refused instead of partly applied.
Rejecting discards the proposal. The server stays approved on the configuration it was already serving, and nothing changes on the gateways:
curl -sS -X POST "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/reject" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"review_notes": "Point it at the internal mirror instead."}'
In the dashboard, a row with a staged change shows which fields the change touches. The status filter's Awaiting review option lists both unpublished submissions and live servers with a change waiting.
Update a Live Server as an Approver
PATCH /mcp_servers/{id} takes write on mcp_servers, the same permission that approves servers. An edit made through it is a publication in its own right. The server stays approved, and the control plane projects the new configuration without taking the existing one offline for another review. This lets an approver rotate an upstream credential without first withdrawing the server.
Which fields the edit changes determines whether it counts as a new review. Changing any of the following updates reviewed_at. Requests made through a user session also set reviewed_by to that user; this field is absent for admin-token actions.
name: the namespace agents address the tools byurl: the upstream itselftransportauth_type,secret,client_id,token_url,scopes: the credential and where it is presentedallowed_environments: where the server is exposedspec_content/spec_urlandapi_key_headeron OpenAPI-backed servers: the tool surface
enabled and timeout_ms are operational knobs inside an already-reviewed configuration. Changing them is not a new review, so they leave reviewed_by and reviewed_at alone.
Narrowing allowed_environments withdraws the server from every environment it no longer names as the asynchronous projection reaches each gateway.
A holder of write on mcp_server_submissions alone cannot use this route; its change is staged for review instead. See Submit a Change to a Live Server. To take a live server off the gateways, reject it.
Revoke an Approval
Rejecting an approved server that carries no staged change revokes the server itself: it is withdrawn from every environment it was serving, and callers lose its tools. Use it when an upstream stops being trustworthy.
curl -sS -X POST "$AISIX_CP/mcp_servers/$MCP_SERVER_ID/reject" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"review_notes": "Upstream credential compromised."}'
Revocation is projected to the gateways asynchronously and needs no gateway restart. To remove the registry entry entirely, delete the server instead.
Rejecting a server that does carry a staged change discards the change first, as described above. Revoking such a server takes two calls: the first discards the proposal, the second withdraws the server.
Audit Trail
Each mutation in this workflow is recorded in the organization audit log with the time and, where applicable, the server's before and after state. User-session actions include the acting user; admin-token actions do not carry a user ID.
| Action | Recorded when |
|---|---|
submit | A server is proposed for review, or a change is proposed to a live server. |
create | A server is registered directly and published. |
approve | A server is approved, or a staged change is applied. |
reject | A server is rejected, an approval is revoked, or a staged change is discarded. |
update | A server's configuration is changed. |
delete | A server is removed. |
Read them from the audit log in the dashboard, or with GET /audit_events?resource_type=mcp_server.
Next Steps
You now understand how AISIX Cloud separates MCP server submission from publication. Use these guides to register servers directly or govern caller access:
- Set Up MCP Gateway: register a server directly and verify MCP tool access.
- Control Tool Access: choose which tools a caller API key may call.
- Manage MCP Access with Policies: configure environment- and team-level tool grants.