From 15402929557610440f4e263f2aaae8cad263d49a Mon Sep 17 00:00:00 2001 From: kayx23 Date: Tue, 30 Jun 2026 16:00:22 +0800 Subject: [PATCH] docs(admin): add MCP server OpenAPI reference --- crates/aisix-admin/src/openapi.rs | 397 +++++++++++++++++++++++ crates/aisix-core/src/models/schema.rs | 44 ++- schemas/resources/mcp_server.schema.json | 3 + 3 files changed, 443 insertions(+), 1 deletion(-) diff --git a/crates/aisix-admin/src/openapi.rs b/crates/aisix-admin/src/openapi.rs index 6b2fa42b..0936584d 100644 --- a/crates/aisix-admin/src/openapi.rs +++ b/crates/aisix-admin/src/openapi.rs @@ -1349,6 +1349,362 @@ const OPENAPI_JSON_BASE: &str = r##"{ "description": "Delete a provider key resource by ID." } }, + "/admin/v1/mcp_servers": { + "get": { + "summary": "List MCP Servers", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/McpServerEntry" + } + } + } + } + }, + "401": { + "description": "Missing or invalid admin key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + }, + "500": { + "description": "Configuration store operation failed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + } + }, + "tags": [ + "MCP Servers" + ], + "description": "List registered upstream MCP server resources." + }, + "post": { + "summary": "Create MCP Server", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpServer" + } + } + }, + "description": "Upstream MCP server configuration." + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpServerEntry" + } + } + } + }, + "400": { + "description": "Schema validation failed, the JSON body is malformed, `display_name` contains the reserved `__` separator, or bearer auth is missing `secret`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + }, + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Missing or invalid admin key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + }, + "409": { + "description": "Duplicate display_name", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + }, + "413": { + "description": "JSON request body exceeds the admin body-size limit", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "415": { + "description": "Missing or unsupported JSON content type", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Configuration store operation failed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + } + }, + "tags": [ + "MCP Servers" + ], + "description": "Create an upstream MCP server resource. The gateway validates the payload, rejects duplicate `display_name` values, and returns the stored resource entry." + } + }, + "/admin/v1/mcp_servers/{id}": { + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "MCP server resource ID generated by the Admin API.", + "example": "1d95ac57-7f27-46a4-b5a3-55d3c3ad0a12" + } + ], + "get": { + "summary": "Get MCP Server by ID", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpServerEntry" + } + } + } + }, + "401": { + "description": "Missing or invalid admin key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + }, + "500": { + "description": "Configuration store operation failed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + } + }, + "tags": [ + "MCP Servers" + ], + "description": "Get an upstream MCP server resource by ID." + }, + "put": { + "summary": "Update MCP Server by ID", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpServer" + } + } + }, + "description": "Replacement upstream MCP server configuration." + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/McpServerEntry" + } + } + } + }, + "400": { + "description": "Schema validation failed, the JSON body is malformed, `display_name` contains the reserved `__` separator, or bearer auth is missing `secret`", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + }, + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Missing or invalid admin key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + }, + "409": { + "description": "Duplicate display_name", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + }, + "413": { + "description": "JSON request body exceeds the admin body-size limit", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "415": { + "description": "Missing or unsupported JSON content type", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Configuration store operation failed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + } + }, + "tags": [ + "MCP Servers" + ], + "description": "Update an upstream MCP server resource by ID. The gateway validates the payload, rejects duplicate `display_name` values, preserves the resource ID, and increments the revision." + }, + "delete": { + "summary": "Delete MCP Server by ID", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid admin key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + }, + "404": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + }, + "500": { + "description": "Configuration store operation failed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminError" + } + } + } + } + }, + "tags": [ + "MCP Servers" + ], + "description": "Delete an upstream MCP server resource by ID." + } + }, "/admin/v1/guardrails": { "get": { "summary": "List Guardrails", @@ -2879,6 +3235,31 @@ const OPENAPI_JSON_BASE: &str = r##"{ }, "description": "Stored Admin API resource entry." }, + "McpServerEntry": { + "type": "object", + "required": [ + "id", + "value", + "revision" + ], + "properties": { + "id": { + "type": "string", + "description": "Resource ID generated by the Admin API.", + "example": "1d95ac57-7f27-46a4-b5a3-55d3c3ad0a12" + }, + "value": { + "$ref": "#/components/schemas/McpServer", + "description": "Stored upstream MCP server configuration." + }, + "revision": { + "type": "integer", + "description": "Monotonic resource revision. Create operations start at 1, and update operations increment the revision.", + "example": 1845 + } + }, + "description": "Stored Admin API resource entry." + }, "GuardrailEntry": { "type": "object", "required": [ @@ -3113,6 +3494,10 @@ const OPENAPI_JSON_BASE: &str = r##"{ "name": "Provider Keys", "description": "Upstream provider credentials referenced by models." }, + { + "name": "MCP Servers", + "description": "Upstream MCP servers exposed through the gateway MCP endpoint." + }, { "name": "Guardrails", "description": "Guardrail policies attached to proxy traffic." @@ -3166,6 +3551,10 @@ const RESOURCE_SCHEMAS: &[(&str, &str)] = &[ "ProviderKey", include_str!("../../../schemas/resources/provider_key.schema.json"), ), + ( + "McpServer", + include_str!("../../../schemas/resources/mcp_server.schema.json"), + ), ( "Guardrail", include_str!("../../../schemas/resources/guardrail.schema.json"), @@ -3650,6 +4039,8 @@ mod tests { "/admin/v1/apikeys/{id}/rotate", "/admin/v1/provider_keys", "/admin/v1/provider_keys/{id}", + "/admin/v1/mcp_servers", + "/admin/v1/mcp_servers/{id}", "/admin/v1/guardrails", "/admin/v1/guardrails/{id}", "/admin/v1/cache_policies", @@ -3681,6 +4072,8 @@ mod tests { "ApiKeyRotateResponse", "ProviderKey", "ProviderKeyEntry", + "McpServer", + "McpServerEntry", "Guardrail", "GuardrailEntry", "CachePolicy", @@ -3728,6 +4121,8 @@ mod tests { "/admin/v1/apikeys/{id}/rotate", "/admin/v1/provider_keys", "/admin/v1/provider_keys/{id}", + "/admin/v1/mcp_servers", + "/admin/v1/mcp_servers/{id}", "/admin/v1/guardrails", "/admin/v1/guardrails/{id}", "/admin/v1/cache_policies", @@ -4270,6 +4665,8 @@ mod tests { ("/admin/v1/apikeys/{id}", "put"), ("/admin/v1/provider_keys", "post"), ("/admin/v1/provider_keys/{id}", "put"), + ("/admin/v1/mcp_servers", "post"), + ("/admin/v1/mcp_servers/{id}", "put"), ("/admin/v1/guardrails", "post"), ("/admin/v1/guardrails/{id}", "put"), ("/admin/v1/cache_policies", "post"), diff --git a/crates/aisix-core/src/models/schema.rs b/crates/aisix-core/src/models/schema.rs index 1d5fda37..61a8bba2 100644 --- a/crates/aisix-core/src/models/schema.rs +++ b/crates/aisix-core/src/models/schema.rs @@ -189,7 +189,49 @@ pub fn provider_key_root_schema() -> Value { /// [`McpTransport`](crate::models::McpTransport) / /// [`McpAuthType`](crate::models::McpAuthType) enums. pub fn mcp_server_root_schema() -> Value { - struct_root_schema::(true) + let mut schema = struct_root_schema::(true); + if let Some(Value::Object(defs)) = schema.get_mut("definitions") { + title_single_value_enum_variants( + defs, + "McpAuthType", + &[("none", "No authentication"), ("bearer", "Bearer token")], + ); + title_single_value_enum_variants( + defs, + "McpTransport", + &[("streamable_http", "Streamable HTTP")], + ); + } + schema +} + +fn title_single_value_enum_variants( + defs: &mut serde_json::Map, + schema_name: &str, + titles: &[(&str, &str)], +) { + let Some(Value::Array(branches)) = defs.get_mut(schema_name).and_then(|d| d.get_mut("oneOf")) + else { + return; + }; + for branch in branches.iter_mut() { + let Some(branch) = branch.as_object_mut() else { + continue; + }; + let Some(value) = branch + .get("enum") + .and_then(|v| v.as_array()) + .and_then(|values| values.first()) + .and_then(|v| v.as_str()) + else { + continue; + }; + if let Some((_, title)) = titles.iter().find(|(expected, _)| *expected == value) { + branch + .entry("title".to_string()) + .or_insert_with(|| Value::String((*title).to_string())); + } + } } /// Canonical JSON Schema for the `guardrail` resource, derived from the diff --git a/schemas/resources/mcp_server.schema.json b/schemas/resources/mcp_server.schema.json index eb128ed7..26c59462 100644 --- a/schemas/resources/mcp_server.schema.json +++ b/schemas/resources/mcp_server.schema.json @@ -10,6 +10,7 @@ "enum": [ "none" ], + "title": "No authentication", "type": "string" }, { @@ -17,6 +18,7 @@ "enum": [ "bearer" ], + "title": "Bearer token", "type": "string" } ] @@ -29,6 +31,7 @@ "enum": [ "streamable_http" ], + "title": "Streamable HTTP", "type": "string" } ]