{"record":{"id":"9c221b5dbdd76148","repo":"yikart/AiToEarn","slug":"32000","errorCode":"-32000","errorMessage":"Bad Request: Mcp-Session-Id header is required","messagePattern":"Bad Request: Mcp-Session-Id header is required","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"project/aitoearn-backend/libs/nest-mcp/src/services/mcp-streamable-http.service.ts","lineNumber":313,"sourceCode":"          id: null,\n        })\n        return\n      }\n\n      // Use existing transport\n      const transport = this.transports[sessionId]\n\n      this.logger.debug(\n        `[${sessionId}] Handling request with existing session`,\n      )\n\n      // Handle the request with existing transport and handlers\n      await transport.handleRequest(req.raw, res.raw, body)\n      return\n    }\n\n    // Case 3: No session ID and not initialization\n    res.status(400).json({\n      jsonrpc: '2.0',\n      error: {\n        code: -32000,\n        message: 'Bad Request: Mcp-Session-Id header is required',\n      },\n      id: null,\n    })\n  }\n\n  /**\n   * Handle GET requests for SSE streams\n   */\n  async handleGetRequest(req: any, res: any): Promise<void> {\n    const adapter = HttpAdapterFactory.getAdapter(req, res)\n    const adaptedReq = adapter.adaptRequest(req)\n    const adaptedRes = adapter.adaptResponse(res)\n\n    if (this.isStatelessMode) {","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/libs/nest-mcp/src/services/mcp-streamable-http.service.ts#L295-L331","documentation":"In stateful mode, a POST arrived with no Mcp-Session-Id header and the body was not an initialize request. Since only initialize may create a session, the server cannot route the call and returns -32000 with HTTP 400. Every non-initialize stateful request must reference an existing session.","triggerScenarios":"POSTing tools/list, tools/call, resources/*, or notifications without initializing first (no session id header), or losing the header between requests because the HTTP client drops custom headers on subsequent calls.","commonSituations":"Calling a tool directly with curl without doing the initialize dance first, fetch/axios wrapper that rebuilds headers per request and forgets mcp-session-id, or misconfiguring the client to talk to a stateful endpoint when it assumes stateless behavior.","solutions":["Send an initialize request first, store the Mcp-Session-Id response header, and attach it to all subsequent requests.","If your usage is one-shot calls without sessions, use the library's stateless mode (isStatelessMode) instead.","Audit your HTTP client so the mcp-session-id header persists across every request in the conversation.","Check that middleware or the proxy isn't stripping the Mcp-Session-Id header."],"exampleFix":"// before\nawait fetch(url, { method: 'POST', body: JSON.stringify(callToolReq) })\n// after\nconst initRes = await fetch(url, { method: 'POST', body: JSON.stringify(initReq) })\nconst sid = initRes.headers.get('mcp-session-id')\nawait fetch(url, { method: 'POST', headers: { 'mcp-session-id': sid }, body: JSON.stringify(callToolReq) })","handlingStrategy":"validation","validationCode":"if (!sessionId) {\n  throw new Error('Call initialize first and pass the returned Mcp-Session-Id header')\n}","typeGuard":"function isStatefulReady(ctx: { sessionId?: string; initialized: boolean }): boolean {\n  return ctx.initialized && typeof ctx.sessionId === 'string' && ctx.sessionId.length > 0\n}","tryCatchPattern":"try {\n  return await post(url, body, { 'mcp-session-id': sessionId })\n} catch (e) {\n  if (e.status === 400 && e.body?.error?.code === -32000) {\n    sessionId = await initialize(url)\n    return post(url, body, { 'mcp-session-id': sessionId })\n  }\n  throw e\n}","preventionTips":["Store the session id in a client context object and inject the header on every request.","Use an official MCP client transport instead of hand-rolled fetch calls.","Check middleware/proxies for stripping of custom mcp-* headers.","If sessions are unwanted, switch the endpoint to stateless mode rather than skipping initialize."],"tags":["session","http-400","stateful","missing-header"],"backgroundTag":"missing-mcp-session-id-header","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}