Submit MCP Server for Review
POST /mcp_server_submissions
POST /mcp_server_submissionsInteractive request editor loads with JavaScript.
Authorization
BearerAdminToken Organization-scoped admin token. Read operations require a valid token, and write operations require a token with write permission.
In: header
Request Body
application/json
Register an MCP server or submit one for review, depending on the endpoint. Authentication secrets are encrypted and never returned.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X POST "$AISIX_CP/mcp_server_submissions" \ -H "Authorization: Bearer $AISIX_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "url": "http://example.com" }'Created
{
"mcp_server": {
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b",
"name": "string",
"type": "mcp",
"url": "http://example.com",
"spec_url": "string",
"api_key_header": "string",
"tool_names": [
"string"
],
"spec": {},
"transport": "streamable_http",
"protocol_version": "2026-07-28",
"auth_type": "none",
"client_id": "string",
"token_url": "string",
"scopes": [
"string"
],
"timeout_ms": 1,
"enabled": true,
"allowed_environments": [
"2f8fd63c-350f-4e43-9e38-47af879eaada"
],
"approval_status": "pending_review",
"submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
"submitted_at": "2019-08-24T14:15:22Z",
"reviewed_by": "92ab4dbc-1b27-40ce-b24b-7dde8f4709be",
"reviewed_at": "2019-08-24T14:15:22Z",
"review_notes": "string",
"pending_change": {
"changes": {},
"spec_url": "string",
"tool_names": [
"string"
],
"secret_set": true,
"submitted_by": "6703ac2f-9eb5-40e9-9fde-511b2dbf4be5",
"submitted_at": "2019-08-24T14:15:22Z"
},
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z"
},
"warnings": [
{
"code": "field_ignored",
"field": "string",
"min_dp_version": "string",
"affected_dp_count": 0,
"affected_dp_versions": [
"string"
]
}
]
}Request body or parameters failed validation.
{
"error": {
"code": "string",
"message": "string"
}
}Missing or invalid bearer.
{
"error": {
"code": "UNAUTHENTICATED",
"message": "no org context"
}
}Authenticated request is not permitted.
{
"error": {
"code": "CUSTOM_KEY_DISABLED",
"message": "custom API key values are disabled for this organization"
}
}Request conflicts with current resource state.
{
"error": {
"code": "CREDENTIAL_IN_USE",
"message": "models still reference this provider_key"
}
}Complete operation details and schema variants
POST /mcp_server_submissions
Submit MCP Server for Review
Proposes an upstream MCP server without publishing it. The
server is registered with approval_status set to
pending_review and is not projected to any environment, so it
cannot be discovered or called until a reviewer approves it.
This is the entry point for roles that may propose servers but
not publish them. Callers who hold write access on MCP servers
can register a server directly with POST /mcp_servers, which
creates it already approved.
Parameters
Request body
Content type: application/json
-
name(string, required): Organization-unique name used as the tool namespace prefix. Names may contain letters, digits,_,., and-, but cannot contain the reserved__separator or start or end with a separator character. -
type(string, optional): What backs this server.mcp(the default): a real upstream MCP server reached aturl.openapi: a REST API whose OpenAPI 3.x document — provided via exactly one ofspec_contentandspec_url— is turned into MCP tools, withurlas the API base URL. Fixed at creation. -
url(string, required): Upstream MCP server URL (type: mcp), or the REST API base URL generated tool calls are issued against (type: openapi). -
spec_content(string, optional): The OpenAPI 3.x document itself, as JSON or YAML text (type: openapionly; at most 1 MiB). Validated, normalized to JSON, and stored at write time — clear errors are returned for an unparseable document, Swagger 2.0, zero tool-generatable operations, and operationIds that collide after tool-name sanitization. -
spec_url(string, optional): URL of the OpenAPI document (type: openapionly), fetched server-side ONCE at write time and stored — the data plane never re-fetches it, so the tool set cannot drift with the remote document. http(s) only; hosts resolving to non-public addresses are refused unless the deployment sets AISIX_CLOUD_MCP_SPEC_ALLOW_PRIVATE_URLS=true (paste the document viaspec_contentotherwise). -
api_key_header(string, optional): Header name the API key is sent under (type: openapiwithauth_type: api_keyonly). Defaults tox-api-keywhen omitted. -
transport(string, optional): MCP transport used to reach the upstream server. -
protocol_version(string, optional): MCP protocol revision the gateway uses when connecting to this server. When omitted ornull, the gateway opens the session with theinitializehandshake, which negotiates among the pre-2026 protocol revisions — the right choice for most servers, including2026-07-28servers that keep backward compatibility. Set2026-07-28for a server that requires the stateless MCP2026-07-28revision (handshake-freeserver/discoverstartup); the connection fails rather than silently downgrading when the server does not support the configured revision. Only valid whentypeismcp. -
auth_type(string, optional): Authentication mode used when AISIX connects to the upstream server. Defaults tononewhen omitted. -
secret(string, optional): The credential — a bearer token, an API key, or an OAuth client secret depending onauth_type; write-only (envelope-encrypted on the server, never returned). Required forbearer/api_key/oauth2; must be absent/empty whenauth_typeisnone. -
client_id(string, optional): OAuth client identifier. Required whenauth_typeisoauth2; must be absent/empty otherwise. -
token_url(string, optional): OAuth token endpoint URL where the client credentials are exchanged for an access token. Required whenauth_typeisoauth2; must be absent/empty otherwise. -
scopes(array, optional): Optional OAuth scopes (only withauth_typeoauth2). Each entry is a single scope token — printable ASCII, no spaces, quotes, backslashes, commas, or braces. -
timeout_ms(integer, optional): Per-request timeout in milliseconds. -
enabled(boolean, optional): Whether the server is dispatched to the data plane. -
allowed_environments(array, optional): Environments this server is exposed to. Empty or null values expose it to no environment.
Responses
201: Createdmcp_server(object, required): An MCP tool source registered at the organization level and exposed to the environments listed inallowed_environments: either an upstream MCP (Model Context Protocol) server (type: mcp), or a REST API described by an OpenAPI document whose operations the gateway exposes as MCP tools (type: openapi). Thesecret(bearer token, API key, or OAuth client secret depending onauth_type) is write-only and never appears in this view.
A server reaches gateways only while approval_status is
approved. Until then it exists solely as a registry entry:
gateway clients cannot discover or call it.
-
mcp_server.id(string, required): MCP server ID. -
mcp_server.org_id(string, required): Organization ID that owns this MCP server. -
mcp_server.name(string, required): Organization-unique name used as the tool namespace prefix. Tool names use the<name>__<tool>format, so names may contain letters, digits,_,., and-, but cannot contain the reserved__separator or start or end with a separator character. Names are limited to 56 characters so composed tool names stay within the MCP 128-character limit. -
mcp_server.type(string, required): What backs this server: a real upstream MCP server (mcp), or a REST API described by an OpenAPI document whose operations become the server's tools (openapi). Fixed at creation. -
mcp_server.url(string, required): Upstream MCP server URL (type: mcp), or the REST API base URL generated tool calls are issued against (type: openapi). -
mcp_server.spec_url(string, optional): Where the OpenAPI document was fetched from at write time (type: openapiservers created viaspec_urlonly; empty for pasted documents). Provenance only — the data plane never re-fetches it. -
mcp_server.api_key_header(string, optional): Header name the API key is sent under fortype: openapiservers withauth_type: api_key. Empty means the defaultx-api-key. -
mcp_server.tool_names(array, optional): The MCP tool names generated from the stored OpenAPI document (type: openapionly), validated collision-free at write time. Exposed to clients as<name>__<tool>. -
mcp_server.spec(object, optional): The stored, normalized OpenAPI document (type: openapionly). Returned on single-server reads; omitted from list responses. -
mcp_server.transport(string, required): MCP transport used to reach the upstream server. -
mcp_server.protocol_version(string, optional): MCP protocol revision the gateway uses when connecting to this server. When unset, the gateway opens the session with theinitializehandshake, which negotiates among the pre-2026 protocol revisions — the right choice for most servers, including2026-07-28servers that keep backward compatibility. Set2026-07-28for a server that requires the stateless MCP2026-07-28revision (handshake-freeserver/discoverstartup); the connection fails rather than silently downgrading when the server does not support the configured revision. Only valid whentypeismcp. -
mcp_server.auth_type(string, required): How AISIX authenticates to the upstream server.none= no credential;bearer= a bearer token supplied assecret;api_key= an API key supplied assecretand sent as thex-api-keyheader (overridable viaapi_key_headerontype: openapiservers);oauth2= OAuth 2.0 client credentials, wheresecretis the client secret and AISIX mints its own access token fromclient_id+token_url(+ optionalscopes). -
mcp_server.client_id(string, optional): OAuth client identifier for the client credentials grant. Present only whenauth_typeisoauth2. -
mcp_server.token_url(string, optional): OAuth token endpoint where the client credentials are exchanged for an access token. Present only whenauth_typeisoauth2. -
mcp_server.scopes(array, optional): OAuth scopes requested in the token exchange (joined with spaces into thescopeparameter). Present only whenauth_typeisoauth2and scopes were configured. -
mcp_server.timeout_ms(integer, optional): Per-request timeout in milliseconds. AISIX applies its default when this value is unset. -
mcp_server.enabled(boolean, required): Whether the server is dispatched to the data plane. -
mcp_server.allowed_environments(array, required): Environment UUIDs this server is projected to. Empty array = projected to no environment. -
mcp_server.approval_status(string, required): Where the server stands in the review workflow.pending_review= submitted and waiting for a decision;approved= published toallowed_environmentsand reachable by gateway clients;rejected= refused, or an approval that was revoked. Patching an approved server throughPATCH /mcp_servers/{id}keeps it approved — that caller may approve servers, so the edit publishes directly.PATCH /mcp_server_submissions/{id}revises a server that is not published yet and leaves it pending; against an approved server it stages the change inpending_changeand leaves this status untouched, so the server keeps serving while the proposal waits. -
mcp_server.submitted_by(string, optional): User who last submitted this server for review. Absent when the submission came from an admin token. -
mcp_server.submitted_at(string, optional): Time of the most recent submission. -
mcp_server.reviewed_by(string, optional): User who made the current approval decision. Absent when the decision came from an admin token, or when no decision has been made yet. -
mcp_server.reviewed_at(string, optional): Time of the current approval decision. -
mcp_server.review_notes(string, optional): Reviewer's note left with the current decision. -
mcp_server.pending_change(object, optional): A change proposed against this server and waiting for review, submitted throughPATCH /mcp_server_submissions/{mcp_server_id}. Absent when nothing is waiting.
Every other field on this server keeps describing the
configuration that is projected and serving: a proposal
changes nothing until it is approved. POST /mcp_servers/{id}/approve applies it, POST /mcp_servers/{id}/reject discards it, and neither takes the
server off the gateways.
-
mcp_server.pending_change.changes(object, required): The fields the proposal would change, in the shape of an update request. A proposed credential is never echoed here — seesecret_set. -
mcp_server.pending_change.spec_url(string, optional): Fetch provenance of a proposed replacement OpenAPI document, when the proposal fetched one. -
mcp_server.pending_change.tool_names(array, optional): The tool surface a proposed replacement OpenAPI document would generate, so a reviewer sees what the tools become before approving it. -
mcp_server.pending_change.secret_set(boolean, optional): True when the proposal rotates the upstream credential. The value itself is stored encrypted and never returned. -
mcp_server.pending_change.submitted_by(string, optional): User who proposed the change. -
mcp_server.pending_change.submitted_at(string, optional): Time the change was proposed. -
mcp_server.created_at(string, required): Time when the MCP server was created. -
mcp_server.updated_at(string, required): Time when the MCP server was last updated. -
warnings(array, optional): Present on save and approval operations when some data plane nodes in the environments this server is exposed to run a gateway version that will not execute part of the saved configuration. Never present on reads. -
warnings[].code(string, required): How affected nodes treat the saved resource.field_ignored: the resource stays in service on those nodes but the named field has no effect there — beware when the field is restrictive, since the restriction is silently not enforced.row_rejected: those nodes refuse the whole resource, so it stops serving there entirely (or, if a previously accepted version exists, they keep serving the old values). -
warnings[].field(string, required): Dot-separated path of the field that triggered the warning, as delivered to gateway nodes. -
warnings[].min_dp_version(string, required): Oldest gateway version that fully executes the field. The literal valueunreleasedmeans no released gateway version executes it yet. -
warnings[].affected_dp_count(integer, required): Number of currently registered nodes in the environment running an older gateway version thanmin_dp_version. -
warnings[].affected_dp_versions(array, required): Distinct gateway versions reported by the affected nodes, capped at five entries. Nodes that report no version appear asunknown. -
400: Request body or parameters failed validation. -
error(object, required): Error details. -
error.code(string, required): Machine-readable identifier. Examples:UNAUTHENTICATED,INVALID_REQUEST,MASTER_KEY_UNSET,INTERNAL. -
error.message(string, required): Human-readable explanation; safe to surface to operators. -
401: Missing or invalid bearer. Response fields (application/json): identical toPOST /mcp_server_submissions, response 400 above. -
403: Authenticated request is not permitted. Response fields (application/json): identical toPOST /mcp_server_submissions, response 400 above. -
409: Request conflicts with current resource state. Response fields (application/json): identical toPOST /mcp_server_submissions, response 400 above.
cURL
curl -X POST '$AISIX_CP/mcp_server_submissions' -H 'Authorization: Bearer $AISIX_TOKEN'