为未鉴权MCP返回接入引导

保持401与Bearer挑战并提供机器可读的Key配置步骤

统一缺失格式错误和无效Key响应以避免凭据枚举

保留请求元信息并同步OpenAPI集成清单与架构文档

补充鉴权脱敏契约测试并完成本地dev栈验证
This commit is contained in:
2026-08-03 12:03:50 +08:00
parent 6a02c7fb38
commit d1a657b5d2
7 changed files with 456 additions and 26 deletions
@@ -178,7 +178,23 @@
"description": "MCP notification 已接受"
},
"401": {
"$ref": "#/components/responses/Unauthorized"
"description": "缺少、格式错误或无法验证 Bearer API Key。返回 WWW-Authenticate 以及机器可读的 MCP 鉴权引导,说明 Header 格式、开发者 API Key 创建位置、凭据安全要求和公开 discovery/Skill/OpenAPI 地址;不暴露 tools、resources、owner 或 Key 是否存在。",
"headers": {
"WWW-Authenticate": {
"description": "Bearer 鉴权挑战。",
"schema": {
"type": "string",
"const": "Bearer realm=\"genarrative-external-editor\""
}
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/McpAuthenticationGuideResponse"
}
}
}
}
}
}
@@ -2736,6 +2752,198 @@
"JsonValue": {
"description": "任意 JSON 值。"
},
"McpAuthenticationGuideResponse": {
"type": "object",
"required": [
"error",
"meta"
],
"additionalProperties": false,
"properties": {
"error": {
"type": "object",
"required": [
"code",
"message",
"details"
],
"additionalProperties": false,
"properties": {
"code": {
"const": "UNAUTHORIZED"
},
"message": {
"const": "连接陶泥儿托管 MCP 需要开发者 API Key"
},
"details": {
"type": "object",
"required": [
"guide"
],
"additionalProperties": false,
"properties": {
"guide": {
"type": "object",
"required": [
"reason",
"action",
"authentication",
"keyManagement",
"retry",
"steps",
"credentialSafety",
"publicDiscovery"
],
"additionalProperties": false,
"properties": {
"reason": {
"const": "MCP_AUTHENTICATION_REQUIRED"
},
"action": {
"const": "CONFIGURE_BEARER_API_KEY"
},
"authentication": {
"type": "object",
"required": [
"scheme",
"header",
"valueFormat"
],
"additionalProperties": false,
"properties": {
"scheme": {
"const": "Bearer"
},
"header": {
"const": "Authorization"
},
"valueFormat": {
"const": "Bearer <tnr_sk_...>"
}
}
},
"keyManagement": {
"type": "object",
"required": [
"navigationLabel",
"rawKeyShownOnce"
],
"additionalProperties": false,
"properties": {
"navigationLabel": {
"const": "开发者 API Key"
},
"rawKeyShownOnce": {
"const": true
}
}
},
"retry": {
"type": "object",
"required": [
"method",
"path",
"rpcMethod"
],
"additionalProperties": false,
"properties": {
"method": {
"const": "POST"
},
"path": {
"const": "/api/external/v1/mcp"
},
"rpcMethod": {
"const": "initialize"
}
}
},
"steps": {
"type": "array",
"items": {
"type": "string"
}
},
"credentialSafety": {
"type": "object",
"required": [
"rawKeyShownOnce",
"neverPasteIntoChat",
"neverStoreInRepository"
],
"additionalProperties": false,
"properties": {
"rawKeyShownOnce": {
"const": true
},
"neverPasteIntoChat": {
"const": true
},
"neverStoreInRepository": {
"const": true
}
}
},
"publicDiscovery": {
"type": "object",
"required": [
"manifest",
"skill",
"openapi"
],
"additionalProperties": false,
"properties": {
"manifest": {
"const": "/api/external/v1/agent-integration.json"
},
"skill": {
"const": "/api/external/v1/skill/SKILL.md"
},
"openapi": {
"const": "/api/external/v1/openapi.json"
}
}
}
}
}
}
}
}
},
"meta": {
"type": "object",
"required": [
"apiVersion",
"routeVersion",
"latencyMs",
"timestamp"
],
"additionalProperties": false,
"properties": {
"apiVersion": {
"type": "string"
},
"requestId": {
"type": "string"
},
"routeVersion": {
"type": "string"
},
"operation": {
"type": "string"
},
"latencyMs": {
"type": "integer",
"minimum": 0
},
"timestamp": {
"type": "string",
"format": "date-time"
}
}
}
}
},
"ErrorResponse": {
"type": "object",
"properties": {