@ateam-ai/mcp 0.3.16 → 0.3.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/http.js +29 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ateam-ai/mcp",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "mcpName": "io.github.ariekogan/ateam-mcp",
5
5
  "description": "A-Team MCP Server — build, validate, and deploy multi-agent solutions from any AI environment",
6
6
  "type": "module",
package/src/http.js CHANGED
@@ -205,11 +205,16 @@ export function startHttpServer(port = 3100) {
205
205
  // Reuse existing session — seed credentials if Bearer token present
206
206
  transport = transports[sessionId];
207
207
  seedCredentials(req, sessionId);
208
- } else if (isInitializeRequest(req.body)) {
209
- // New session (or stale session after server restart) create fresh session.
210
- // Accept initialize requests even if they carry a stale mcp-session-id.
211
- if (sessionId) {
212
- console.log(`[HTTP] Stale session ${sessionId} creating new session (server was restarted)`);
208
+ } else if (isInitializeRequest(req.body) || (sessionId && !transports[sessionId])) {
209
+ // New session, OR stale session with any request type (server restart recovery).
210
+ // Many MCP clients (Claude mobile, Claude Code) cache the session ID and fail to
211
+ // re-initialize on 400. To survive container restarts transparently, we synthesize
212
+ // a fresh initialize under the hood whenever we see a stale session.
213
+ const isStaleRecovery = sessionId && !transports[sessionId] && !isInitializeRequest(req.body);
214
+ if (sessionId && isInitializeRequest(req.body)) {
215
+ console.log(`[HTTP] Stale session ${sessionId} — client re-initialized`);
216
+ } else if (isStaleRecovery) {
217
+ console.log(`[HTTP] Stale session ${sessionId} — auto-reinitializing transparently (${req.body?.method || "unknown"})`);
213
218
  }
214
219
 
215
220
  const newSessionId = randomUUID();
@@ -235,18 +240,27 @@ export function startHttpServer(port = 3100) {
235
240
 
236
241
  const server = createServer(newSessionId);
237
242
  await server.connect(transport);
243
+
244
+ if (isStaleRecovery) {
245
+ // Force the underlying web-standard transport into "initialized" state without
246
+ // requiring a real initialize handshake. This bypasses the SDK's built-in check
247
+ // (`Bad Request: Server not initialized`) so the non-initialize request dispatches.
248
+ const inner = transport._webStandardTransport;
249
+ if (inner) {
250
+ inner.sessionId = newSessionId;
251
+ inner._initialized = true;
252
+ }
253
+ transports[newSessionId] = transport;
254
+ // Rewrite the request's session-id header so SDK session validation passes.
255
+ req.headers["mcp-session-id"] = newSessionId;
256
+ // Tell the client about the new session id so future requests use it.
257
+ res.setHeader("mcp-session-id", newSessionId);
258
+ await transport.handleRequest(req, res, req.body);
259
+ return;
260
+ }
261
+
238
262
  await transport.handleRequest(req, res, req.body);
239
263
  return;
240
- } else if (sessionId && !transports[sessionId]) {
241
- // Stale session (non-initialize request) — tell client to re-initialize.
242
- // This happens after server restarts when the client still has the old session ID.
243
- console.log(`[HTTP] Stale session ${sessionId} — returning 400 to trigger re-init`);
244
- res.status(400).json({
245
- jsonrpc: "2.0",
246
- error: { code: -32600, message: "Session expired. Please re-initialize." },
247
- id: req.body?.id || null,
248
- });
249
- return;
250
264
  } else {
251
265
  res.status(400).json({
252
266
  jsonrpc: "2.0",