@productbrain/mcp 0.0.1-beta.9452 → 0.0.1-beta.9469
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/dist/{chunk-NCTCZQHK.js → chunk-BCQ7KBLE.js} +2 -2
- package/dist/{chunk-Q77SFDBZ.js → chunk-FVH3B7MF.js} +24 -10
- package/dist/{chunk-Q77SFDBZ.js.map → chunk-FVH3B7MF.js.map} +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/http.js +51 -54
- package/dist/http.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/{setup-6UYW6XKO.js → setup-YETABTTN.js} +2 -2
- package/package.json +1 -1
- /package/dist/{chunk-NCTCZQHK.js.map → chunk-BCQ7KBLE.js.map} +0 -0
- /package/dist/{setup-6UYW6XKO.js.map → setup-YETABTTN.js.map} +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
4
|
var subcommand = process.argv[2];
|
|
5
5
|
if (subcommand === "setup") {
|
|
6
|
-
const { runSetup } = await import("../setup-
|
|
6
|
+
const { runSetup } = await import("../setup-YETABTTN.js");
|
|
7
7
|
await runSetup();
|
|
8
8
|
} else {
|
|
9
9
|
await import("../index.js");
|
package/dist/http.js
CHANGED
|
@@ -2,19 +2,21 @@ import {
|
|
|
2
2
|
SERVER_VERSION,
|
|
3
3
|
createProductBrainServer,
|
|
4
4
|
initFeatureFlags
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BCQ7KBLE.js";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_CLOUD_URL,
|
|
8
8
|
apiKeysUrl,
|
|
9
9
|
bootstrapHttp,
|
|
10
|
+
checkKeyAgainstCandidates,
|
|
10
11
|
forgetStreamLifecycle,
|
|
11
12
|
getKeyState,
|
|
12
13
|
getPostHogClient,
|
|
13
14
|
hashKey,
|
|
14
15
|
initAnalytics,
|
|
16
|
+
parseFallbackUrls,
|
|
15
17
|
runWithAuth,
|
|
16
18
|
shutdownAnalytics
|
|
17
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-FVH3B7MF.js";
|
|
18
20
|
|
|
19
21
|
// src/http.ts
|
|
20
22
|
import { createHash, randomUUID } from "crypto";
|
|
@@ -206,6 +208,14 @@ function recordAuthFailure(failures, ip, now) {
|
|
|
206
208
|
}
|
|
207
209
|
}
|
|
208
210
|
}
|
|
211
|
+
function initializeKeyGate(verdict, failures, ip, now) {
|
|
212
|
+
if (verdict === "ok" || verdict === "rate_limited") return "admit";
|
|
213
|
+
if (verdict === "rejected") {
|
|
214
|
+
recordAuthFailure(failures, ip, now);
|
|
215
|
+
return "unauthorized";
|
|
216
|
+
}
|
|
217
|
+
return "unavailable";
|
|
218
|
+
}
|
|
209
219
|
|
|
210
220
|
// src/lib/oauthRedirectAllowlist.ts
|
|
211
221
|
var DEFAULT_OAUTH_REDIRECT_URIS = [
|
|
@@ -309,6 +319,10 @@ bootstrapHttp();
|
|
|
309
319
|
initAnalytics();
|
|
310
320
|
initFeatureFlags(getPostHogClient());
|
|
311
321
|
var PORT = parseInt(process.env.PORT ?? process.env.MCP_PORT ?? "3002", 10);
|
|
322
|
+
function keyCheckCandidates() {
|
|
323
|
+
const primaryUrl = (process.env.CONVEX_SITE_URL ?? DEFAULT_CLOUD_URL).replace(/\/$/, "");
|
|
324
|
+
return [primaryUrl, ...parseFallbackUrls(process.env.CONVEX_FALLBACK_URLS).map((u) => u.replace(/\/$/, ""))];
|
|
325
|
+
}
|
|
312
326
|
function baseUrl(req) {
|
|
313
327
|
const proto = req.headers["x-forwarded-proto"] ?? req.protocol ?? "http";
|
|
314
328
|
const host = req.headers.host ?? `localhost:${PORT}`;
|
|
@@ -1055,58 +1069,25 @@ app.post(
|
|
|
1055
1069
|
return;
|
|
1056
1070
|
}
|
|
1057
1071
|
let workspaceName = "Your Workspace";
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
if (checkData.ok) {
|
|
1078
|
-
if (checkData.workspaceName) workspaceName = checkData.workspaceName;
|
|
1079
|
-
foundUrl = checkData.deploymentUrl ?? url2;
|
|
1080
|
-
break;
|
|
1081
|
-
}
|
|
1082
|
-
if (checkData.error === "rate_limited") {
|
|
1083
|
-
rateLimitedRetryAfter = checkData.retryAfterSeconds;
|
|
1084
|
-
continue;
|
|
1085
|
-
}
|
|
1086
|
-
anyDefinitiveReject = true;
|
|
1087
|
-
}
|
|
1088
|
-
if (!foundUrl) {
|
|
1089
|
-
if (rateLimitedRetryAfter != null && !anyDefinitiveReject) {
|
|
1090
|
-
sendError(
|
|
1091
|
-
"Rate limited",
|
|
1092
|
-
`This API key is valid but temporarily rate limited. Try again in ${rateLimitedRetryAfter}s.`,
|
|
1093
|
-
429
|
|
1094
|
-
);
|
|
1095
|
-
return;
|
|
1096
|
-
}
|
|
1097
|
-
if (anyDefinitiveReject) {
|
|
1098
|
-
sendError(
|
|
1099
|
-
"Key not recognized",
|
|
1100
|
-
"This API key wasn't found in Product Brain. Check your API Keys in Cortex and try again.",
|
|
1101
|
-
401
|
|
1102
|
-
);
|
|
1103
|
-
return;
|
|
1104
|
-
}
|
|
1105
|
-
process.stderr.write("[authorize] key-check unavailable \u2014 proceeding without validation\n");
|
|
1106
|
-
} else {
|
|
1107
|
-
getKeyState(api_key).deploymentUrl = foundUrl;
|
|
1108
|
-
}
|
|
1109
|
-
} catch {
|
|
1072
|
+
const check = await checkKeyAgainstCandidates(keyCheckCandidates(), api_key, 5e3);
|
|
1073
|
+
if (check.verdict === "ok") {
|
|
1074
|
+
if (check.workspaceName) workspaceName = check.workspaceName;
|
|
1075
|
+
getKeyState(api_key).deploymentUrl = check.deploymentUrl;
|
|
1076
|
+
} else if (check.verdict === "rate_limited") {
|
|
1077
|
+
sendError(
|
|
1078
|
+
"Rate limited",
|
|
1079
|
+
`This API key is valid but temporarily rate limited. Try again in ${check.retryAfterSeconds ?? 60}s.`,
|
|
1080
|
+
429
|
|
1081
|
+
);
|
|
1082
|
+
return;
|
|
1083
|
+
} else if (check.verdict === "rejected") {
|
|
1084
|
+
sendError(
|
|
1085
|
+
"Key not recognized",
|
|
1086
|
+
"This API key wasn't found in Product Brain. Check your API Keys in Cortex and try again.",
|
|
1087
|
+
401
|
|
1088
|
+
);
|
|
1089
|
+
return;
|
|
1090
|
+
} else {
|
|
1110
1091
|
process.stderr.write("[authorize] key-check unavailable \u2014 proceeding without validation\n");
|
|
1111
1092
|
}
|
|
1112
1093
|
const code = randomUUID();
|
|
@@ -1286,6 +1267,22 @@ app.post("/mcp", mcpLimiter, async (req, res) => {
|
|
|
1286
1267
|
entry.lastAccess = Date.now();
|
|
1287
1268
|
}
|
|
1288
1269
|
} else if (!sessionId && isInitializeRequest(req.body)) {
|
|
1270
|
+
const check = await checkKeyAgainstCandidates(keyCheckCandidates(), apiKey, 5e3);
|
|
1271
|
+
const gate = initializeKeyGate(check.verdict, authFailures, reqIp, Date.now());
|
|
1272
|
+
if (gate === "unauthorized") {
|
|
1273
|
+
logRequest("POST", "auth_fail");
|
|
1274
|
+
send401(req, res);
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
if (gate === "unavailable") {
|
|
1278
|
+
res.status(503).json({
|
|
1279
|
+
jsonrpc: "2.0",
|
|
1280
|
+
error: { code: -32e3, message: "Product Brain could not verify this API key right now. Retry shortly." },
|
|
1281
|
+
id: req.body?.id ?? null
|
|
1282
|
+
});
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
if (check.verdict === "ok" || check.verdict === "rate_limited") getKeyState(apiKey).deploymentUrl = check.deploymentUrl;
|
|
1289
1286
|
const keyH = hashKey(apiKey);
|
|
1290
1287
|
const plan = planKeyAdmission(
|
|
1291
1288
|
sessions,
|