{"record":{"id":"b2dd88761eabffdb","repo":"screenpipe/screenpipe","slug":"unauthorized","errorCode":null,"errorMessage":"unauthorized","messagePattern":"unauthorized","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"packages/screenpipe-mcp/src/http-server.ts","lineNumber":349,"sourceCode":"    );\n\n    if (req.method === \"OPTIONS\") {\n      res.writeHead(204);\n      res.end();\n      return;\n    }\n\n    // Health check is unauthenticated — monitors / load balancers need it.\n    // It only reveals session count, no user data.\n    if (req.url === \"/health\") {\n      res.writeHead(200, { \"Content-Type\": \"application/json\" });\n      res.end(JSON.stringify({ status: \"ok\", sessions: sessions.size }));\n      return;\n    }\n\n    // Auth gate for everything else.\n    if (!isAuthorized(req, config.apiKey)) {\n      res.writeHead(401, { \"Content-Type\": \"application/json\" });\n      res.end(JSON.stringify({ error: \"unauthorized\" }));\n      return;\n    }\n\n    // MCP endpoint\n    if (req.url === \"/mcp\" || req.url?.startsWith(\"/mcp?\")) {\n      const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n      let session = sessionId ? sessions.get(sessionId) : undefined;\n\n      if (!session) {\n        const server = createMcpServer(fetchAPI);\n        const transport = new StreamableHTTPServerTransport({\n          sessionIdGenerator: () => crypto.randomUUID(),\n          onsessioninitialized: (newSessionId) => {\n            sessions.set(newSessionId, { server, transport });\n          },\n          onsessionclosed: (closedSessionId) => {\n            sessions.delete(closedSessionId);","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/screenpipe/screenpipe/blob/4ebf712990fee17eeaf904dacf749b6e96ac9bf3/packages/screenpipe-mcp/src/http-server.ts#L331-L367","documentation":"The screenpipe MCP HTTP server gates every non-health endpoint behind an API-key check (`isAuthorized(req, config.apiKey)`). Requests failing that check get HTTP 401 with `{\"error\":\"unauthorized\"}`. Only the health endpoint is exempt.","triggerScenarios":"Any request to the MCP HTTP server (e.g. POST /mcp) without the expected API key: missing Authorization header, wrong key, or the client configured without the key that the server was started with (config.apiKey).","commonSituations":"MCP clients configured before a key was added to the server config; key rotated on the server but not the client; multiple MCP server instances with different keys; proxies stripping the Authorization header.","solutions":["Configure the MCP client with the same API key the server was started with (header `Authorization: Bearer <key>`).","Check how the server was launched and what config.apiKey is; restart it with a known key if lost.","Verify no intermediary (reverse proxy, shell script) strips or rewrites the Authorization header.","Use the unauthenticated health endpoint to confirm connectivity separately from auth."],"exampleFix":"// before: client with no auth\nfetch(\"http://localhost:3030/mcp\", { method: \"POST\", body });\n\n// after\nfetch(\"http://localhost:3030/mcp\", {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.SCREENPIPE_API_KEY}` },\n  body,\n});","handlingStrategy":"validation","validationCode":"if (!config.apiKey) throw new Error(\"MCP HTTP server requires an apiKey in config\");\n// client side:\nif (!clientApiKey) throw new Error(\"set Authorization: Bearer <key> for /mcp calls\");","typeGuard":null,"tryCatchPattern":"const res = await fetch(base + \"/mcp\", { headers: { Authorization: `Bearer ${key}` }, ... });\nif (res.status === 401) {\n  const { error } = await res.json();\n  throw new Error(`MCP server rejected key (${error}); realign client and server apiKey`);\n}","preventionTips":["Pass the same apiKey value to the server launch and every client config.","Rotate keys on both sides in one deploy step.","Smoke-test with the health endpoint, then an authed /mcp ping, before real usage."],"tags":["auth","mcp","http","api-key"],"backgroundTag":"unauthorized-api-access","analyzedSha":"4ebf712990fee17eeaf904dacf749b6e96ac9bf3","analyzedAt":"2026-09-01T23:33:43.065Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}