hive-intelligence 1.1.3 → 1.1.4
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/LICENSE +23 -0
- package/README.md +175 -54
- package/agent-skills/.claude-plugin/plugin.json +6 -0
- package/agent-skills/.mcp.json +11 -0
- package/agent-skills/AGENTS.md +37 -0
- package/agent-skills/README.md +13 -14
- package/agent-skills/SKILL.md +16 -4
- package/agent-skills/evals/trigger-queries.json +270 -0
- package/agent-skills/package.json +3 -3
- package/agent-skills/packs/hive-build/SKILL.md +11 -10
- package/agent-skills/packs/hive-build/evals/evals.json +2 -2
- package/agent-skills/packs/hive-mcp/SKILL.md +44 -121
- package/agent-skills/packs/hive-mcp/evals/evals.json +1 -1
- package/agent-skills/packs/hive-mcp/references/client-install-matrix.md +1 -1
- package/agent-skills/packs/hive-mcp/references/clients.md +141 -0
- package/agent-skills/packs/hive-query/SKILL.md +3 -2
- package/agent-skills/packs/hive-query/references/root-mcp-workflow.md +1 -1
- package/agent-skills/packs/hive-stateful-monitoring/SKILL.md +75 -0
- package/agent-skills/packs/hive-stateful-monitoring/evals/evals.json +49 -0
- package/agent-skills/packs/hive-tool-discovery/SKILL.md +1 -1
- package/agent-skills/references/agents-routing.md +2 -0
- package/agent-skills/scripts/validate-agent-skills-package.mjs +49 -11
- package/agent-skills/skills.sh.json +3 -2
- package/build/{alias-CZ3DEYHF.js → alias-3OPMQF4X.js} +2 -3
- package/build/{api-client-I23XLSHU.js → api-client-EPF6FD7A.js} +4 -4
- package/build/{auth-KKINNBXT.js → auth-Q5Q24IRI.js} +3 -4
- package/build/{browser-auth-EEFGRHWY.js → browser-auth-VPF5LZMZ.js} +2 -3
- package/build/{cache-EGNMENNA.js → cache-T6KC5YEY.js} +2 -3
- package/build/{chunk-KBVPIZS4.js → chunk-3WYWXTNN.js} +0 -1
- package/build/{chunk-2MYMHMBF.js → chunk-4F5CI6LX.js} +6 -6
- package/build/{chunk-RKICZ6DZ.js → chunk-5XXI25JE.js} +7 -8
- package/build/{chunk-IZTN7WFH.js → chunk-7JWXBKEJ.js} +5 -3
- package/build/chunk-CEWCB5YS.js +71 -0
- package/build/{chunk-MPIUUE3T.js → chunk-FH3YGSY5.js} +0 -1
- package/build/{chunk-QNCI4DEB.js → chunk-FRXMGRZQ.js} +35 -21
- package/build/{chunk-PGBVNMNZ.js → chunk-GZPDEXO4.js} +0 -1
- package/build/{chunk-UKHZIVDT.js → chunk-IZPAMRHP.js} +5 -6
- package/build/{chunk-2X3U4DFK.js → chunk-JTUKQWIO.js} +3267 -916
- package/build/{chunk-XYBEFFZ3.js → chunk-NP6NSOG2.js} +1 -2
- package/build/{chunk-V77LO4RO.js → chunk-POT2MBEK.js} +0 -1
- package/build/{chunk-B6G222LS.js → chunk-VBOKVQ74.js} +18 -3
- package/build/{chunk-DYJBTKNR.js → chunk-YZ2PXBJK.js} +5 -3
- package/build/chunk-ZCU7XQKF.js +14 -0
- package/build/{chunk-KGYBTXIN.js → chunk-ZTJVOWDQ.js} +0 -1
- package/build/{chunk-IDZD2NVG.js → chunk-ZXB53E7H.js} +5 -6
- package/build/cli.js +56 -54
- package/build/{completion-BELZL7ND.js → completion-46K674EL.js} +2 -3
- package/build/{config-TDX4VUGW.js → config-XE6Q5P4I.js} +3 -4
- package/build/{config-dir-V43W2WIA.js → config-dir-MAWX5AUF.js} +2 -3
- package/build/{doctor-5K5UWHNX.js → doctor-HGMQE6IN.js} +33 -9
- package/build/{errors-E6MVUBNA.js → errors-J2PH3NLJ.js} +2 -3
- package/build/{format-TSFSI2K7.js → format-5X2HIVDT.js} +1 -2
- package/build/{init-YQ5NBICF.js → init-JMDNM7ZZ.js} +1 -2
- package/build/{init-all-6OWEQALB.js → init-all-5SKNV75X.js} +10 -11
- package/build/{mcpServer-AEX3RQ4U.js → mcpServer-5TKKSKJM.js} +7 -6
- package/build/monitor-worker.js +1140 -0
- package/build/{namespace-PVHBFDW2.js → namespace-FSX2G3NM.js} +2 -3
- package/build/{open-YUIJP37F.js → open-5A6ZQMGC.js} +2 -3
- package/build/{output-IYJBFCYK.js → output-V3D4YZ6U.js} +2 -3
- package/build/{serve-KWNJK6EY.js → serve-AGCOXXFM.js} +9 -4
- package/build/server.js +437 -145
- package/build/{setup-YTUKMPNP.js → setup-RMETGJWK.js} +4 -5
- package/build/stdio.js +9 -8
- package/build/{telemetry-5IPRKZBL.js → telemetry-WCME5XEU.js} +4 -4
- package/build/{tools-PJHWFCAG.js → tools-KAB6QBZC.js} +15 -15
- package/build/{uninstall-HWXEIP6K.js → uninstall-FLJMBBSC.js} +7 -8
- package/build/update-check-LNZQK3XA.js +18 -0
- package/build/upgrade-DTUIHVPS.js +171 -0
- package/build/version-I6HDAF4L.js +14 -0
- package/build/{watch-KZ5EDZK3.js → watch-YNN255QX.js} +7 -7
- package/package.json +14 -9
- package/build/alias-CZ3DEYHF.js.map +0 -1
- package/build/api-client-I23XLSHU.js.map +0 -1
- package/build/auth-KKINNBXT.js.map +0 -1
- package/build/browser-auth-EEFGRHWY.js.map +0 -1
- package/build/cache-EGNMENNA.js.map +0 -1
- package/build/chunk-2MYMHMBF.js.map +0 -1
- package/build/chunk-2X3U4DFK.js.map +0 -1
- package/build/chunk-B6G222LS.js.map +0 -1
- package/build/chunk-DYJBTKNR.js.map +0 -1
- package/build/chunk-IDZD2NVG.js.map +0 -1
- package/build/chunk-IZTN7WFH.js.map +0 -1
- package/build/chunk-KBVPIZS4.js.map +0 -1
- package/build/chunk-KGYBTXIN.js.map +0 -1
- package/build/chunk-MPIUUE3T.js.map +0 -1
- package/build/chunk-PGBVNMNZ.js.map +0 -1
- package/build/chunk-QNCI4DEB.js.map +0 -1
- package/build/chunk-RKICZ6DZ.js.map +0 -1
- package/build/chunk-UKHZIVDT.js.map +0 -1
- package/build/chunk-V77LO4RO.js.map +0 -1
- package/build/chunk-XYBEFFZ3.js.map +0 -1
- package/build/cli.js.map +0 -1
- package/build/completion-BELZL7ND.js.map +0 -1
- package/build/config-TDX4VUGW.js.map +0 -1
- package/build/config-dir-V43W2WIA.js.map +0 -1
- package/build/doctor-5K5UWHNX.js.map +0 -1
- package/build/errors-E6MVUBNA.js.map +0 -1
- package/build/format-TSFSI2K7.js.map +0 -1
- package/build/init-YQ5NBICF.js.map +0 -1
- package/build/init-all-6OWEQALB.js.map +0 -1
- package/build/mcpServer-AEX3RQ4U.js.map +0 -1
- package/build/namespace-PVHBFDW2.js.map +0 -1
- package/build/open-YUIJP37F.js.map +0 -1
- package/build/output-IYJBFCYK.js.map +0 -1
- package/build/serve-KWNJK6EY.js.map +0 -1
- package/build/server.js.map +0 -1
- package/build/setup-YTUKMPNP.js.map +0 -1
- package/build/stdio.js.map +0 -1
- package/build/telemetry-5IPRKZBL.js.map +0 -1
- package/build/tools-PJHWFCAG.js.map +0 -1
- package/build/uninstall-HWXEIP6K.js.map +0 -1
- package/build/watch-KZ5EDZK3.js.map +0 -1
package/build/server.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
executeToolByName
|
|
5
|
+
} from "./chunk-CEWCB5YS.js";
|
|
3
6
|
import {
|
|
4
7
|
AUTH_COMPATIBILITY,
|
|
5
8
|
CategoryEndpoints,
|
|
9
|
+
HIVE_AUTH_SUBJECT_ARG,
|
|
10
|
+
HIVE_AUTH_USER_ARG,
|
|
6
11
|
HIVE_PROMPTS,
|
|
7
12
|
HIVE_RESOURCES,
|
|
8
13
|
RUNTIME_STATUSES,
|
|
9
|
-
SERVER_NAME,
|
|
10
|
-
SERVER_VERSION,
|
|
11
14
|
TASK_TOOLSETS,
|
|
12
15
|
TASK_TOOLSET_RUNTIME_STATUSES,
|
|
13
16
|
ToolRegistry,
|
|
@@ -15,9 +18,8 @@ import {
|
|
|
15
18
|
buildToolCatalogEntry,
|
|
16
19
|
classifyRuntimeStatusFromError,
|
|
17
20
|
createHiveMcpServer,
|
|
18
|
-
createToolNotFoundResult,
|
|
19
21
|
dynamicTools,
|
|
20
|
-
|
|
22
|
+
generateSubjectSigningSecret,
|
|
21
23
|
getAllWrappedEndpoints,
|
|
22
24
|
getCorsAllowedOrigins,
|
|
23
25
|
getCsvEnv,
|
|
@@ -27,27 +29,35 @@ import {
|
|
|
27
29
|
getProviderList,
|
|
28
30
|
getRateLimitMax,
|
|
29
31
|
getRedisClient,
|
|
30
|
-
getRequiredEnvVar,
|
|
31
32
|
getRootVisibleToolCount,
|
|
32
|
-
|
|
33
|
+
getSupabaseAdmin,
|
|
34
|
+
getSupabaseAuthClient,
|
|
33
35
|
getTaskCanaryCatalog,
|
|
34
36
|
getTaskCanaryHistory,
|
|
35
|
-
|
|
37
|
+
hasSubjectSigningSecret,
|
|
38
|
+
isB2BSubjectsEnabled,
|
|
36
39
|
isProduction,
|
|
37
40
|
isRedisAvailable,
|
|
38
|
-
|
|
41
|
+
isSupabaseConfigured,
|
|
42
|
+
recordSubjectAuditEvent,
|
|
43
|
+
resolveSubjectContext,
|
|
39
44
|
runSelfTestFull,
|
|
40
45
|
runSelfTestProvider,
|
|
41
46
|
runSelfTestQuick,
|
|
42
47
|
runTaskCanariesQuick,
|
|
43
48
|
runTaskCanary,
|
|
49
|
+
sanitizeKeyMeta,
|
|
44
50
|
secureLogger,
|
|
45
51
|
trackServerEvent
|
|
46
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-JTUKQWIO.js";
|
|
47
53
|
import {
|
|
48
54
|
HIVE_AGENT_SKILLS
|
|
49
|
-
} from "./chunk-
|
|
50
|
-
import
|
|
55
|
+
} from "./chunk-VBOKVQ74.js";
|
|
56
|
+
import {
|
|
57
|
+
SERVER_NAME,
|
|
58
|
+
SERVER_VERSION
|
|
59
|
+
} from "./chunk-ZCU7XQKF.js";
|
|
60
|
+
import "./chunk-3WYWXTNN.js";
|
|
51
61
|
|
|
52
62
|
// src/server.ts
|
|
53
63
|
import dotenv from "dotenv";
|
|
@@ -1048,46 +1058,6 @@ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
|
1048
1058
|
|
|
1049
1059
|
// src/services/unkey-service.ts
|
|
1050
1060
|
import { Unkey } from "@unkey/api";
|
|
1051
|
-
|
|
1052
|
-
// src/db/supabase.ts
|
|
1053
|
-
import { createClient } from "@supabase/supabase-js";
|
|
1054
|
-
var _supabaseAdmin = null;
|
|
1055
|
-
var _supabaseAuth = null;
|
|
1056
|
-
function isSupabaseConfigured() {
|
|
1057
|
-
return hasEnvVars("SUPABASE_URL", "SUPABASE_SERVICE_ROLE_KEY");
|
|
1058
|
-
}
|
|
1059
|
-
function getSupabaseAdmin() {
|
|
1060
|
-
if (!_supabaseAdmin) {
|
|
1061
|
-
if (!isSupabaseConfigured()) {
|
|
1062
|
-
throw new Error(
|
|
1063
|
-
"Supabase not configured. Set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY."
|
|
1064
|
-
);
|
|
1065
|
-
}
|
|
1066
|
-
_supabaseAdmin = createClient(
|
|
1067
|
-
getRequiredEnvVar("SUPABASE_URL"),
|
|
1068
|
-
getRequiredEnvVar("SUPABASE_SERVICE_ROLE_KEY"),
|
|
1069
|
-
{ auth: { persistSession: false, autoRefreshToken: false } }
|
|
1070
|
-
);
|
|
1071
|
-
}
|
|
1072
|
-
return _supabaseAdmin;
|
|
1073
|
-
}
|
|
1074
|
-
function getSupabaseAuthClient() {
|
|
1075
|
-
if (!_supabaseAuth) {
|
|
1076
|
-
if (!hasEnvVars("SUPABASE_URL", "SUPABASE_ANON_KEY")) {
|
|
1077
|
-
throw new Error(
|
|
1078
|
-
"Supabase auth client not configured. Set SUPABASE_URL and SUPABASE_ANON_KEY."
|
|
1079
|
-
);
|
|
1080
|
-
}
|
|
1081
|
-
_supabaseAuth = createClient(
|
|
1082
|
-
getRequiredEnvVar("SUPABASE_URL"),
|
|
1083
|
-
getRequiredEnvVar("SUPABASE_ANON_KEY"),
|
|
1084
|
-
{ auth: { persistSession: false, autoRefreshToken: false } }
|
|
1085
|
-
);
|
|
1086
|
-
}
|
|
1087
|
-
return _supabaseAuth;
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
// src/services/unkey-service.ts
|
|
1091
1061
|
var _unkey = null;
|
|
1092
1062
|
function getAuthBackendMode() {
|
|
1093
1063
|
const mode = (process.env.HIVE_AUTH_BACKEND ?? "auto").trim().toLowerCase();
|
|
@@ -1155,13 +1125,22 @@ async function createApiKey(opts) {
|
|
|
1155
1125
|
`Key limit reached. Your ${plan.name} plan allows ${plan.max_api_keys} keys.`
|
|
1156
1126
|
);
|
|
1157
1127
|
}
|
|
1128
|
+
const subjectSigningSecret = opts.b2bSubjectsEnabled ? generateSubjectSigningSecret() : void 0;
|
|
1129
|
+
const meta = {
|
|
1130
|
+
plan: opts.planId,
|
|
1131
|
+
name: opts.name,
|
|
1132
|
+
...opts.b2bSubjectsEnabled ? {
|
|
1133
|
+
b2b_subjects_enabled: true,
|
|
1134
|
+
subject_signing_secret: subjectSigningSecret
|
|
1135
|
+
} : {}
|
|
1136
|
+
};
|
|
1158
1137
|
const result = await getUnkey().keys.createKey({
|
|
1159
1138
|
apiId: getApiId(),
|
|
1160
1139
|
prefix: "hive_live",
|
|
1161
1140
|
name: opts.name,
|
|
1162
1141
|
byteLength: 24,
|
|
1163
1142
|
externalId: opts.userId,
|
|
1164
|
-
meta
|
|
1143
|
+
meta,
|
|
1165
1144
|
ratelimits: [
|
|
1166
1145
|
{
|
|
1167
1146
|
name: "requests",
|
|
@@ -1177,7 +1156,11 @@ async function createApiKey(opts) {
|
|
|
1177
1156
|
});
|
|
1178
1157
|
throw new Error("Failed to create API key");
|
|
1179
1158
|
}
|
|
1180
|
-
return {
|
|
1159
|
+
return {
|
|
1160
|
+
keyId: result.data.keyId,
|
|
1161
|
+
key: result.data.key,
|
|
1162
|
+
subjectSigningSecret
|
|
1163
|
+
};
|
|
1181
1164
|
}
|
|
1182
1165
|
async function verifyApiKey(rawKey, analyticsTags = []) {
|
|
1183
1166
|
const tags = normalizeAnalyticsTags(analyticsTags);
|
|
@@ -1207,6 +1190,7 @@ async function verifyApiKey(rawKey, analyticsTags = []) {
|
|
|
1207
1190
|
planId: d.meta?.plan,
|
|
1208
1191
|
name: d.name,
|
|
1209
1192
|
credits: d.credits ?? void 0,
|
|
1193
|
+
meta: d.meta ?? void 0,
|
|
1210
1194
|
ratelimit: rl ? { remaining: rl.remaining, limit: rl.limit, reset: rl.reset } : void 0
|
|
1211
1195
|
};
|
|
1212
1196
|
}
|
|
@@ -1225,7 +1209,7 @@ async function listKeys(userId) {
|
|
|
1225
1209
|
enabled: k.enabled ?? true,
|
|
1226
1210
|
credits: k.credits?.remaining ?? void 0,
|
|
1227
1211
|
externalId: k.identity?.externalId ?? void 0,
|
|
1228
|
-
meta: k.meta ?? void 0
|
|
1212
|
+
meta: sanitizeKeyMeta(k.meta ?? void 0)
|
|
1229
1213
|
}));
|
|
1230
1214
|
}
|
|
1231
1215
|
async function revokeKey(keyId) {
|
|
@@ -3564,7 +3548,8 @@ async function handleRedisLookup(key, res, next) {
|
|
|
3564
3548
|
// src/routes/keys.ts
|
|
3565
3549
|
var router3 = Router3();
|
|
3566
3550
|
var CreateKeySchema = z2.object({
|
|
3567
|
-
name: z2.string().min(1).max(100).optional()
|
|
3551
|
+
name: z2.string().min(1).max(100).optional(),
|
|
3552
|
+
b2b_subjects_enabled: z2.boolean().optional()
|
|
3568
3553
|
});
|
|
3569
3554
|
router3.post(
|
|
3570
3555
|
"/",
|
|
@@ -3582,7 +3567,7 @@ router3.post(
|
|
|
3582
3567
|
)
|
|
3583
3568
|
);
|
|
3584
3569
|
}
|
|
3585
|
-
const { name } = parseResult.data;
|
|
3570
|
+
const { name, b2b_subjects_enabled } = parseResult.data;
|
|
3586
3571
|
const { data: profile } = await getSupabaseAdmin().from("user_profiles").select("plan_id").eq("id", user.id).single();
|
|
3587
3572
|
const planId = profile?.plan_id ?? "demo";
|
|
3588
3573
|
await ensureWallet(user.id, planId);
|
|
@@ -3590,7 +3575,8 @@ router3.post(
|
|
|
3590
3575
|
const result = await createApiKey({
|
|
3591
3576
|
userId: user.id,
|
|
3592
3577
|
name: name ?? "Default",
|
|
3593
|
-
planId
|
|
3578
|
+
planId,
|
|
3579
|
+
b2bSubjectsEnabled: b2b_subjects_enabled ?? false
|
|
3594
3580
|
});
|
|
3595
3581
|
return res.status(201).json({
|
|
3596
3582
|
ok: true,
|
|
@@ -3599,6 +3585,8 @@ router3.post(
|
|
|
3599
3585
|
key: result.key,
|
|
3600
3586
|
name: name ?? "Default",
|
|
3601
3587
|
plan: planId,
|
|
3588
|
+
b2b_subjects_enabled: b2b_subjects_enabled ?? false,
|
|
3589
|
+
...result.subjectSigningSecret ? { subject_signing_secret: result.subjectSigningSecret } : {},
|
|
3602
3590
|
warning: "Save this key \u2014 it will not be shown again."
|
|
3603
3591
|
}
|
|
3604
3592
|
});
|
|
@@ -3743,6 +3731,176 @@ router4.get(
|
|
|
3743
3731
|
);
|
|
3744
3732
|
var usage_default = router4;
|
|
3745
3733
|
|
|
3734
|
+
// src/routes/b2b.ts
|
|
3735
|
+
import { Router as Router5 } from "express";
|
|
3736
|
+
var router5 = Router5();
|
|
3737
|
+
var SIGNED_SUBJECT_HEADERS = [
|
|
3738
|
+
"X-Hive-Tenant-Id",
|
|
3739
|
+
"X-Hive-End-User-Id",
|
|
3740
|
+
"X-Hive-Subject-Timestamp",
|
|
3741
|
+
"X-Hive-Subject-Signature"
|
|
3742
|
+
];
|
|
3743
|
+
var SIGNATURE_PAYLOAD = 'METHOD + "\\n" + PATH + "\\n" + TENANT_ID + "\\n" + END_USER_ID + "\\n" + TIMESTAMP';
|
|
3744
|
+
function buildB2BReadinessPayload(args) {
|
|
3745
|
+
const meta = args.verifyResult?.meta;
|
|
3746
|
+
const b2bEnabled = args.authBackend === "unkey" ? isB2BSubjectsEnabled(meta) : false;
|
|
3747
|
+
const secretConfigured = args.authBackend === "unkey" && b2bEnabled ? hasSubjectSigningSecret(meta) : false;
|
|
3748
|
+
const warnings = [];
|
|
3749
|
+
let mode;
|
|
3750
|
+
if (args.authBackend === "static") {
|
|
3751
|
+
mode = "static_key";
|
|
3752
|
+
warnings.push(
|
|
3753
|
+
"Static HIVE_API_KEYS authentication does not provide a Hive owner user_id or per-key B2B subject metadata. Use Unkey-backed Hive keys for partner/end-user state isolation."
|
|
3754
|
+
);
|
|
3755
|
+
} else if (b2bEnabled) {
|
|
3756
|
+
mode = "b2b_enabled";
|
|
3757
|
+
if (!secretConfigured) {
|
|
3758
|
+
warnings.push(
|
|
3759
|
+
"This API key has B2B subjects enabled but no subject signing secret is configured. Stateful writes with signed subject headers will fail."
|
|
3760
|
+
);
|
|
3761
|
+
}
|
|
3762
|
+
} else {
|
|
3763
|
+
mode = "direct_user";
|
|
3764
|
+
warnings.push(
|
|
3765
|
+
"This key is valid for direct-user state, but B2B subjects are not enabled. A partner using this key without signed subject headers will share one default subject across downstream customers."
|
|
3766
|
+
);
|
|
3767
|
+
}
|
|
3768
|
+
return {
|
|
3769
|
+
b2b_adapter_ready: args.authBackend === "unkey" && b2bEnabled && secretConfigured,
|
|
3770
|
+
mode,
|
|
3771
|
+
auth_backend: args.authBackend,
|
|
3772
|
+
api_key: {
|
|
3773
|
+
valid: true,
|
|
3774
|
+
...args.verifyResult?.keyId ? { key_id: args.verifyResult.keyId } : {},
|
|
3775
|
+
...args.verifyResult?.userId ? { owner_user_id: args.verifyResult.userId } : {},
|
|
3776
|
+
...args.verifyResult?.planId ? { plan_id: args.verifyResult.planId } : {},
|
|
3777
|
+
...args.verifyResult?.name ? { name: args.verifyResult.name } : {},
|
|
3778
|
+
b2b_subjects_enabled: b2bEnabled,
|
|
3779
|
+
subject_signing_secret_configured: secretConfigured,
|
|
3780
|
+
...args.verifyResult?.ratelimit ? { ratelimit_remaining: args.verifyResult.ratelimit.remaining } : {}
|
|
3781
|
+
},
|
|
3782
|
+
state: {
|
|
3783
|
+
stateful_tools_supported: args.authBackend === "unkey",
|
|
3784
|
+
direct_user_subject: "default_self",
|
|
3785
|
+
signed_subjects_required_for_stateful_writes: b2bEnabled,
|
|
3786
|
+
isolation_boundary: "owner_user_id + subject_id"
|
|
3787
|
+
},
|
|
3788
|
+
signed_subject_headers: SIGNED_SUBJECT_HEADERS,
|
|
3789
|
+
signature_payload: SIGNATURE_PAYLOAD,
|
|
3790
|
+
signature_algorithm: "HMAC-SHA256",
|
|
3791
|
+
timestamp_skew_seconds: 300,
|
|
3792
|
+
endpoints: {
|
|
3793
|
+
mcp: "/mcp",
|
|
3794
|
+
rest_execute: "/api/v1/execute",
|
|
3795
|
+
readiness: "/api/v1/b2b/readiness"
|
|
3796
|
+
},
|
|
3797
|
+
smoke: {
|
|
3798
|
+
command: "npm run smoke:b2b-partner",
|
|
3799
|
+
required_env: ["HIVE_API_KEY", "HIVE_SUBJECT_SIGNING_SECRET"]
|
|
3800
|
+
},
|
|
3801
|
+
warnings
|
|
3802
|
+
};
|
|
3803
|
+
}
|
|
3804
|
+
function getRequestApiKey(req) {
|
|
3805
|
+
const xApiKey = req.headers["x-api-key"];
|
|
3806
|
+
if (typeof xApiKey === "string" && xApiKey.trim()) return xApiKey.trim();
|
|
3807
|
+
const auth = req.headers.authorization;
|
|
3808
|
+
if (auth?.startsWith("Bearer ")) {
|
|
3809
|
+
const token = auth.slice("Bearer ".length).trim();
|
|
3810
|
+
return token || void 0;
|
|
3811
|
+
}
|
|
3812
|
+
return void 0;
|
|
3813
|
+
}
|
|
3814
|
+
router5.get(
|
|
3815
|
+
"/readiness",
|
|
3816
|
+
asyncHandler(async (req, res) => {
|
|
3817
|
+
const key = getRequestApiKey(req);
|
|
3818
|
+
if (!key) {
|
|
3819
|
+
return res.status(401).json(
|
|
3820
|
+
apiError(
|
|
3821
|
+
"authentication_error",
|
|
3822
|
+
"AUTH_REQUIRED",
|
|
3823
|
+
"API key required. Set x-api-key header or Authorization: Bearer <key>.",
|
|
3824
|
+
{ requestId: req.requestId }
|
|
3825
|
+
)
|
|
3826
|
+
);
|
|
3827
|
+
}
|
|
3828
|
+
if (isUnkeyRequired() && !isUnkeyConfigured()) {
|
|
3829
|
+
return res.status(503).json(
|
|
3830
|
+
apiError(
|
|
3831
|
+
"internal_error",
|
|
3832
|
+
"AUTH_NOT_CONFIGURED",
|
|
3833
|
+
"Unkey authentication is selected but not configured. Set UNKEY_ROOT_KEY and UNKEY_API_ID, or set HIVE_AUTH_BACKEND=static with HIVE_API_KEYS.",
|
|
3834
|
+
{ requestId: req.requestId }
|
|
3835
|
+
)
|
|
3836
|
+
);
|
|
3837
|
+
}
|
|
3838
|
+
if (isUnkeyConfigured()) {
|
|
3839
|
+
const result = await verifyApiKey(key, [
|
|
3840
|
+
"service=hive",
|
|
3841
|
+
"transport=rest",
|
|
3842
|
+
"route=/api/v1/b2b/readiness"
|
|
3843
|
+
]);
|
|
3844
|
+
if (!result.valid) {
|
|
3845
|
+
const statusCode = result.code === "RATE_LIMITED" ? 429 : 403;
|
|
3846
|
+
const errorCode = result.code === "RATE_LIMITED" ? "RATE_LIMITED" : "INVALID_API_KEY";
|
|
3847
|
+
if (result.code === "RATE_LIMITED") res.setHeader("Retry-After", "60");
|
|
3848
|
+
return res.status(statusCode).json(
|
|
3849
|
+
apiError(
|
|
3850
|
+
"authentication_error",
|
|
3851
|
+
errorCode,
|
|
3852
|
+
result.code === "RATE_LIMITED" ? "Rate limit exceeded." : "Invalid API key.",
|
|
3853
|
+
{ requestId: req.requestId }
|
|
3854
|
+
)
|
|
3855
|
+
);
|
|
3856
|
+
}
|
|
3857
|
+
if (!result.userId) {
|
|
3858
|
+
return res.status(403).json(
|
|
3859
|
+
apiError(
|
|
3860
|
+
"authentication_error",
|
|
3861
|
+
"INVALID_API_KEY",
|
|
3862
|
+
"Invalid API key.",
|
|
3863
|
+
{ requestId: req.requestId }
|
|
3864
|
+
)
|
|
3865
|
+
);
|
|
3866
|
+
}
|
|
3867
|
+
return res.json({
|
|
3868
|
+
ok: true,
|
|
3869
|
+
data: buildB2BReadinessPayload({
|
|
3870
|
+
authBackend: "unkey",
|
|
3871
|
+
verifyResult: result
|
|
3872
|
+
})
|
|
3873
|
+
});
|
|
3874
|
+
}
|
|
3875
|
+
const staticKeys = getCsvEnv("HIVE_API_KEYS");
|
|
3876
|
+
if (staticKeys.length === 0) {
|
|
3877
|
+
return res.status(503).json(
|
|
3878
|
+
apiError(
|
|
3879
|
+
"internal_error",
|
|
3880
|
+
"AUTH_NOT_CONFIGURED",
|
|
3881
|
+
"API key authentication is not configured. Set HIVE_API_KEYS or configure Unkey.",
|
|
3882
|
+
{ requestId: req.requestId }
|
|
3883
|
+
)
|
|
3884
|
+
);
|
|
3885
|
+
}
|
|
3886
|
+
if (!staticKeys.includes(key)) {
|
|
3887
|
+
return res.status(403).json(
|
|
3888
|
+
apiError(
|
|
3889
|
+
"authentication_error",
|
|
3890
|
+
"INVALID_API_KEY",
|
|
3891
|
+
"Invalid API key.",
|
|
3892
|
+
{ requestId: req.requestId }
|
|
3893
|
+
)
|
|
3894
|
+
);
|
|
3895
|
+
}
|
|
3896
|
+
return res.json({
|
|
3897
|
+
ok: true,
|
|
3898
|
+
data: buildB2BReadinessPayload({ authBackend: "static" })
|
|
3899
|
+
});
|
|
3900
|
+
})
|
|
3901
|
+
);
|
|
3902
|
+
var b2b_default = router5;
|
|
3903
|
+
|
|
3746
3904
|
// src/middleware/request-id.ts
|
|
3747
3905
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3748
3906
|
function requestIdMiddleware(req, res, next) {
|
|
@@ -4075,64 +4233,6 @@ function generateOpenApiSpec() {
|
|
|
4075
4233
|
return _cachedSpec;
|
|
4076
4234
|
}
|
|
4077
4235
|
|
|
4078
|
-
// src/services/tool-execution.ts
|
|
4079
|
-
async function executeToolByName(toolName, args) {
|
|
4080
|
-
const allEndpoints = getAllWrappedEndpoints();
|
|
4081
|
-
const lookup = resolveEndpoint(allEndpoints, toolName);
|
|
4082
|
-
if (!lookup.ok) {
|
|
4083
|
-
const result2 = createToolNotFoundResult(toolName);
|
|
4084
|
-
secureLogger.toolCall(toolName, false, result2.durationMs, {
|
|
4085
|
-
transport: "rest",
|
|
4086
|
-
runtimeStatus: "failing",
|
|
4087
|
-
errorClass: "not_found"
|
|
4088
|
-
});
|
|
4089
|
-
return {
|
|
4090
|
-
ok: false,
|
|
4091
|
-
error: result2.error,
|
|
4092
|
-
durationMs: result2.durationMs,
|
|
4093
|
-
meta: result2.hive
|
|
4094
|
-
};
|
|
4095
|
-
}
|
|
4096
|
-
const result = await executeEndpoint(lookup.endpoint, args, {
|
|
4097
|
-
transport: "rest",
|
|
4098
|
-
clients: getSharedClients()
|
|
4099
|
-
});
|
|
4100
|
-
if (result.validationErrors) {
|
|
4101
|
-
return {
|
|
4102
|
-
ok: false,
|
|
4103
|
-
error: result.error,
|
|
4104
|
-
validationErrors: result.validationErrors,
|
|
4105
|
-
durationMs: result.durationMs,
|
|
4106
|
-
meta: result.hive
|
|
4107
|
-
};
|
|
4108
|
-
}
|
|
4109
|
-
if (result.ok) {
|
|
4110
|
-
return {
|
|
4111
|
-
ok: true,
|
|
4112
|
-
data: result.data,
|
|
4113
|
-
durationMs: result.durationMs,
|
|
4114
|
-
meta: result.hive
|
|
4115
|
-
};
|
|
4116
|
-
}
|
|
4117
|
-
if (result.error?.code === "PROVIDER_UNAVAILABLE") {
|
|
4118
|
-
return {
|
|
4119
|
-
ok: false,
|
|
4120
|
-
error: result.error,
|
|
4121
|
-
durationMs: result.durationMs,
|
|
4122
|
-
meta: result.hive
|
|
4123
|
-
};
|
|
4124
|
-
}
|
|
4125
|
-
if (result.error?.code === "INTERNAL_ERROR") {
|
|
4126
|
-
secureLogger.error(`[tool-execution] ${toolName} threw`, result.error, {});
|
|
4127
|
-
}
|
|
4128
|
-
return {
|
|
4129
|
-
ok: false,
|
|
4130
|
-
error: result.error,
|
|
4131
|
-
durationMs: result.durationMs,
|
|
4132
|
-
meta: result.hive
|
|
4133
|
-
};
|
|
4134
|
-
}
|
|
4135
|
-
|
|
4136
4236
|
// src/utils/mcpHttp.ts
|
|
4137
4237
|
function isMcpPath(path) {
|
|
4138
4238
|
return path === "/mcp" || path === "/mcp/" || /\/mcp\/?$/.test(path);
|
|
@@ -4145,6 +4245,7 @@ function hasRequiredStreamableHttpAcceptHeader(acceptHeader) {
|
|
|
4145
4245
|
}
|
|
4146
4246
|
|
|
4147
4247
|
// src/serverCard.ts
|
|
4248
|
+
import { LATEST_PROTOCOL_VERSION } from "@modelcontextprotocol/sdk/types.js";
|
|
4148
4249
|
function buildServerCard() {
|
|
4149
4250
|
const underlyingToolCount = getAllWrappedEndpoints().length;
|
|
4150
4251
|
const visibleToolCount = getRootVisibleToolCount();
|
|
@@ -4153,8 +4254,8 @@ function buildServerCard() {
|
|
|
4153
4254
|
name: "Hive Intelligence",
|
|
4154
4255
|
id: "io.github.sharpe-labs/hive-mcp",
|
|
4155
4256
|
version: SERVER_VERSION,
|
|
4156
|
-
protocolVersion:
|
|
4157
|
-
description: "
|
|
4257
|
+
protocolVersion: LATEST_PROTOCOL_VERSION,
|
|
4258
|
+
description: "Managed crypto market infrastructure for AI agents \u2014 live prices, DeFi, wallets, and token risk through MCP, REST API, or CLI.",
|
|
4158
4259
|
author: {
|
|
4159
4260
|
name: "Hive Intelligence",
|
|
4160
4261
|
url: "https://www.hiveintelligence.xyz",
|
|
@@ -4164,7 +4265,7 @@ function buildServerCard() {
|
|
|
4164
4265
|
documentation: "https://www.hiveintelligence.xyz/crypto-mcp",
|
|
4165
4266
|
repository: {
|
|
4166
4267
|
type: "git",
|
|
4167
|
-
url: "https://github.com/
|
|
4268
|
+
url: "https://github.com/hive-intel/hive-sdk"
|
|
4168
4269
|
},
|
|
4169
4270
|
license: "MIT",
|
|
4170
4271
|
categories: ["finance", "crypto", "defi", "web3", "ai-agents"],
|
|
@@ -4211,6 +4312,18 @@ function buildServerCard() {
|
|
|
4211
4312
|
Authorization: "Bearer <YOUR_HIVE_API_KEY>",
|
|
4212
4313
|
"x-api-key": "<YOUR_HIVE_API_KEY>"
|
|
4213
4314
|
},
|
|
4315
|
+
b2bSubjectHeaders: {
|
|
4316
|
+
note: "B2B-enabled API keys may isolate downstream customer state by sending signed subject headers from a trusted backend adapter. Stateful writes require these headers when b2b_subjects_enabled=true.",
|
|
4317
|
+
readinessUrl: "https://mcp.hiveintelligence.xyz/api/v1/b2b/readiness",
|
|
4318
|
+
headers: [
|
|
4319
|
+
"X-Hive-Tenant-Id",
|
|
4320
|
+
"X-Hive-End-User-Id",
|
|
4321
|
+
"X-Hive-Subject-Timestamp",
|
|
4322
|
+
"X-Hive-Subject-Signature"
|
|
4323
|
+
],
|
|
4324
|
+
signaturePayload: 'METHOD + "\\n" + PATH + "\\n" + TENANT_ID + "\\n" + END_USER_ID + "\\n" + TIMESTAMP',
|
|
4325
|
+
algorithm: "HMAC-SHA256"
|
|
4326
|
+
},
|
|
4214
4327
|
signupUrl: "https://www.hiveintelligence.xyz/login?next=/dashboard/keys",
|
|
4215
4328
|
freeTier: {
|
|
4216
4329
|
monthlyCredits: 1e4,
|
|
@@ -4266,9 +4379,13 @@ function buildServerCard() {
|
|
|
4266
4379
|
setupUrl: "https://hiveintelligence.xyz/install/claude-code"
|
|
4267
4380
|
},
|
|
4268
4381
|
{
|
|
4269
|
-
name: "
|
|
4382
|
+
name: "OpenAI Responses API",
|
|
4270
4383
|
setupUrl: "https://hiveintelligence.xyz/install/chatgpt"
|
|
4271
4384
|
},
|
|
4385
|
+
{
|
|
4386
|
+
name: "Codex CLI",
|
|
4387
|
+
setupUrl: "https://hiveintelligence.xyz/install/codex"
|
|
4388
|
+
},
|
|
4272
4389
|
{
|
|
4273
4390
|
name: "Cursor",
|
|
4274
4391
|
setupUrl: "https://hiveintelligence.xyz/install/cursor"
|
|
@@ -4363,13 +4480,16 @@ app.use(
|
|
|
4363
4480
|
(req, res, next) => {
|
|
4364
4481
|
if (req.method === "POST" && (req.path === "/mcp" || req.path.endsWith("/mcp"))) {
|
|
4365
4482
|
const origin = req.headers.origin;
|
|
4366
|
-
if (origin && !LOCALHOST_RE.test(origin)
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4483
|
+
if (origin && !LOCALHOST_RE.test(origin)) {
|
|
4484
|
+
const enforce = isProduction() || ALLOWED_MCP_ORIGINS.length > 0;
|
|
4485
|
+
if (enforce && !ALLOWED_MCP_ORIGINS.includes(origin)) {
|
|
4486
|
+
res.status(403).json({
|
|
4487
|
+
jsonrpc: "2.0",
|
|
4488
|
+
error: { code: -32600, message: "Origin not allowed" },
|
|
4489
|
+
id: null
|
|
4490
|
+
});
|
|
4491
|
+
return;
|
|
4492
|
+
}
|
|
4373
4493
|
}
|
|
4374
4494
|
}
|
|
4375
4495
|
next();
|
|
@@ -4435,7 +4555,7 @@ function buildMcpDiscoveryDescriptor() {
|
|
|
4435
4555
|
name: "Hive Intelligence",
|
|
4436
4556
|
id: SERVER_NAME,
|
|
4437
4557
|
version: SERVER_VERSION,
|
|
4438
|
-
description: "
|
|
4558
|
+
description: "Managed crypto market infrastructure for AI agents \u2014 unified API for crypto market data, DeFi, wallets, security, DEX flows, NFTs, and prediction markets",
|
|
4439
4559
|
endpoints: {
|
|
4440
4560
|
mcp: "/mcp",
|
|
4441
4561
|
rest: "/api/v1",
|
|
@@ -4464,7 +4584,11 @@ app.get(["/.well-known/mcp.json", "/mcp.json"], (_req, res) => {
|
|
|
4464
4584
|
res.json(buildMcpDiscoveryDescriptor());
|
|
4465
4585
|
});
|
|
4466
4586
|
app.get(
|
|
4467
|
-
[
|
|
4587
|
+
[
|
|
4588
|
+
"/.well-known/mcp/server-card.json",
|
|
4589
|
+
"/server-card.json",
|
|
4590
|
+
"/mcp/server-card.json"
|
|
4591
|
+
],
|
|
4468
4592
|
(_req, res) => {
|
|
4469
4593
|
setDiscoveryHeaders(res);
|
|
4470
4594
|
res.json(buildServerCard());
|
|
@@ -4489,6 +4613,7 @@ app.use(health_default);
|
|
|
4489
4613
|
app.use("/auth", auth_default);
|
|
4490
4614
|
app.use("/api/v1/keys", keys_default);
|
|
4491
4615
|
app.use("/api/v1/usage", usage_default);
|
|
4616
|
+
app.use("/api/v1/b2b", b2b_default);
|
|
4492
4617
|
var mcpIpRateLimiter = createIpRateLimiter();
|
|
4493
4618
|
var restIpRateLimiter = createIpRateLimiter();
|
|
4494
4619
|
var mcpMiddlewares = [mcpIpRateLimiter];
|
|
@@ -4526,42 +4651,127 @@ function extractApiKey(req) {
|
|
|
4526
4651
|
async function validateMcpApiKey(req) {
|
|
4527
4652
|
const key = extractApiKey(req);
|
|
4528
4653
|
if (isUnkeyRequired() && !isUnkeyConfigured()) {
|
|
4529
|
-
return
|
|
4654
|
+
return {
|
|
4655
|
+
ok: false,
|
|
4656
|
+
error: "Unkey authentication is selected but not configured. Set UNKEY_ROOT_KEY and UNKEY_API_ID, or set HIVE_AUTH_BACKEND=static with HIVE_API_KEYS."
|
|
4657
|
+
};
|
|
4530
4658
|
}
|
|
4531
4659
|
if (isUnkeyConfigured()) {
|
|
4532
4660
|
if (!key)
|
|
4533
|
-
return
|
|
4661
|
+
return {
|
|
4662
|
+
ok: false,
|
|
4663
|
+
error: `API key required. Get a free key at https://hiveintelligence.xyz/dashboard/keys then pass it as 'Authorization: Bearer <key>' or 'x-api-key: <key>'. Claude Code: claude mcp add --transport http hive https://mcp.hiveintelligence.xyz/mcp --header "Authorization: Bearer <key>".`
|
|
4664
|
+
};
|
|
4534
4665
|
let result;
|
|
4535
4666
|
try {
|
|
4536
|
-
result = await withTimeout(
|
|
4667
|
+
result = await withTimeout(
|
|
4668
|
+
verifyApiKey(key, getMcpAnalyticsTags(req)),
|
|
4669
|
+
500
|
|
4670
|
+
);
|
|
4537
4671
|
} catch (err) {
|
|
4538
4672
|
secureLogger.warn("MCP Unkey verifyApiKey timeout/failure", {
|
|
4539
4673
|
error: err instanceof Error ? err.message : String(err)
|
|
4540
4674
|
});
|
|
4541
|
-
return
|
|
4675
|
+
return {
|
|
4676
|
+
ok: false,
|
|
4677
|
+
error: "Authentication service temporarily unavailable. Please retry in a moment."
|
|
4678
|
+
};
|
|
4542
4679
|
}
|
|
4543
4680
|
if (!result.valid) {
|
|
4544
|
-
if (result.code === "RATE_LIMITED")
|
|
4545
|
-
|
|
4681
|
+
if (result.code === "RATE_LIMITED") {
|
|
4682
|
+
return { ok: false, error: "Rate limit exceeded." };
|
|
4683
|
+
}
|
|
4684
|
+
return { ok: false, error: "Invalid API key." };
|
|
4546
4685
|
}
|
|
4547
4686
|
if (!result.userId) {
|
|
4548
|
-
return "Invalid API key.";
|
|
4687
|
+
return { ok: false, error: "Invalid API key." };
|
|
4549
4688
|
}
|
|
4550
4689
|
void debitCreditsAsync({
|
|
4551
4690
|
userId: result.userId,
|
|
4552
4691
|
keyId: result.keyId,
|
|
4553
4692
|
requestId: req.requestId
|
|
4554
4693
|
});
|
|
4555
|
-
return
|
|
4694
|
+
return {
|
|
4695
|
+
ok: true,
|
|
4696
|
+
userId: result.userId,
|
|
4697
|
+
keyId: result.keyId,
|
|
4698
|
+
keyMeta: result.meta
|
|
4699
|
+
};
|
|
4556
4700
|
}
|
|
4557
4701
|
const validKeys = (process.env.HIVE_API_KEYS || "").split(",").filter(Boolean);
|
|
4558
4702
|
if (validKeys.length === 0) {
|
|
4559
|
-
return
|
|
4703
|
+
return {
|
|
4704
|
+
ok: false,
|
|
4705
|
+
error: "API key authentication is not configured on this server."
|
|
4706
|
+
};
|
|
4560
4707
|
}
|
|
4561
4708
|
if (!key)
|
|
4562
|
-
return
|
|
4563
|
-
|
|
4564
|
-
|
|
4709
|
+
return {
|
|
4710
|
+
ok: false,
|
|
4711
|
+
error: "API key required. Set x-api-key header or Authorization: Bearer <key>."
|
|
4712
|
+
};
|
|
4713
|
+
if (!validKeys.includes(key)) return { ok: false, error: "Invalid API key." };
|
|
4714
|
+
return { ok: true };
|
|
4715
|
+
}
|
|
4716
|
+
var STATEFUL_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
4717
|
+
"hive_create_monitor",
|
|
4718
|
+
"hive_update_monitor",
|
|
4719
|
+
"hive_archive_monitor",
|
|
4720
|
+
"hive_update_alert_status",
|
|
4721
|
+
"hive_remember_fact",
|
|
4722
|
+
"hive_forget_memory_fact"
|
|
4723
|
+
]);
|
|
4724
|
+
function getMcpHiveToolName(body) {
|
|
4725
|
+
if (body?.method !== "tools/call") return void 0;
|
|
4726
|
+
const toolName = body.params?.name;
|
|
4727
|
+
const toolArgs = body.params?.arguments;
|
|
4728
|
+
if (!toolName || typeof toolName !== "string") return void 0;
|
|
4729
|
+
if (toolName === "invoke_api_endpoint") {
|
|
4730
|
+
const endpointName = typeof toolArgs?.endpoint_name === "string" ? toolArgs.endpoint_name : typeof toolArgs?.args?.endpoint_name === "string" ? toolArgs.args.endpoint_name : void 0;
|
|
4731
|
+
return endpointName?.startsWith("hive_") ? endpointName : void 0;
|
|
4732
|
+
}
|
|
4733
|
+
return toolName.startsWith("hive_") ? toolName : void 0;
|
|
4734
|
+
}
|
|
4735
|
+
function removeHiddenHiveAuthArgs(args) {
|
|
4736
|
+
if (!args || typeof args !== "object" || Array.isArray(args)) return;
|
|
4737
|
+
delete args[HIVE_AUTH_USER_ARG];
|
|
4738
|
+
delete args[HIVE_AUTH_SUBJECT_ARG];
|
|
4739
|
+
}
|
|
4740
|
+
function getRestHiveToolName(toolName, args) {
|
|
4741
|
+
if (toolName.startsWith("hive_")) return toolName;
|
|
4742
|
+
if (toolName !== "invoke_api_endpoint") return void 0;
|
|
4743
|
+
const endpointName = typeof args.endpoint_name === "string" ? args.endpoint_name : typeof args.args?.endpoint_name === "string" ? args.args.endpoint_name : void 0;
|
|
4744
|
+
return endpointName?.startsWith("hive_") ? endpointName : void 0;
|
|
4745
|
+
}
|
|
4746
|
+
function injectMcpAuthContext(body, context) {
|
|
4747
|
+
if (body?.method !== "tools/call") return;
|
|
4748
|
+
const toolName = body.params?.name;
|
|
4749
|
+
if (!toolName || typeof toolName !== "string") return;
|
|
4750
|
+
if (toolName !== "invoke_api_endpoint" && !toolName.startsWith("hive_")) {
|
|
4751
|
+
return;
|
|
4752
|
+
}
|
|
4753
|
+
if (!body.params.arguments || typeof body.params.arguments !== "object") {
|
|
4754
|
+
body.params.arguments = {};
|
|
4755
|
+
}
|
|
4756
|
+
const toolArgs = body.params.arguments;
|
|
4757
|
+
if (toolName === "invoke_api_endpoint") {
|
|
4758
|
+
removeHiddenHiveAuthArgs(toolArgs);
|
|
4759
|
+
removeHiddenHiveAuthArgs(toolArgs.args);
|
|
4760
|
+
const endpointName = typeof toolArgs.endpoint_name === "string" ? toolArgs.endpoint_name : typeof toolArgs.args?.endpoint_name === "string" ? toolArgs.args.endpoint_name : void 0;
|
|
4761
|
+
if (!endpointName?.startsWith("hive_") || !context) return;
|
|
4762
|
+
if (!toolArgs.args || typeof toolArgs.args !== "object") {
|
|
4763
|
+
toolArgs.args = {};
|
|
4764
|
+
}
|
|
4765
|
+
toolArgs.args[HIVE_AUTH_USER_ARG] = context.userId;
|
|
4766
|
+
toolArgs.args[HIVE_AUTH_SUBJECT_ARG] = context.subjectId;
|
|
4767
|
+
return;
|
|
4768
|
+
}
|
|
4769
|
+
removeHiddenHiveAuthArgs(toolArgs);
|
|
4770
|
+
if (typeof toolName === "string" && toolName.startsWith("hive_")) {
|
|
4771
|
+
if (!context) return;
|
|
4772
|
+
toolArgs[HIVE_AUTH_USER_ARG] = context.userId;
|
|
4773
|
+
toolArgs[HIVE_AUTH_SUBJECT_ARG] = context.subjectId;
|
|
4774
|
+
}
|
|
4565
4775
|
}
|
|
4566
4776
|
function getMcpAnalyticsTags(req) {
|
|
4567
4777
|
const body = req.body;
|
|
@@ -4582,11 +4792,11 @@ function getMcpAnalyticsTags(req) {
|
|
|
4582
4792
|
function createStatelessMcpHandler(scope) {
|
|
4583
4793
|
return async (req, res) => {
|
|
4584
4794
|
const sessionCorrelationId = req.requestId;
|
|
4585
|
-
const
|
|
4586
|
-
if (
|
|
4795
|
+
const auth = await validateMcpApiKey(req);
|
|
4796
|
+
if (!auth.ok) {
|
|
4587
4797
|
res.status(200).json({
|
|
4588
4798
|
jsonrpc: "2.0",
|
|
4589
|
-
error: { code: -32001, message:
|
|
4799
|
+
error: { code: -32001, message: auth.error },
|
|
4590
4800
|
id: req.body?.id ?? null
|
|
4591
4801
|
});
|
|
4592
4802
|
return;
|
|
@@ -4606,6 +4816,43 @@ function createStatelessMcpHandler(scope) {
|
|
|
4606
4816
|
}
|
|
4607
4817
|
}
|
|
4608
4818
|
}
|
|
4819
|
+
const hiveToolName = getMcpHiveToolName(body);
|
|
4820
|
+
let subjectContext;
|
|
4821
|
+
if (hiveToolName && auth.userId) {
|
|
4822
|
+
const subject = await resolveSubjectContext({
|
|
4823
|
+
userId: auth.userId,
|
|
4824
|
+
keyId: auth.keyId,
|
|
4825
|
+
keyMeta: auth.keyMeta,
|
|
4826
|
+
method: req.method,
|
|
4827
|
+
path: req.path,
|
|
4828
|
+
headers: req.headers,
|
|
4829
|
+
requiresSubjectHeaders: STATEFUL_WRITE_TOOLS.has(hiveToolName)
|
|
4830
|
+
});
|
|
4831
|
+
if (!subject.ok) {
|
|
4832
|
+
res.status(200).json({
|
|
4833
|
+
jsonrpc: "2.0",
|
|
4834
|
+
error: {
|
|
4835
|
+
code: -32002,
|
|
4836
|
+
message: subject.message,
|
|
4837
|
+
data: { code: subject.code }
|
|
4838
|
+
},
|
|
4839
|
+
id: body?.id ?? null
|
|
4840
|
+
});
|
|
4841
|
+
return;
|
|
4842
|
+
}
|
|
4843
|
+
subjectContext = subject.data;
|
|
4844
|
+
if (STATEFUL_WRITE_TOOLS.has(hiveToolName)) {
|
|
4845
|
+
recordSubjectAuditEvent({
|
|
4846
|
+
userId: subject.data.userId,
|
|
4847
|
+
subjectId: subject.data.subjectId,
|
|
4848
|
+
keyId: auth.keyId,
|
|
4849
|
+
transport: "mcp",
|
|
4850
|
+
toolName: hiveToolName,
|
|
4851
|
+
requestId: req.requestId
|
|
4852
|
+
});
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
injectMcpAuthContext(body, subjectContext);
|
|
4609
4856
|
const server = createHiveMcpServer(scope).getServer();
|
|
4610
4857
|
const transport = new StreamableHTTPServerTransport({
|
|
4611
4858
|
sessionIdGenerator: void 0,
|
|
@@ -4787,7 +5034,53 @@ app.post(
|
|
|
4787
5034
|
meta: { tool: toolName ?? null, duration_ms: 0 }
|
|
4788
5035
|
});
|
|
4789
5036
|
}
|
|
4790
|
-
const
|
|
5037
|
+
const endpointArgs = { ...args ?? {} };
|
|
5038
|
+
removeHiddenHiveAuthArgs(endpointArgs);
|
|
5039
|
+
removeHiddenHiveAuthArgs(endpointArgs.args);
|
|
5040
|
+
const authReq = req;
|
|
5041
|
+
const hiveToolName = getRestHiveToolName(toolName, endpointArgs);
|
|
5042
|
+
if (hiveToolName && authReq.userId) {
|
|
5043
|
+
const subject = await resolveSubjectContext({
|
|
5044
|
+
userId: authReq.userId,
|
|
5045
|
+
keyId: authReq.unkeyKeyId,
|
|
5046
|
+
keyMeta: authReq.unkeyResult?.meta,
|
|
5047
|
+
method: req.method,
|
|
5048
|
+
path: req.path,
|
|
5049
|
+
headers: req.headers,
|
|
5050
|
+
requiresSubjectHeaders: STATEFUL_WRITE_TOOLS.has(hiveToolName)
|
|
5051
|
+
});
|
|
5052
|
+
if (!subject.ok) {
|
|
5053
|
+
return res.status(subject.status).json(
|
|
5054
|
+
apiError(
|
|
5055
|
+
subject.status === 400 ? "invalid_request_error" : "authentication_error",
|
|
5056
|
+
subject.code,
|
|
5057
|
+
subject.message,
|
|
5058
|
+
{ requestId: req.requestId }
|
|
5059
|
+
)
|
|
5060
|
+
);
|
|
5061
|
+
}
|
|
5062
|
+
if (toolName === "invoke_api_endpoint") {
|
|
5063
|
+
if (!endpointArgs.args || typeof endpointArgs.args !== "object") {
|
|
5064
|
+
endpointArgs.args = {};
|
|
5065
|
+
}
|
|
5066
|
+
endpointArgs.args[HIVE_AUTH_USER_ARG] = subject.data.userId;
|
|
5067
|
+
endpointArgs.args[HIVE_AUTH_SUBJECT_ARG] = subject.data.subjectId;
|
|
5068
|
+
} else {
|
|
5069
|
+
endpointArgs[HIVE_AUTH_USER_ARG] = subject.data.userId;
|
|
5070
|
+
endpointArgs[HIVE_AUTH_SUBJECT_ARG] = subject.data.subjectId;
|
|
5071
|
+
}
|
|
5072
|
+
if (STATEFUL_WRITE_TOOLS.has(hiveToolName)) {
|
|
5073
|
+
recordSubjectAuditEvent({
|
|
5074
|
+
userId: subject.data.userId,
|
|
5075
|
+
subjectId: subject.data.subjectId,
|
|
5076
|
+
keyId: authReq.unkeyKeyId,
|
|
5077
|
+
transport: "rest",
|
|
5078
|
+
toolName: hiveToolName,
|
|
5079
|
+
requestId: req.requestId
|
|
5080
|
+
});
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5083
|
+
const result = await executeToolByName(toolName, endpointArgs);
|
|
4791
5084
|
const meta = {
|
|
4792
5085
|
tool: toolName,
|
|
4793
5086
|
duration_ms: result.durationMs,
|
|
@@ -5017,4 +5310,3 @@ export {
|
|
|
5017
5310
|
server_default as default,
|
|
5018
5311
|
startHttpServer
|
|
5019
5312
|
};
|
|
5020
|
-
//# sourceMappingURL=server.js.map
|