{"record":{"id":"758244e7c484a7d4","repo":"upstash/context7","slug":"32603","errorCode":"-32603","errorMessage":"Internal server error","messagePattern":"Internal server error","errorType":"http","errorClass":null,"httpStatus":500,"severity":"critical","filePath":"packages/mcp/src/index.ts","lineNumber":463,"sourceCode":"            }\n          }\n        }\n\n        const context: ClientContext = {\n          clientIp: req.ip,\n          apiKey,\n          clientInfo: extractClientInfoFromUserAgent(req.headers[\"user-agent\"]),\n          plugin,\n          transport: \"http\",\n        };\n\n        await requestContext.run(context, async () => {\n          await nodeHandler(req, res, req.body);\n        });\n      } catch (error) {\n        console.error(\"Error handling MCP request:\", error);\n        if (!res.headersSent) {\n          res.status(500).json({\n            jsonrpc: \"2.0\",\n            error: { code: -32603, message: \"Internal server error\" },\n            id: null,\n          });\n        }\n      }\n    };\n\n    // JSON bodies and JSON-RPC error envelopes are the MCP contract only, so the\n    // parser and its error boundary live on the MCP router: every other route\n    // stays out of the parser and keeps its own response shape.\n    const mcpRouter = express.Router();\n    mcpRouter.use(express.json());\n    mcpRouter.use(mcpBodyErrorHandler);\n    mcpRouter.all(\"/\", (req, res) => handleMcpRequest(req, res));\n    // OAuth-protected endpoint - requires authentication\n    mcpRouter.all(\"/oauth\", (req, res) => handleMcpRequest(req, res));\n    app.use(\"/mcp\", mcpRouter);","sourceCodeStart":445,"sourceCodeEnd":481,"githubUrl":"https://github.com/upstash/context7/blob/80e681a507c5287bc12e483367c40754e29461b9/packages/mcp/src/index.ts#L445-L481","documentation":"Catch-all around the MCP request handler in `handleMcpRequest`: any unexpected throw from `requestContext.run(nodeHandler, ...)` is logged server-side (\"Error handling MCP request:\") and answered with HTTP 500 and JSON-RPC code -32603 \"Internal server error\" — but only if headers were not already sent. The details are deliberately hidden from the client; the server log holds the real stack.","triggerScenarios":"A bug in a tool implementation throwing a non-Error; a request-conversion failure inside the adapter (the code installs `onerror` hooks precisely so these reach this handler); OOM or corrupted state in a long-lived deployment.","commonSituations":"Server-side regressions after an SDK upgrade; resource exhaustion under load; malformed payloads that bypass earlier parsing.","solutions":["Inspect server logs for the \"Error handling MCP request:\" stack — the client-side message is intentionally vague","Retry the request; transient handler faults often clear","Update/restart the MCP server deployment","Report with the logged stack if it reproduces on the latest version"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"function isJsonRpcInternalError(body: unknown): boolean {\n  return typeof body === 'object' && body !== null && (body as any)?.error?.code === -32603;\n}","tryCatchPattern":"try {\n  const result = await mcpClient.callTool('get-library-docs', args);\n} catch (error) {\n  if (/Internal server error|-32603/.test(String(error))) {\n    await sleep(1000);\n    return mcpClient.callTool('get-library-docs', args); // one idempotent retry\n  }\n  throw error;\n}","preventionTips":["Make JSON-RPC calls idempotent so a single retry is safe","Server operators: keep the onerror hooks wired so adapter throws reach the express catch-all and get logged","Watch server logs for 'Error handling MCP request:' — client messages intentionally carry no detail"],"tags":["mcp","server","json-rpc","unhandled-exception"],"backgroundTag":"json-rpc-internal-error","analyzedSha":"80e681a507c5287bc12e483367c40754e29461b9","analyzedAt":"2026-08-18T18:00:18.510Z","contentChangedAt":"2026-08-18T18:00:18.510Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}