@lifeaitools/clauth 1.5.7 → 1.5.9

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.
@@ -2870,13 +2870,18 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
2870
2870
  }
2871
2871
 
2872
2872
  // ── OAuth Discovery (RFC 9728 + RFC 8414) ──────────────
2873
- if (reqPath === "/.well-known/oauth-protected-resource" ||
2874
- reqPath === "/.well-known/oauth-protected-resource/mcp" ||
2875
- reqPath === "/.well-known/oauth-protected-resource/sse") {
2873
+ if (reqPath.startsWith("/.well-known/oauth-protected-resource")) {
2876
2874
  const base = oauthBase();
2875
+ // Derive resource URL from the well-known path suffix
2876
+ // /.well-known/oauth-protected-resource → /mcp
2877
+ // /.well-known/oauth-protected-resource/mcp → /mcp
2878
+ // /.well-known/oauth-protected-resource/gws → /gws
2879
+ // /.well-known/oauth-protected-resource/clauth → /clauth
2880
+ const suffix = reqPath.replace("/.well-known/oauth-protected-resource", "").replace(/^\//, "") || "mcp";
2881
+ const resourcePath = suffix === "sse" ? "mcp" : suffix;
2877
2882
  res.writeHead(200, { "Content-Type": "application/json", ...CORS });
2878
2883
  return res.end(JSON.stringify({
2879
- resource: `${base}/mcp`,
2884
+ resource: `${base}/${resourcePath}`,
2880
2885
  authorization_servers: [base],
2881
2886
  scopes_supported: ["mcp:tools"],
2882
2887
  bearer_methods_supported: ["header"],
@@ -3000,9 +3005,23 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
3000
3005
  return res.end(JSON.stringify({ access_token: accessToken, token_type: "Bearer", expires_in: 86400 }));
3001
3006
  }
3002
3007
 
3008
+ // ── MCP path helpers ──
3009
+ const MCP_PATHS = ["/mcp", "/gws", "/clauth"];
3010
+ const isMcpPath = MCP_PATHS.includes(reqPath);
3011
+ function toolsForPath(p) {
3012
+ if (p === "/gws") return MCP_TOOLS.filter(t => t.name.startsWith("gws_"));
3013
+ if (p === "/clauth") return MCP_TOOLS.filter(t => t.name.startsWith("clauth_"));
3014
+ return MCP_TOOLS; // /mcp — all tools
3015
+ }
3016
+ function serverNameForPath(p) {
3017
+ if (p === "/gws") return "gws";
3018
+ if (p === "/clauth") return "clauth";
3019
+ return "clauth";
3020
+ }
3021
+
3003
3022
  // ── MCP OAuth-protected endpoint (for claude.ai web) ──
3004
- // POST /mcp — requires Bearer token; returns 401 to trigger OAuth flow
3005
- if (method === "POST" && reqPath === "/mcp") {
3023
+ // POST /mcp|/gws|/clauth — requires Bearer token; returns 401 to trigger OAuth flow
3024
+ if (method === "POST" && isMcpPath) {
3006
3025
  const authHeader = req.headers.authorization;
3007
3026
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
3008
3027
  const base = oauthBase();
@@ -3023,9 +3042,24 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
3023
3042
  // fall through to MCP handling below
3024
3043
  }
3025
3044
 
3045
+ // For namespaced paths, send path-specific 401 so claude.ai fetches the right resource metadata
3046
+ if (method === "POST" && (reqPath === "/gws" || reqPath === "/clauth")) {
3047
+ const authHeader = req.headers.authorization;
3048
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
3049
+ const base = oauthBase();
3050
+ const pathName = reqPath.slice(1); // "gws" or "clauth"
3051
+ res.writeHead(401, {
3052
+ "Content-Type": "application/json",
3053
+ "WWW-Authenticate": `Bearer resource_metadata="${base}/.well-known/oauth-protected-resource/${pathName}"`,
3054
+ ...CORS,
3055
+ });
3056
+ return res.end(JSON.stringify({ error: "unauthorized" }));
3057
+ }
3058
+ }
3059
+
3026
3060
  // ── MCP Streamable HTTP transport (2025-03-26 spec) ──
3027
- // POST /sse or POST /mcp — JSON-RPC over HTTP
3028
- if (method === "POST" && (reqPath === "/sse" || reqPath === "/mcp")) {
3061
+ // POST /sse, /mcp, /gws, /clauth — JSON-RPC over HTTP
3062
+ if (method === "POST" && (reqPath === "/sse" || isMcpPath)) {
3029
3063
  let body;
3030
3064
  try { body = await readBody(req); } catch {
3031
3065
  res.writeHead(400, { "Content-Type": "application/json", ...CORS });
@@ -3034,7 +3068,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
3034
3068
 
3035
3069
  const id = body.id;
3036
3070
  const rpcMethod = body.method;
3037
- const logMsg = `[${new Date().toISOString()}] Streamable HTTP: ${rpcMethod} id=${id}\n`;
3071
+ const logMsg = `[${new Date().toISOString()}] Streamable HTTP [${reqPath}]: ${rpcMethod} id=${id}\n`;
3038
3072
  try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
3039
3073
 
3040
3074
  // Notifications — no response needed
@@ -3046,7 +3080,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
3046
3080
  if (rpcMethod === "initialize") {
3047
3081
  const result = {
3048
3082
  protocolVersion: "2025-03-26",
3049
- serverInfo: { name: "clauth", version: VERSION },
3083
+ serverInfo: { name: serverNameForPath(reqPath), version: VERSION },
3050
3084
  capabilities: { tools: {} }
3051
3085
  };
3052
3086
  res.writeHead(200, { "Content-Type": "application/json", ...CORS });
@@ -3055,7 +3089,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
3055
3089
 
3056
3090
  if (rpcMethod === "tools/list") {
3057
3091
  res.writeHead(200, { "Content-Type": "application/json", ...CORS });
3058
- return res.end(JSON.stringify({ jsonrpc: "2.0", id, result: { tools: MCP_TOOLS } }));
3092
+ return res.end(JSON.stringify({ jsonrpc: "2.0", id, result: { tools: toolsForPath(reqPath) } }));
3059
3093
  }
3060
3094
 
3061
3095
  if (rpcMethod === "tools/call") {
@@ -4321,7 +4355,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
4321
4355
  // Don't count browser noise, MCP discovery probes, or OAuth probes as auth failures
4322
4356
  const isBenign = reqPath.startsWith("/.well-known/") || [
4323
4357
  "/favicon.ico", "/robots.txt", "/apple-touch-icon.png", "/apple-touch-icon-precomposed.png",
4324
- "/sse", "/mcp", "/message", "/register", "/authorize", "/token", "/shutdown", "/restart",
4358
+ "/sse", "/mcp", "/gws", "/clauth", "/message", "/register", "/authorize", "/token", "/shutdown", "/restart",
4325
4359
  ].includes(reqPath);
4326
4360
  if (isBenign) {
4327
4361
  res.writeHead(404, { "Content-Type": "application/json", ...CORS });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/clauth",
3
- "version": "1.5.7",
3
+ "version": "1.5.9",
4
4
  "description": "Hardware-bound credential vault for the LIFEAI infrastructure stack",
5
5
  "type": "module",
6
6
  "bin": {