* 处理所有进入 MCP 服务的 HTTP 请求。
(req: IncomingMessage, res: ServerResponse)
| 206 | * 处理所有进入 MCP 服务的 HTTP 请求。 |
| 207 | */ |
| 208 | private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> { |
| 209 | if (req.method === 'OPTIONS') { |
| 210 | this.sendNoContent(res) |
| 211 | return |
| 212 | } |
| 213 | |
| 214 | const requestUrl = new URL(req.url || '/', `http://${req.headers.host || '127.0.0.1'}`) |
| 215 | const pathname = requestUrl.pathname |
| 216 | |
| 217 | if (req.method === 'GET' && pathname === '/mcp') { |
| 218 | this.sendRawJson(res, 200, { |
| 219 | name: 'ZTools MCP', |
| 220 | protocolVersion: MCP_PROTOCOL_VERSION, |
| 221 | message: 'Use POST /mcp with JSON-RPC 2.0' |
| 222 | }) |
| 223 | return |
| 224 | } |
| 225 | |
| 226 | if (req.method !== 'POST' || pathname !== '/mcp') { |
| 227 | this.sendMcpError(res, null, -32601, 'Method not found') |
| 228 | return |
| 229 | } |
| 230 | |
| 231 | // 同时支持标准 Authorization: Bearer 和 ?key= 查询参数鉴权。 |
| 232 | const authHeader = req.headers['authorization'] |
| 233 | const bearerToken = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : null |
| 234 | const queryToken = requestUrl.searchParams.get('key') |
| 235 | const token = bearerToken || queryToken |
| 236 | if (!token || token !== this.config.apiKey) { |
| 237 | this.sendMcpError(res, null, -32001, 'API 密钥无效') |
| 238 | return |
| 239 | } |
| 240 | |
| 241 | try { |
| 242 | const body = await this.readBody(req) |
| 243 | await this.handleMcpRequest(res, body) |
| 244 | } catch (error) { |
| 245 | console.error('[McpServer] 请求处理失败:', error) |
| 246 | this.sendMcpError( |
| 247 | res, |
| 248 | null, |
| 249 | -32603, |
| 250 | error instanceof Error ? error.message : 'Internal error' |
| 251 | ) |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | /** |
| 256 | * 读取并解析请求体,仅接受 JSON 对象。 |
no test coverage detected