@lifeaitools/clauth 1.5.12 → 1.5.14
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.
- package/cli/commands/serve.js +16 -30
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -3029,41 +3029,23 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3029
3029
|
return "clauth";
|
|
3030
3030
|
}
|
|
3031
3031
|
|
|
3032
|
-
// ── MCP
|
|
3033
|
-
//
|
|
3032
|
+
// ── MCP endpoint auth — log all incoming POSTs, accept with or without token ──
|
|
3033
|
+
// /gws and /clauth are open (no OAuth gate) — tunnel URL is the shared secret.
|
|
3034
|
+
// OAuth flow is still supported (tokens accepted when present) but not required.
|
|
3034
3035
|
if (method === "POST" && isMcpPath) {
|
|
3035
3036
|
const authHeader = req.headers.authorization;
|
|
3036
|
-
// Detailed auth logging — helps diagnose claude.ai post-token failures
|
|
3037
3037
|
const authLogMsg = [
|
|
3038
3038
|
`[${new Date().toISOString()}] MCP POST ${reqPath}`,
|
|
3039
3039
|
` Authorization: ${authHeader ? (authHeader.startsWith("Bearer ") ? `Bearer ${authHeader.slice(7, 15)}… (known=${oauthTokens.has(authHeader.slice(7))})` : authHeader.slice(0, 30) + "…") : "(none)"}`,
|
|
3040
3040
|
` mcp-protocol-version: ${req.headers["mcp-protocol-version"] || "(not set)"}`,
|
|
3041
3041
|
` accept: ${req.headers["accept"] || "(not set)"}`,
|
|
3042
|
-
` x-forwarded-for: ${req.headers["x-forwarded-for"] || "(not set)"}`,
|
|
3043
3042
|
].join("\n") + "\n";
|
|
3044
3043
|
try { fs.appendFileSync(LOG_FILE, authLogMsg); } catch {}
|
|
3045
|
-
|
|
3046
|
-
if (
|
|
3047
|
-
|
|
3048
|
-
// Path-specific resource metadata URL so claude.ai gets the right resource URI
|
|
3049
|
-
const pathName = reqPath === "/mcp" ? "mcp" : reqPath.slice(1);
|
|
3050
|
-
res.writeHead(401, {
|
|
3051
|
-
"Content-Type": "application/json",
|
|
3052
|
-
"WWW-Authenticate": `Bearer resource_metadata="${base}/.well-known/oauth-protected-resource/${pathName}"`,
|
|
3053
|
-
...CORS,
|
|
3054
|
-
});
|
|
3055
|
-
return res.end(JSON.stringify({ error: "unauthorized" }));
|
|
3044
|
+
// Mark as remote if a valid token is present (for vault access scoping)
|
|
3045
|
+
if (authHeader?.startsWith("Bearer ") && oauthTokens.has(authHeader.slice(7))) {
|
|
3046
|
+
req._clauthRemote = true;
|
|
3056
3047
|
}
|
|
3057
|
-
|
|
3058
|
-
if (!oauthTokens.has(token)) {
|
|
3059
|
-
const badTokenLog = `[${new Date().toISOString()}] OAuth: REJECTED token ${token.slice(0,8)}… (pool size=${oauthTokens.size})\n`;
|
|
3060
|
-
try { fs.appendFileSync(LOG_FILE, badTokenLog); } catch {}
|
|
3061
|
-
res.writeHead(401, { "Content-Type": "application/json", ...CORS });
|
|
3062
|
-
return res.end(JSON.stringify({ error: "invalid_token" }));
|
|
3063
|
-
}
|
|
3064
|
-
// Token valid — mark as remote caller (claude.ai via tunnel)
|
|
3065
|
-
req._clauthRemote = true;
|
|
3066
|
-
// fall through to MCP handling below
|
|
3048
|
+
// fall through to MCP handling — no 401 gate on these paths
|
|
3067
3049
|
}
|
|
3068
3050
|
|
|
3069
3051
|
// ── MCP Streamable HTTP transport (2025-03-26 spec) ──
|
|
@@ -3087,12 +3069,16 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3087
3069
|
}
|
|
3088
3070
|
|
|
3089
3071
|
if (rpcMethod === "initialize") {
|
|
3072
|
+
// Echo back the client's requested protocol version (negotiate down if needed)
|
|
3073
|
+
const clientVersion = req.headers["mcp-protocol-version"] || body.params?.protocolVersion || "2025-03-26";
|
|
3074
|
+
const SUPPORTED = ["2025-11-25", "2025-03-26"];
|
|
3075
|
+
const protocolVersion = SUPPORTED.includes(clientVersion) ? clientVersion : "2025-03-26";
|
|
3090
3076
|
const result = {
|
|
3091
|
-
protocolVersion
|
|
3077
|
+
protocolVersion,
|
|
3092
3078
|
serverInfo: { name: serverNameForPath(reqPath), version: VERSION },
|
|
3093
3079
|
capabilities: { tools: {} }
|
|
3094
3080
|
};
|
|
3095
|
-
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
3081
|
+
res.writeHead(200, { "Content-Type": "application/json", "mcp-protocol-version": protocolVersion, ...CORS });
|
|
3096
3082
|
return res.end(JSON.stringify({ jsonrpc: "2.0", id, result }));
|
|
3097
3083
|
}
|
|
3098
3084
|
|
|
@@ -3121,9 +3107,9 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3121
3107
|
return res.end(JSON.stringify({ jsonrpc: "2.0", id, error: { code: -32601, message: `Unknown method: ${rpcMethod}` } }));
|
|
3122
3108
|
}
|
|
3123
3109
|
|
|
3124
|
-
// ── MCP SSE transport
|
|
3125
|
-
// GET /sse — open SSE stream, receive endpoint event
|
|
3126
|
-
if (method === "GET" && reqPath === "/sse") {
|
|
3110
|
+
// ── MCP SSE transport — /sse and namespaced paths ────
|
|
3111
|
+
// GET /sse|/gws|/clauth — open SSE stream, receive endpoint event
|
|
3112
|
+
if (method === "GET" && (reqPath === "/sse" || isMcpPath)) {
|
|
3127
3113
|
const sessionId = `ses_${++sseCounter}_${Date.now()}`;
|
|
3128
3114
|
|
|
3129
3115
|
res.writeHead(200, {
|