From f84f73ca23a38ae78ede32823454f21b70ec3b53 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Tue, 11 Aug 2026 11:50:14 +0000 Subject: [PATCH] docs: complete swagger annotations for organization-scoped MCP routes The moved and newly introduced MCP endpoints carried only @Summary and the apidocgen skip marker. Add the full annotation set (@ID, @Security, @Tags, params, responses, @Router) matching the ACL endpoints, and regenerate the API reference. --- coderd/apidoc/docs.go | 638 ++++++++++++++++++++++++++++++++++ coderd/apidoc/swagger.json | 580 +++++++++++++++++++++++++++++++ coderd/mcp.go | 58 ++++ docs/manifest.json | 4 + docs/reference/api/mcp.md | 6 + docs/reference/api/schemas.md | 236 +++++++++++++ 6 files changed, 1522 insertions(+) create mode 100644 docs/reference/api/mcp.md diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index f810c261fcf..371aaf778dc 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -1101,6 +1101,316 @@ const docTemplate = `{ ] } }, + "/api/experimental/mcp-servers/{mcpserverconfig}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "MCP" + ], + "summary": "Get MCP server config", + "operationId": "get-mcp-server-config", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpserverconfig", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.MCPServerConfig" + } + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + }, + "delete": { + "tags": [ + "MCP" + ], + "summary": "Delete MCP server config", + "operationId": "delete-mcp-server-config", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpserverconfig", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + }, + "patch": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "MCP" + ], + "summary": "Update MCP server config", + "operationId": "update-mcp-server-config", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpserverconfig", + "in": "path", + "required": true + }, + { + "description": "Update MCP server config request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.UpdateMCPServerConfigRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.MCPServerConfig" + } + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + } + }, + "/api/experimental/mcp-servers/{mcpserverconfig}/oauth2/connect": { + "get": { + "tags": [ + "MCP" + ], + "summary": "Initiate MCP server OAuth2 connect", + "operationId": "initiate-mcp-server-oauth2-connect", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpserverconfig", + "in": "path", + "required": true + } + ], + "responses": { + "307": { + "description": "Temporary Redirect" + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + } + }, + "/api/experimental/mcp-servers/{mcpserverconfig}/oauth2/disconnect": { + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "MCP" + ], + "summary": "Disconnect MCP server OAuth2 token", + "operationId": "disconnect-mcp-server-oauth2-token", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpserverconfig", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.MCPServerOAuth2DisconnectResponse" + } + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + } + }, + "/api/experimental/mcp/servers/{mcpServer}/oauth2/callback": { + "get": { + "produces": [ + "text/html" + ], + "tags": [ + "MCP" + ], + "summary": "Handle MCP server OAuth2 callback", + "operationId": "handle-mcp-server-oauth2-callback", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpServer", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + } + }, + "/api/experimental/organizations/{organization}/mcp-servers": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "MCP" + ], + "summary": "List MCP server configs", + "operationId": "list-mcp-server-configs", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Organization ID", + "name": "organization", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.MCPServerConfig" + } + } + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "MCP" + ], + "summary": "Create MCP server config", + "operationId": "create-mcp-server-config", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Organization ID", + "name": "organization", + "in": "path", + "required": true + }, + { + "description": "Create MCP server config request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.CreateMCPServerConfigRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/codersdk.MCPServerConfig" + } + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + } + }, "/api/experimental/users/{user}/skills": { "get": { "produces": [ @@ -19074,6 +19384,115 @@ const docTemplate = `{ } } }, + "codersdk.CreateMCPServerConfigRequest": { + "type": "object", + "required": [ + "auth_type", + "availability", + "display_name", + "slug", + "transport", + "url" + ], + "properties": { + "allow_in_plan_mode": { + "type": "boolean" + }, + "api_key_header": { + "type": "string" + }, + "api_key_value": { + "type": "string" + }, + "auth_type": { + "type": "string", + "enum": [ + "none", + "oauth2", + "api_key", + "custom_headers", + "user_oidc" + ] + }, + "availability": { + "type": "string", + "enum": [ + "force_on", + "default_on", + "default_off" + ] + }, + "custom_headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "display_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_coder_headers": { + "description": "ForwardCoderHeaders, when true, forwards Coder identity\nheaders on every outgoing MCP request. See MCPServerConfig.", + "type": "boolean" + }, + "icon_url": { + "type": "string" + }, + "model_intent": { + "type": "boolean" + }, + "oauth2_auth_url": { + "type": "string" + }, + "oauth2_client_id": { + "type": "string" + }, + "oauth2_client_secret": { + "type": "string" + }, + "oauth2_revocation_url": { + "description": "OAuth2RevocationURL is the provider's RFC 7009 revocation\nendpoint; auto-populated by OAuth2 discovery when omitted.", + "type": "string" + }, + "oauth2_scopes": { + "type": "string" + }, + "oauth2_token_url": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "tool_allow_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "tool_deny_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "transport": { + "type": "string", + "enum": [ + "streamable_http", + "sse" + ] + }, + "url": { + "type": "string" + } + } + }, "codersdk.CreateOrganizationRequest": { "type": "object", "required": [ @@ -21387,6 +21806,124 @@ const docTemplate = `{ } } }, + "codersdk.MCPServerConfig": { + "type": "object", + "properties": { + "allow_in_plan_mode": { + "type": "boolean" + }, + "api_key_header": { + "description": "API key fields (only populated for admins).", + "type": "string" + }, + "auth_connected": { + "description": "Per-user state (populated for non-admin requests).", + "type": "boolean" + }, + "auth_type": { + "description": "\"none\", \"oauth2\", \"api_key\", \"custom_headers\", \"user_oidc\"", + "type": "string" + }, + "availability": { + "description": "Availability policy set by admin.", + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "description": { + "type": "string" + }, + "display_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_coder_headers": { + "description": "ForwardCoderHeaders forwards the same Coder identity headers we\nsend to LLM providers (X-Coder-Owner-Id, X-Coder-Chat-Id, and the\noptional X-Coder-Subchat-Id and X-Coder-Workspace-Id) to this\nMCP server on every request. Off by default to avoid leaking\nchat identity to third-party servers.", + "type": "boolean" + }, + "has_api_key": { + "type": "boolean" + }, + "has_custom_headers": { + "type": "boolean" + }, + "has_oauth2_secret": { + "type": "boolean" + }, + "icon_url": { + "type": "string" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "model_intent": { + "type": "boolean" + }, + "oauth2_auth_url": { + "type": "string" + }, + "oauth2_client_id": { + "description": "OAuth2 fields (only populated for admins).", + "type": "string" + }, + "oauth2_revocation_url": { + "type": "string" + }, + "oauth2_scopes": { + "type": "string" + }, + "oauth2_token_url": { + "type": "string" + }, + "organization_id": { + "type": "string", + "format": "uuid" + }, + "slug": { + "type": "string" + }, + "tool_allow_list": { + "description": "Tool governance.", + "type": "array", + "items": { + "type": "string" + } + }, + "tool_deny_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "transport": { + "description": "\"streamable_http\" or \"sse\"", + "type": "string" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "url": { + "type": "string" + } + } + }, + "codersdk.MCPServerOAuth2DisconnectResponse": { + "type": "object", + "properties": { + "token_revocation_error": { + "type": "string" + }, + "token_revoked": { + "type": "boolean" + } + } + }, "codersdk.MatchedProvisioners": { "type": "object", "properties": { @@ -26055,6 +26592,107 @@ const docTemplate = `{ } } }, + "codersdk.UpdateMCPServerConfigRequest": { + "type": "object", + "properties": { + "allow_in_plan_mode": { + "type": "boolean" + }, + "api_key_header": { + "type": "string" + }, + "api_key_value": { + "type": "string" + }, + "auth_type": { + "type": "string", + "enum": [ + "none", + "oauth2", + "api_key", + "custom_headers", + "user_oidc" + ] + }, + "availability": { + "type": "string", + "enum": [ + "force_on", + "default_on", + "default_off" + ] + }, + "custom_headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "display_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_coder_headers": { + "description": "ForwardCoderHeaders, when set, updates whether Coder identity\nheaders are forwarded on every outgoing MCP request.", + "type": "boolean" + }, + "icon_url": { + "type": "string" + }, + "model_intent": { + "type": "boolean" + }, + "oauth2_auth_url": { + "type": "string" + }, + "oauth2_client_id": { + "type": "string" + }, + "oauth2_client_secret": { + "type": "string" + }, + "oauth2_revocation_url": { + "description": "OAuth2RevocationURL is validated in the handler because a\nvalidate tag would reject the pointer to \"\" that clears it.", + "type": "string" + }, + "oauth2_scopes": { + "type": "string" + }, + "oauth2_token_url": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "tool_allow_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "tool_deny_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "transport": { + "type": "string", + "enum": [ + "streamable_http", + "sse" + ] + }, + "url": { + "type": "string" + } + } + }, "codersdk.UpdateOrganizationRequest": { "type": "object", "properties": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 32dd9832b00..1e9169d11a5 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -974,6 +974,284 @@ ] } }, + "/api/experimental/mcp-servers/{mcpserverconfig}": { + "get": { + "produces": ["application/json"], + "tags": ["MCP"], + "summary": "Get MCP server config", + "operationId": "get-mcp-server-config", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpserverconfig", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.MCPServerConfig" + } + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + }, + "delete": { + "tags": ["MCP"], + "summary": "Delete MCP server config", + "operationId": "delete-mcp-server-config", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpserverconfig", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + }, + "patch": { + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["MCP"], + "summary": "Update MCP server config", + "operationId": "update-mcp-server-config", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpserverconfig", + "in": "path", + "required": true + }, + { + "description": "Update MCP server config request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.UpdateMCPServerConfigRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.MCPServerConfig" + } + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + } + }, + "/api/experimental/mcp-servers/{mcpserverconfig}/oauth2/connect": { + "get": { + "tags": ["MCP"], + "summary": "Initiate MCP server OAuth2 connect", + "operationId": "initiate-mcp-server-oauth2-connect", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpserverconfig", + "in": "path", + "required": true + } + ], + "responses": { + "307": { + "description": "Temporary Redirect" + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + } + }, + "/api/experimental/mcp-servers/{mcpserverconfig}/oauth2/disconnect": { + "delete": { + "produces": ["application/json"], + "tags": ["MCP"], + "summary": "Disconnect MCP server OAuth2 token", + "operationId": "disconnect-mcp-server-oauth2-token", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpserverconfig", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.MCPServerOAuth2DisconnectResponse" + } + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + } + }, + "/api/experimental/mcp/servers/{mcpServer}/oauth2/callback": { + "get": { + "produces": ["text/html"], + "tags": ["MCP"], + "summary": "Handle MCP server OAuth2 callback", + "operationId": "handle-mcp-server-oauth2-callback", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "MCP server config ID", + "name": "mcpServer", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + } + }, + "/api/experimental/organizations/{organization}/mcp-servers": { + "get": { + "produces": ["application/json"], + "tags": ["MCP"], + "summary": "List MCP server configs", + "operationId": "list-mcp-server-configs", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Organization ID", + "name": "organization", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.MCPServerConfig" + } + } + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + }, + "post": { + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["MCP"], + "summary": "Create MCP server config", + "operationId": "create-mcp-server-config", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "Organization ID", + "name": "organization", + "in": "path", + "required": true + }, + { + "description": "Create MCP server config request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.CreateMCPServerConfigRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/codersdk.MCPServerConfig" + } + } + }, + "security": [ + { + "CoderSessionToken": [] + } + ], + "x-apidocgen": { + "skip": true + } + } + }, "/api/experimental/users/{user}/skills": { "get": { "produces": ["application/json"], @@ -17252,6 +17530,102 @@ } } }, + "codersdk.CreateMCPServerConfigRequest": { + "type": "object", + "required": [ + "auth_type", + "availability", + "display_name", + "slug", + "transport", + "url" + ], + "properties": { + "allow_in_plan_mode": { + "type": "boolean" + }, + "api_key_header": { + "type": "string" + }, + "api_key_value": { + "type": "string" + }, + "auth_type": { + "type": "string", + "enum": ["none", "oauth2", "api_key", "custom_headers", "user_oidc"] + }, + "availability": { + "type": "string", + "enum": ["force_on", "default_on", "default_off"] + }, + "custom_headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "display_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_coder_headers": { + "description": "ForwardCoderHeaders, when true, forwards Coder identity\nheaders on every outgoing MCP request. See MCPServerConfig.", + "type": "boolean" + }, + "icon_url": { + "type": "string" + }, + "model_intent": { + "type": "boolean" + }, + "oauth2_auth_url": { + "type": "string" + }, + "oauth2_client_id": { + "type": "string" + }, + "oauth2_client_secret": { + "type": "string" + }, + "oauth2_revocation_url": { + "description": "OAuth2RevocationURL is the provider's RFC 7009 revocation\nendpoint; auto-populated by OAuth2 discovery when omitted.", + "type": "string" + }, + "oauth2_scopes": { + "type": "string" + }, + "oauth2_token_url": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "tool_allow_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "tool_deny_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "transport": { + "type": "string", + "enum": ["streamable_http", "sse"] + }, + "url": { + "type": "string" + } + } + }, "codersdk.CreateOrganizationRequest": { "type": "object", "required": ["name"], @@ -19464,6 +19838,124 @@ } } }, + "codersdk.MCPServerConfig": { + "type": "object", + "properties": { + "allow_in_plan_mode": { + "type": "boolean" + }, + "api_key_header": { + "description": "API key fields (only populated for admins).", + "type": "string" + }, + "auth_connected": { + "description": "Per-user state (populated for non-admin requests).", + "type": "boolean" + }, + "auth_type": { + "description": "\"none\", \"oauth2\", \"api_key\", \"custom_headers\", \"user_oidc\"", + "type": "string" + }, + "availability": { + "description": "Availability policy set by admin.", + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "description": { + "type": "string" + }, + "display_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_coder_headers": { + "description": "ForwardCoderHeaders forwards the same Coder identity headers we\nsend to LLM providers (X-Coder-Owner-Id, X-Coder-Chat-Id, and the\noptional X-Coder-Subchat-Id and X-Coder-Workspace-Id) to this\nMCP server on every request. Off by default to avoid leaking\nchat identity to third-party servers.", + "type": "boolean" + }, + "has_api_key": { + "type": "boolean" + }, + "has_custom_headers": { + "type": "boolean" + }, + "has_oauth2_secret": { + "type": "boolean" + }, + "icon_url": { + "type": "string" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "model_intent": { + "type": "boolean" + }, + "oauth2_auth_url": { + "type": "string" + }, + "oauth2_client_id": { + "description": "OAuth2 fields (only populated for admins).", + "type": "string" + }, + "oauth2_revocation_url": { + "type": "string" + }, + "oauth2_scopes": { + "type": "string" + }, + "oauth2_token_url": { + "type": "string" + }, + "organization_id": { + "type": "string", + "format": "uuid" + }, + "slug": { + "type": "string" + }, + "tool_allow_list": { + "description": "Tool governance.", + "type": "array", + "items": { + "type": "string" + } + }, + "tool_deny_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "transport": { + "description": "\"streamable_http\" or \"sse\"", + "type": "string" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "url": { + "type": "string" + } + } + }, + "codersdk.MCPServerOAuth2DisconnectResponse": { + "type": "object", + "properties": { + "token_revocation_error": { + "type": "string" + }, + "token_revoked": { + "type": "boolean" + } + } + }, "codersdk.MatchedProvisioners": { "type": "object", "properties": { @@ -23947,6 +24439,94 @@ } } }, + "codersdk.UpdateMCPServerConfigRequest": { + "type": "object", + "properties": { + "allow_in_plan_mode": { + "type": "boolean" + }, + "api_key_header": { + "type": "string" + }, + "api_key_value": { + "type": "string" + }, + "auth_type": { + "type": "string", + "enum": ["none", "oauth2", "api_key", "custom_headers", "user_oidc"] + }, + "availability": { + "type": "string", + "enum": ["force_on", "default_on", "default_off"] + }, + "custom_headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "display_name": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "forward_coder_headers": { + "description": "ForwardCoderHeaders, when set, updates whether Coder identity\nheaders are forwarded on every outgoing MCP request.", + "type": "boolean" + }, + "icon_url": { + "type": "string" + }, + "model_intent": { + "type": "boolean" + }, + "oauth2_auth_url": { + "type": "string" + }, + "oauth2_client_id": { + "type": "string" + }, + "oauth2_client_secret": { + "type": "string" + }, + "oauth2_revocation_url": { + "description": "OAuth2RevocationURL is validated in the handler because a\nvalidate tag would reject the pointer to \"\" that clears it.", + "type": "string" + }, + "oauth2_scopes": { + "type": "string" + }, + "oauth2_token_url": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "tool_allow_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "tool_deny_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "transport": { + "type": "string", + "enum": ["streamable_http", "sse"] + }, + "url": { + "type": "string" + } + } + }, "codersdk.UpdateOrganizationRequest": { "type": "object", "properties": { diff --git a/coderd/mcp.go b/coderd/mcp.go index b104c569370..971f82570ac 100644 --- a/coderd/mcp.go +++ b/coderd/mcp.go @@ -141,6 +141,13 @@ func shouldRefreshOIDCToken(link database.UserLink) (bool, time.Time) { } // @Summary List MCP server configs +// @ID list-mcp-server-configs +// @Security CoderSessionToken +// @Tags MCP +// @Produce json +// @Param organization path string true "Organization ID" format(uuid) +// @Success 200 {array} codersdk.MCPServerConfig +// @Router /api/experimental/organizations/{organization}/mcp-servers [get] // @x-apidocgen {"skip": true} // EXPERIMENTAL: this endpoint is experimental and is subject to change. // @@ -215,6 +222,15 @@ func (api *API) listMCPServerConfigs(rw http.ResponseWriter, r *http.Request) { } // @Summary Create MCP server config +// @ID create-mcp-server-config +// @Security CoderSessionToken +// @Tags MCP +// @Accept json +// @Produce json +// @Param organization path string true "Organization ID" format(uuid) +// @Param request body codersdk.CreateMCPServerConfigRequest true "Create MCP server config request" +// @Success 201 {object} codersdk.MCPServerConfig +// @Router /api/experimental/organizations/{organization}/mcp-servers [post] // @x-apidocgen {"skip": true} // EXPERIMENTAL: this endpoint is experimental and is subject to change. // @@ -515,6 +531,13 @@ func (api *API) createMCPServerConfig(rw http.ResponseWriter, r *http.Request) { } // @Summary Get MCP server config +// @ID get-mcp-server-config +// @Security CoderSessionToken +// @Tags MCP +// @Produce json +// @Param mcpserverconfig path string true "MCP server config ID" format(uuid) +// @Success 200 {object} codersdk.MCPServerConfig +// @Router /api/experimental/mcp-servers/{mcpserverconfig} [get] // @x-apidocgen {"skip": true} // EXPERIMENTAL: this endpoint is experimental and is subject to change. // @@ -570,6 +593,15 @@ func (api *API) getMCPServerConfigForMutation(rw http.ResponseWriter, r *http.Re } // @Summary Update MCP server config +// @ID update-mcp-server-config +// @Security CoderSessionToken +// @Tags MCP +// @Accept json +// @Produce json +// @Param mcpserverconfig path string true "MCP server config ID" format(uuid) +// @Param request body codersdk.UpdateMCPServerConfigRequest true "Update MCP server config request" +// @Success 200 {object} codersdk.MCPServerConfig +// @Router /api/experimental/mcp-servers/{mcpserverconfig} [patch] // @x-apidocgen {"skip": true} // EXPERIMENTAL: this endpoint is experimental and is subject to change. // @@ -879,6 +911,12 @@ func (api *API) updateMCPServerConfig(rw http.ResponseWriter, r *http.Request) { } // @Summary Delete MCP server config +// @ID delete-mcp-server-config +// @Security CoderSessionToken +// @Tags MCP +// @Param mcpserverconfig path string true "MCP server config ID" format(uuid) +// @Success 204 +// @Router /api/experimental/mcp-servers/{mcpserverconfig} [delete] // @x-apidocgen {"skip": true} // EXPERIMENTAL: this endpoint is experimental and is subject to change. func (api *API) deleteMCPServerConfig(rw http.ResponseWriter, r *http.Request) { @@ -900,6 +938,12 @@ func (api *API) deleteMCPServerConfig(rw http.ResponseWriter, r *http.Request) { } // @Summary Initiate MCP server OAuth2 connect +// @ID initiate-mcp-server-oauth2-connect +// @Security CoderSessionToken +// @Tags MCP +// @Param mcpserverconfig path string true "MCP server config ID" format(uuid) +// @Success 307 +// @Router /api/experimental/mcp-servers/{mcpserverconfig}/oauth2/connect [get] // @x-apidocgen {"skip": true} // EXPERIMENTAL: this endpoint is experimental and is subject to change. // Redirects the user to the MCP server's OAuth2 authorization URL. @@ -976,6 +1020,13 @@ func (api *API) mcpServerOAuth2Connect(rw http.ResponseWriter, r *http.Request) } // @Summary Handle MCP server OAuth2 callback +// @ID handle-mcp-server-oauth2-callback +// @Security CoderSessionToken +// @Tags MCP +// @Produce html +// @Param mcpServer path string true "MCP server config ID" format(uuid) +// @Success 200 +// @Router /api/experimental/mcp/servers/{mcpServer}/oauth2/callback [get] // @x-apidocgen {"skip": true} // EXPERIMENTAL: this endpoint is experimental and is subject to change. // Exchanges the authorization code for tokens and stores them. @@ -1151,6 +1202,13 @@ func (api *API) mcpServerOAuth2Callback(rw http.ResponseWriter, r *http.Request) } // @Summary Disconnect MCP server OAuth2 token +// @ID disconnect-mcp-server-oauth2-token +// @Security CoderSessionToken +// @Tags MCP +// @Produce json +// @Param mcpserverconfig path string true "MCP server config ID" format(uuid) +// @Success 200 {object} codersdk.MCPServerOAuth2DisconnectResponse +// @Router /api/experimental/mcp-servers/{mcpserverconfig}/oauth2/disconnect [delete] // @x-apidocgen {"skip": true} // EXPERIMENTAL: this endpoint is experimental and is subject to change. // Removes the user's stored OAuth2 token for an MCP server. diff --git a/docs/manifest.json b/docs/manifest.json index d9ae6fa5447..9f4acc3c083 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1636,6 +1636,10 @@ "title": "Insights", "path": "./reference/api/insights.md" }, + { + "title": "MCP", + "path": "./reference/api/mcp.md" + }, { "title": "Members", "path": "./reference/api/members.md" diff --git a/docs/reference/api/mcp.md b/docs/reference/api/mcp.md new file mode 100644 index 00000000000..9feb9375878 --- /dev/null +++ b/docs/reference/api/mcp.md @@ -0,0 +1,6 @@ +--- +# Code generated by make gen. DO NOT EDIT. +title: MCP +--- + + diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 57b00a38e66..1b212729ce1 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -5002,6 +5002,80 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `name` | string | true | | | | `quota_allowance` | integer | false | | | +## codersdk.CreateMCPServerConfigRequest + +```json +{ + "allow_in_plan_mode": true, + "api_key_header": "string", + "api_key_value": "string", + "auth_type": "none", + "availability": "force_on", + "custom_headers": { + "property1": "string", + "property2": "string" + }, + "description": "string", + "display_name": "string", + "enabled": true, + "forward_coder_headers": true, + "icon_url": "string", + "model_intent": true, + "oauth2_auth_url": "string", + "oauth2_client_id": "string", + "oauth2_client_secret": "string", + "oauth2_revocation_url": "string", + "oauth2_scopes": "string", + "oauth2_token_url": "string", + "slug": "string", + "tool_allow_list": [ + "string" + ], + "tool_deny_list": [ + "string" + ], + "transport": "streamable_http", + "url": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|-------------------------|-----------------|----------|--------------|------------------------------------------------------------------------------------------------------------------------| +| `allow_in_plan_mode` | boolean | false | | | +| `api_key_header` | string | false | | | +| `api_key_value` | string | false | | | +| `auth_type` | string | true | | | +| `availability` | string | true | | | +| `custom_headers` | object | false | | | +| » `[any property]` | string | false | | | +| `description` | string | false | | | +| `display_name` | string | true | | | +| `enabled` | boolean | false | | | +| `forward_coder_headers` | boolean | false | | Forward coder headers when true, forwards Coder identity headers on every outgoing MCP request. See MCPServerConfig. | +| `icon_url` | string | false | | | +| `model_intent` | boolean | false | | | +| `oauth2_auth_url` | string | false | | | +| `oauth2_client_id` | string | false | | | +| `oauth2_client_secret` | string | false | | | +| `oauth2_revocation_url` | string | false | | Oauth2 revocation URL is the provider's RFC 7009 revocation endpoint; auto-populated by OAuth2 discovery when omitted. | +| `oauth2_scopes` | string | false | | | +| `oauth2_token_url` | string | false | | | +| `slug` | string | true | | | +| `tool_allow_list` | array of string | false | | | +| `tool_deny_list` | array of string | false | | | +| `transport` | string | true | | | +| `url` | string | true | | | + +#### Enumerated Values + +| Property | Value(s) | +|----------------|------------------------------------------------------------| +| `auth_type` | `api_key`, `custom_headers`, `none`, `oauth2`, `user_oidc` | +| `availability` | `default_off`, `default_on`, `force_on` | +| `transport` | `sse`, `streamable_http` | + ## codersdk.CreateOrganizationRequest ```json @@ -8608,6 +8682,94 @@ Only certain features set these fields: - FeatureManagedAgentLimit - FeatureAgen |-----------------|--------|----------|--------------|-------------| | `session_token` | string | true | | | +## codersdk.MCPServerConfig + +```json +{ + "allow_in_plan_mode": true, + "api_key_header": "string", + "auth_connected": true, + "auth_type": "string", + "availability": "string", + "created_at": "2019-08-24T14:15:22Z", + "description": "string", + "display_name": "string", + "enabled": true, + "forward_coder_headers": true, + "has_api_key": true, + "has_custom_headers": true, + "has_oauth2_secret": true, + "icon_url": "string", + "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", + "model_intent": true, + "oauth2_auth_url": "string", + "oauth2_client_id": "string", + "oauth2_revocation_url": "string", + "oauth2_scopes": "string", + "oauth2_token_url": "string", + "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6", + "slug": "string", + "tool_allow_list": [ + "string" + ], + "tool_deny_list": [ + "string" + ], + "transport": "string", + "updated_at": "2019-08-24T14:15:22Z", + "url": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|-------------------------|-----------------|----------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `allow_in_plan_mode` | boolean | false | | | +| `api_key_header` | string | false | | Api key header key fields (only populated for admins). | +| `auth_connected` | boolean | false | | Per-user state (populated for non-admin requests). | +| `auth_type` | string | false | | "none", "oauth2", "api_key", "custom_headers", "user_oidc" | +| `availability` | string | false | | Availability policy set by admin. | +| `created_at` | string | false | | | +| `description` | string | false | | | +| `display_name` | string | false | | | +| `enabled` | boolean | false | | | +| `forward_coder_headers` | boolean | false | | Forward coder headers forwards the same Coder identity headers we send to LLM providers (X-Coder-Owner-Id, X-Coder-Chat-Id, and the optional X-Coder-Subchat-Id and X-Coder-Workspace-Id) to this MCP server on every request. Off by default to avoid leaking chat identity to third-party servers. | +| `has_api_key` | boolean | false | | | +| `has_custom_headers` | boolean | false | | | +| `has_oauth2_secret` | boolean | false | | | +| `icon_url` | string | false | | | +| `id` | string | false | | | +| `model_intent` | boolean | false | | | +| `oauth2_auth_url` | string | false | | | +| `oauth2_client_id` | string | false | | Oauth2 client ID fields (only populated for admins). | +| `oauth2_revocation_url` | string | false | | | +| `oauth2_scopes` | string | false | | | +| `oauth2_token_url` | string | false | | | +| `organization_id` | string | false | | | +| `slug` | string | false | | | +| `tool_allow_list` | array of string | false | | Tool governance. | +| `tool_deny_list` | array of string | false | | | +| `transport` | string | false | | "streamable_http" or "sse" | +| `updated_at` | string | false | | | +| `url` | string | false | | | + +## codersdk.MCPServerOAuth2DisconnectResponse + +```json +{ + "token_revocation_error": "string", + "token_revoked": true +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|--------------------------|---------|----------|--------------|-------------| +| `token_revocation_error` | string | false | | | +| `token_revoked` | boolean | false | | | + ## codersdk.MatchedProvisioners ```json @@ -13999,6 +14161,80 @@ Restarts will only happen on weekdays in this list on weeks which line up with W | `url` | string | false | | URL to download the latest release of Coder. | | `version` | string | false | | Version is the semantic version for the latest release of Coder. | +## codersdk.UpdateMCPServerConfigRequest + +```json +{ + "allow_in_plan_mode": true, + "api_key_header": "string", + "api_key_value": "string", + "auth_type": "none", + "availability": "force_on", + "custom_headers": { + "property1": "string", + "property2": "string" + }, + "description": "string", + "display_name": "string", + "enabled": true, + "forward_coder_headers": true, + "icon_url": "string", + "model_intent": true, + "oauth2_auth_url": "string", + "oauth2_client_id": "string", + "oauth2_client_secret": "string", + "oauth2_revocation_url": "string", + "oauth2_scopes": "string", + "oauth2_token_url": "string", + "slug": "string", + "tool_allow_list": [ + "string" + ], + "tool_deny_list": [ + "string" + ], + "transport": "streamable_http", + "url": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|-------------------------|-----------------|----------|--------------|-------------------------------------------------------------------------------------------------------------------------| +| `allow_in_plan_mode` | boolean | false | | | +| `api_key_header` | string | false | | | +| `api_key_value` | string | false | | | +| `auth_type` | string | false | | | +| `availability` | string | false | | | +| `custom_headers` | object | false | | | +| » `[any property]` | string | false | | | +| `description` | string | false | | | +| `display_name` | string | false | | | +| `enabled` | boolean | false | | | +| `forward_coder_headers` | boolean | false | | Forward coder headers when set, updates whether Coder identity headers are forwarded on every outgoing MCP request. | +| `icon_url` | string | false | | | +| `model_intent` | boolean | false | | | +| `oauth2_auth_url` | string | false | | | +| `oauth2_client_id` | string | false | | | +| `oauth2_client_secret` | string | false | | | +| `oauth2_revocation_url` | string | false | | Oauth2 revocation URL is validated in the handler because a validate tag would reject the pointer to "" that clears it. | +| `oauth2_scopes` | string | false | | | +| `oauth2_token_url` | string | false | | | +| `slug` | string | false | | | +| `tool_allow_list` | array of string | false | | | +| `tool_deny_list` | array of string | false | | | +| `transport` | string | false | | | +| `url` | string | false | | | + +#### Enumerated Values + +| Property | Value(s) | +|----------------|------------------------------------------------------------| +| `auth_type` | `api_key`, `custom_headers`, `none`, `oauth2`, `user_oidc` | +| `availability` | `default_off`, `default_on`, `force_on` | +| `transport` | `sse`, `streamable_http` | + ## codersdk.UpdateOrganizationRequest ```json