@lifeaitools/clauth 1.5.32 → 1.5.34

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.
@@ -2978,8 +2978,9 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
2978
2978
  // fall through to MCP handling
2979
2979
  }
2980
2980
 
2981
- // ── MCP Streamable HTTP transport (2025-03-26 spec) ──
2981
+ // ── MCP Streamable HTTP transport ──
2982
2982
  // POST /sse, /mcp, /gws, /clauth — JSON-RPC over HTTP
2983
+ // claude.ai requires text/event-stream SSE format (like regen-media/Express).
2983
2984
  if (method === "POST" && (reqPath === "/sse" || isMcpPath)) {
2984
2985
  let body;
2985
2986
  try { body = await readBody(req); } catch {
@@ -2992,26 +2993,45 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
2992
2993
  const logMsg = `[${new Date().toISOString()}] Streamable HTTP [${reqPath}]: ${rpcMethod} id=${id}\n`;
2993
2994
  try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
2994
2995
 
2996
+ // Check if client accepts SSE — claude.ai sends Accept: application/json, text/event-stream
2997
+ const acceptsSSE = (req.headers.accept || "").includes("text/event-stream");
2998
+
2999
+ // Helper: respond in SSE or JSON format based on client preference
3000
+ // SSE response matches regen-media/Express exactly: no CORS, Content-Length, x-powered-by
3001
+ function mcpRespond(res, jsonRpcResponse) {
3002
+ if (acceptsSSE) {
3003
+ const ssePayload = `event: message\ndata: ${JSON.stringify(jsonRpcResponse)}\n\n`;
3004
+ const buf = Buffer.from(ssePayload, "utf8");
3005
+ res.writeHead(200, {
3006
+ "Content-Type": "text/event-stream",
3007
+ "Content-Length": buf.length,
3008
+ "Cache-Control": "no-cache",
3009
+ "vary": "Accept-Encoding",
3010
+ "x-powered-by": "Express",
3011
+ });
3012
+ return res.end(buf);
3013
+ }
3014
+ res.writeHead(200, { "Content-Type": "application/json", ...CORS });
3015
+ return res.end(JSON.stringify(jsonRpcResponse));
3016
+ }
3017
+
2995
3018
  // Notifications — no response needed
2996
3019
  if (rpcMethod === "notifications/initialized" || rpcMethod === "initialized") {
2997
- res.writeHead(204, CORS);
3020
+ res.writeHead(202, CORS);
2998
3021
  return res.end();
2999
3022
  }
3000
3023
 
3001
3024
  if (rpcMethod === "initialize") {
3002
- // Always return 2025-03-26 — returning 2025-11-25 causes claude.ai to require OAuth
3003
3025
  const result = {
3004
3026
  protocolVersion: "2025-03-26",
3005
3027
  serverInfo: { name: serverNameForPath(reqPath), version: VERSION },
3006
- capabilities: { tools: {} }
3028
+ capabilities: { tools: { listChanged: true } }
3007
3029
  };
3008
- res.writeHead(200, { "Content-Type": "application/json", ...CORS });
3009
- return res.end(JSON.stringify({ jsonrpc: "2.0", id, result }));
3030
+ return mcpRespond(res, { jsonrpc: "2.0", id, result });
3010
3031
  }
3011
3032
 
3012
3033
  if (rpcMethod === "tools/list") {
3013
- res.writeHead(200, { "Content-Type": "application/json", ...CORS });
3014
- return res.end(JSON.stringify({ jsonrpc: "2.0", id, result: { tools: toolsForPath(reqPath) } }));
3034
+ return mcpRespond(res, { jsonrpc: "2.0", id, result: { tools: toolsForPath(reqPath) } });
3015
3035
  }
3016
3036
 
3017
3037
  if (rpcMethod === "tools/call") {
@@ -3021,17 +3041,14 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
3021
3041
  try {
3022
3042
  const result = await handleMcpTool(vault, name, args || {});
3023
3043
  password = vault.password;
3024
- res.writeHead(200, { "Content-Type": "application/json", ...CORS });
3025
- return res.end(JSON.stringify({ jsonrpc: "2.0", id, result }));
3044
+ return mcpRespond(res, { jsonrpc: "2.0", id, result });
3026
3045
  } catch (err) {
3027
- res.writeHead(200, { "Content-Type": "application/json", ...CORS });
3028
- return res.end(JSON.stringify({ jsonrpc: "2.0", id, result: mcpError(`Internal error: ${err.message}`) }));
3046
+ return mcpRespond(res, { jsonrpc: "2.0", id, result: mcpError(`Internal error: ${err.message}`) });
3029
3047
  }
3030
3048
  }
3031
3049
 
3032
3050
  // Unknown method
3033
- res.writeHead(200, { "Content-Type": "application/json", ...CORS });
3034
- return res.end(JSON.stringify({ jsonrpc: "2.0", id, error: { code: -32601, message: `Unknown method: ${rpcMethod}` } }));
3051
+ return mcpRespond(res, { jsonrpc: "2.0", id, error: { code: -32601, message: `Unknown method: ${rpcMethod}` } });
3035
3052
  }
3036
3053
 
3037
3054
  // ── MCP SSE transport — /sse and namespaced paths ────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/clauth",
3
- "version": "1.5.32",
3
+ "version": "1.5.34",
4
4
  "description": "Hardware-bound credential vault for the LIFEAI infrastructure stack",
5
5
  "type": "module",
6
6
  "bin": {