header('origin', '')); if ($origin !== '' && !in_array(rtrim($origin, '/'), array_map(static fn ($o) => rtrim($o, '/'), McpConfig::allowedOrigins()), true)) { return [403, 'Origin not allowed', 'origin_not_allowed']; } $ips = McpConfig::allowedIps(); if ($ips && !in_array($request->ip(), $ips, true)) { return [403, '来源 IP 不在 AI 助手白名单内', 'ip_not_allowed']; } return null; } /** MCP 端点的 401:JSON-RPC 错误体 + WWW-Authenticate */ public static function unauthorized(McpException $e): Response { $body = ['jsonrpc' => '2.0', 'id' => null, 'error' => ['code' => -32001, 'message' => $e->getMessage(), 'data' => ['reason' => $e->reason]]]; return json($body, 401)->header(['WWW-Authenticate' => 'Bearer error="invalid_token", error_description="' . $e->reason . '"']); } /** REST 接口的统一信封(与后台 JsonService 一致) */ public static function envelope(int $code, string $msg, $data = [], int $httpStatus = 200, int $show = 0): Response { $response = json(['code' => $code, 'show' => $show, 'msg' => $msg, 'data' => $data ?: new \stdClass()], $httpStatus); if ($httpStatus === 401) { $response->header(['WWW-Authenticate' => 'Bearer error="invalid_token"']); } return $response; } }