hive-intelligence 1.8.0 → 1.10.0
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/README.md +42 -10
- package/agent-skills/packs/hive/SKILL.md +10 -8
- package/agent-skills/packs/hive-mcp/SKILL.md +18 -10
- package/agent-skills/packs/hive-mcp/references/client-install-matrix.md +6 -4
- package/agent-skills/packs/hive-mcp/references/clients.md +6 -3
- package/agent-skills/packs/hive-token-diligence/SKILL.md +2 -0
- package/build/{chunk-L4KVJDA7.js → chunk-5IQUEFCD.js} +13 -6
- package/build/{chunk-ORJIFYF4.js → chunk-E2FAHUXM.js} +26 -1
- package/build/{chunk-HWV3XFXH.js → chunk-Z42XNN47.js} +1236 -239
- package/build/cli.js +23 -15
- package/build/config-audit-7GC42QX7.js +235 -0
- package/build/{doctor-5HAAZU4R.js → doctor-SMUVDZZ2.js} +61 -4
- package/build/{init-all-JXLG7LOX.js → init-all-SPEWION5.js} +9 -9
- package/build/{mcpServer-LNRRWXSV.js → mcpServer-T3DYYFCC.js} +1 -1
- package/build/monitor-worker.js +52 -6
- package/build/release.json +4 -4
- package/build/serve-2ICWEUMC.js +126 -0
- package/build/server.js +129 -13
- package/build/stdio.js +1 -1
- package/build/{tools-NJQPIJ53.js → tools-J6VPDGYP.js} +7 -3
- package/build/{upgrade-3NR3LAGU.js → upgrade-BJADUTO6.js} +1 -1
- package/package.json +12 -12
- package/build/serve-MOP4WYH6.js +0 -49
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
|
|
2
|
+
import "./chunk-OMO7XLC5.js";
|
|
3
|
+
|
|
4
|
+
// src/cli/serve.ts
|
|
5
|
+
import dotenv from "dotenv";
|
|
6
|
+
function resolveStdioMode(opts = {}, env = process.env) {
|
|
7
|
+
return opts.local || env.HIVE_STDIO_MODE?.toLowerCase() === "local" ? "local" : "proxy";
|
|
8
|
+
}
|
|
9
|
+
function updateNotice(pending, running) {
|
|
10
|
+
return pending ? `A newer Hive version (${pending}) is available; this server is running ${running}. Tell the user to run "hive upgrade" and restart this client to get the latest tools and data.` : void 0;
|
|
11
|
+
}
|
|
12
|
+
function bridgeTransports(local, remote, opts) {
|
|
13
|
+
local.onmessage = (message) => {
|
|
14
|
+
remote.send(message).catch((err) => {
|
|
15
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
16
|
+
const hint = /\b401\b|unauthori[sz]ed/i.test(reason) ? ` Run "hive auth login" or set HIVE_API_KEY in this server's env.` : "";
|
|
17
|
+
process.stderr.write(`Hive proxy: ${reason}
|
|
18
|
+
`);
|
|
19
|
+
if ("method" in message && "id" in message) {
|
|
20
|
+
void local.send({
|
|
21
|
+
jsonrpc: "2.0",
|
|
22
|
+
id: message.id,
|
|
23
|
+
error: {
|
|
24
|
+
code: -32603,
|
|
25
|
+
message: `Hive could not reach ${opts.remoteUrl}: ${reason}.${hint}`
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
remote.onmessage = (message) => {
|
|
32
|
+
const result = "result" in message ? message.result : void 0;
|
|
33
|
+
if (typeof result?.protocolVersion === "string") {
|
|
34
|
+
remote.setProtocolVersion?.(result.protocolVersion);
|
|
35
|
+
const notice = opts.notice?.();
|
|
36
|
+
if (notice && "result" in message) {
|
|
37
|
+
const instructions = [result.instructions, notice].filter((part) => typeof part === "string" && part).join("\n\n");
|
|
38
|
+
message = { ...message, result: { ...message.result, instructions } };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
void local.send(message);
|
|
42
|
+
};
|
|
43
|
+
remote.onerror = (err) => process.stderr.write(`Hive proxy: ${err.message}
|
|
44
|
+
`);
|
|
45
|
+
local.onclose = () => void remote.close();
|
|
46
|
+
}
|
|
47
|
+
async function startStdio(envFile, opts = {}) {
|
|
48
|
+
dotenv.config({ path: envFile || ".env", quiet: true });
|
|
49
|
+
console.log = (...args) => console.error("[LOG]", ...args);
|
|
50
|
+
if (resolveStdioMode(opts) === "proxy") return startStdioProxy();
|
|
51
|
+
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
52
|
+
const { createHiveMcpServer, SERVER_NAME, SERVER_VERSION } = await import("./mcpServer-T3DYYFCC.js");
|
|
53
|
+
const { getPendingUpdateVersion } = await import("./update-check-36QU6PKA.js");
|
|
54
|
+
const transport = new StdioServerTransport();
|
|
55
|
+
const pendingUpdate = getPendingUpdateVersion();
|
|
56
|
+
const instructionsSuffix = updateNotice(pendingUpdate, SERVER_VERSION);
|
|
57
|
+
const mcpServer = createHiveMcpServer(
|
|
58
|
+
{ kind: "root" },
|
|
59
|
+
{ instructionsSuffix }
|
|
60
|
+
);
|
|
61
|
+
const server = mcpServer.getServer();
|
|
62
|
+
let isShuttingDown = false;
|
|
63
|
+
const shutdown = async () => {
|
|
64
|
+
if (isShuttingDown) return;
|
|
65
|
+
isShuttingDown = true;
|
|
66
|
+
const forceTimer = setTimeout(() => process.exit(1), 3e3);
|
|
67
|
+
forceTimer.unref();
|
|
68
|
+
try {
|
|
69
|
+
await server.close();
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
process.exit(0);
|
|
73
|
+
};
|
|
74
|
+
process.on("SIGINT", shutdown);
|
|
75
|
+
process.on("SIGTERM", shutdown);
|
|
76
|
+
process.stdin.on("end", shutdown);
|
|
77
|
+
await server.connect(transport);
|
|
78
|
+
console.error(
|
|
79
|
+
`Hive MCP stdio server connected (${SERVER_NAME} v${SERVER_VERSION}, local providers)`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
async function startStdioProxy() {
|
|
83
|
+
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
84
|
+
const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
85
|
+
const { resolveApiKey, resolveApiUrl } = await import("./config-dir-2QLA5PXD.js");
|
|
86
|
+
const { getPendingUpdateVersion } = await import("./update-check-36QU6PKA.js");
|
|
87
|
+
const { SERVER_VERSION } = await import("./version-ITRM4X2U.js");
|
|
88
|
+
const remoteUrl = `${resolveApiUrl().replace(/\/+$/, "")}/mcp`;
|
|
89
|
+
const apiKey = resolveApiKey();
|
|
90
|
+
const remote = new StreamableHTTPClientTransport(new URL(remoteUrl), {
|
|
91
|
+
requestInit: {
|
|
92
|
+
headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const local = new StdioServerTransport();
|
|
96
|
+
bridgeTransports(local, remote, {
|
|
97
|
+
remoteUrl,
|
|
98
|
+
notice: () => updateNotice(getPendingUpdateVersion(), SERVER_VERSION)
|
|
99
|
+
});
|
|
100
|
+
if (Object.keys(process.env).some(
|
|
101
|
+
(k) => /^(COINGECKO|ALCHEMY|GOPLUS|HELIUS|MORALIS|TENDERLY)_/.test(k)
|
|
102
|
+
)) {
|
|
103
|
+
console.error(
|
|
104
|
+
"Hive: provider keys found in env but ignored; hosted Hive serves every provider. Set HIVE_STDIO_MODE=local to run providers with your own keys."
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
process.stdin.on("end", () => process.exit(0));
|
|
108
|
+
await remote.start();
|
|
109
|
+
await local.start();
|
|
110
|
+
console.error(
|
|
111
|
+
`Hive MCP stdio proxy v${SERVER_VERSION} -> ${remoteUrl} (${apiKey ? "API key" : 'keyless: discovery + free hero calls; run "hive auth login" for the full catalog'}). Self-host with your own provider keys: hive serve --local`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
async function startHttp(port, envFile) {
|
|
115
|
+
dotenv.config({ path: envFile || ".env", quiet: true });
|
|
116
|
+
process.env.PORT = String(port);
|
|
117
|
+
const { startHttpServer } = await import("./server.js");
|
|
118
|
+
await startHttpServer();
|
|
119
|
+
}
|
|
120
|
+
export {
|
|
121
|
+
bridgeTransports,
|
|
122
|
+
resolveStdioMode,
|
|
123
|
+
startHttp,
|
|
124
|
+
startStdio,
|
|
125
|
+
updateNotice
|
|
126
|
+
};
|
package/build/server.js
CHANGED
|
@@ -5,8 +5,10 @@ import {
|
|
|
5
5
|
consumeCredits,
|
|
6
6
|
ensureWallet,
|
|
7
7
|
executeToolByName,
|
|
8
|
-
getWalletStatus
|
|
9
|
-
|
|
8
|
+
getWalletStatus,
|
|
9
|
+
refundCredits,
|
|
10
|
+
refundSettled
|
|
11
|
+
} from "./chunk-E2FAHUXM.js";
|
|
10
12
|
import {
|
|
11
13
|
CategoryEndpoints,
|
|
12
14
|
HERO_TOOL_NAMES,
|
|
@@ -102,7 +104,7 @@ import {
|
|
|
102
104
|
validateEndpointArgs,
|
|
103
105
|
verifyApiKey,
|
|
104
106
|
waitForRedisAvailability
|
|
105
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-Z42XNN47.js";
|
|
106
108
|
import {
|
|
107
109
|
HIVE_AGENT_SKILLS
|
|
108
110
|
} from "./chunk-4QDGA6GP.js";
|
|
@@ -2598,10 +2600,11 @@ async function debitApiKeyCreditForExecution(req, res) {
|
|
|
2598
2600
|
const result = authReq.unkeyResult;
|
|
2599
2601
|
if (!result || !authReq.userId) return;
|
|
2600
2602
|
try {
|
|
2603
|
+
const idempotencyKey = authReq.creditDebitIdempotencyKey ?? randomUUID();
|
|
2601
2604
|
const consumeResult = await consumeCredits({
|
|
2602
2605
|
userId: authReq.userId,
|
|
2603
2606
|
cost: REQUEST_COST,
|
|
2604
|
-
idempotencyKey
|
|
2607
|
+
idempotencyKey,
|
|
2605
2608
|
requestId: req.requestId,
|
|
2606
2609
|
keyId: authReq.unkeyKeyId
|
|
2607
2610
|
});
|
|
@@ -2627,6 +2630,7 @@ async function debitApiKeyCreditForExecution(req, res) {
|
|
|
2627
2630
|
};
|
|
2628
2631
|
}
|
|
2629
2632
|
authReq.quotaRemaining = consumeResult.balance ?? void 0;
|
|
2633
|
+
authReq.creditDebitedKey = idempotencyKey;
|
|
2630
2634
|
authReq.idempotencyExecutionStarted = true;
|
|
2631
2635
|
res.setHeader(
|
|
2632
2636
|
"X-Quota-Remaining",
|
|
@@ -5556,6 +5560,23 @@ async function consumeAnonMaterialQuota(ipHash, overrides = {}) {
|
|
|
5556
5560
|
return { allowed: false, reason: "unavailable" };
|
|
5557
5561
|
}
|
|
5558
5562
|
}
|
|
5563
|
+
async function refundAnonMaterialQuota(ipHash) {
|
|
5564
|
+
try {
|
|
5565
|
+
if (!isSupabaseConfigured()) return void 0;
|
|
5566
|
+
const { data, error } = await getSupabaseAdmin().rpc(
|
|
5567
|
+
"refund_anon_daily_quota",
|
|
5568
|
+
{ p_ip_hash: ipHash, p_ip_limit: getAnonDailyMaterialCap() }
|
|
5569
|
+
);
|
|
5570
|
+
if (error) throw new Error(error.message);
|
|
5571
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
5572
|
+
return typeof row?.remaining === "number" ? row.remaining : void 0;
|
|
5573
|
+
} catch (err) {
|
|
5574
|
+
secureLogger.warn("Anonymous quota refund failed", {
|
|
5575
|
+
error: err instanceof Error ? err.message : String(err)
|
|
5576
|
+
});
|
|
5577
|
+
return void 0;
|
|
5578
|
+
}
|
|
5579
|
+
}
|
|
5559
5580
|
|
|
5560
5581
|
// src/serverCard.ts
|
|
5561
5582
|
function buildServerCard() {
|
|
@@ -6925,10 +6946,11 @@ function buildMcpQuotaExhaustedCopy(args) {
|
|
|
6925
6946
|
}
|
|
6926
6947
|
async function debitMcpCredits(args) {
|
|
6927
6948
|
try {
|
|
6949
|
+
const idempotencyKey = randomUUID4();
|
|
6928
6950
|
const debit = await consumeCredits({
|
|
6929
6951
|
userId: args.userId,
|
|
6930
6952
|
cost: 1,
|
|
6931
|
-
idempotencyKey
|
|
6953
|
+
idempotencyKey,
|
|
6932
6954
|
requestId: args.requestId,
|
|
6933
6955
|
keyId: args.keyId
|
|
6934
6956
|
});
|
|
@@ -6952,7 +6974,7 @@ async function debitMcpCredits(args) {
|
|
|
6952
6974
|
rateLimited: true
|
|
6953
6975
|
};
|
|
6954
6976
|
}
|
|
6955
|
-
return { ok: true, balance: debit.balance };
|
|
6977
|
+
return { ok: true, balance: debit.balance, idempotencyKey };
|
|
6956
6978
|
} catch (err) {
|
|
6957
6979
|
secureLogger.warn("MCP consume_credits debit failed", {
|
|
6958
6980
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -6963,6 +6985,32 @@ async function debitMcpCredits(args) {
|
|
|
6963
6985
|
};
|
|
6964
6986
|
}
|
|
6965
6987
|
}
|
|
6988
|
+
async function refundKeyedCredit(res, args) {
|
|
6989
|
+
const refund = await refundCredits({
|
|
6990
|
+
userId: args.userId,
|
|
6991
|
+
debitIdempotencyKey: args.debitIdempotencyKey,
|
|
6992
|
+
detail: {
|
|
6993
|
+
tool: args.toolName,
|
|
6994
|
+
runtime_status: args.runtimeStatus,
|
|
6995
|
+
transport: args.transport
|
|
6996
|
+
}
|
|
6997
|
+
});
|
|
6998
|
+
if (!refundSettled(refund.code)) return { refunded: false };
|
|
6999
|
+
if (!res.headersSent) {
|
|
7000
|
+
res.setHeader(
|
|
7001
|
+
"X-Quota-Remaining",
|
|
7002
|
+
refund.balance === null ? "unlimited" : String(refund.balance)
|
|
7003
|
+
);
|
|
7004
|
+
}
|
|
7005
|
+
return { refunded: true, creditsRemaining: refund.balance };
|
|
7006
|
+
}
|
|
7007
|
+
async function refundAnonCall(res, ipHash) {
|
|
7008
|
+
const remaining = await refundAnonMaterialQuota(ipHash);
|
|
7009
|
+
if (remaining !== void 0 && !res.headersSent) {
|
|
7010
|
+
res.setHeader("X-Quota-Remaining", String(remaining));
|
|
7011
|
+
}
|
|
7012
|
+
return remaining;
|
|
7013
|
+
}
|
|
6966
7014
|
function extractApiKey(req) {
|
|
6967
7015
|
return req.headers["x-api-key"] ?? (req.headers.authorization?.startsWith("Bearer ") ? req.headers.authorization.slice(7) : void 0);
|
|
6968
7016
|
}
|
|
@@ -7412,10 +7460,10 @@ function createStatelessMcpHandler(scope) {
|
|
|
7412
7460
|
if (!auth.ok && !mcpCredentialPresented(req)) {
|
|
7413
7461
|
const decision = await authorizeAnonymousMcpRequest(req);
|
|
7414
7462
|
if (decision.kind === "allow") {
|
|
7463
|
+
const ipHash = anonymousIpHash(ipRateLimitKeyFromRequest(req));
|
|
7415
7464
|
anonymousLane = {
|
|
7416
|
-
principalRaw: `anon:${
|
|
7417
|
-
|
|
7418
|
-
)}`,
|
|
7465
|
+
principalRaw: `anon:${ipHash}`,
|
|
7466
|
+
ipHash,
|
|
7419
7467
|
materialGranted: decision.materialGranted,
|
|
7420
7468
|
quotaRemaining: decision.quotaRemaining
|
|
7421
7469
|
};
|
|
@@ -7641,6 +7689,8 @@ function createStatelessMcpHandler(scope) {
|
|
|
7641
7689
|
clientName: resolveMcpClientName(req, body),
|
|
7642
7690
|
isInternal: isMonitorSecretRequest(req)
|
|
7643
7691
|
};
|
|
7692
|
+
let anonCallHeld = anonymousLane?.materialGranted === true;
|
|
7693
|
+
let anonCallBilled = false;
|
|
7644
7694
|
const server = createHiveMcpServer(scope, {
|
|
7645
7695
|
requestId: req.requestId,
|
|
7646
7696
|
analytics,
|
|
@@ -7698,6 +7748,7 @@ function createStatelessMcpHandler(scope) {
|
|
|
7698
7748
|
beforeToolExecution: keyedAuth?.userId ? async (executedToolName) => {
|
|
7699
7749
|
const creditCost = getMcpCreditCost(executedToolName);
|
|
7700
7750
|
let keyedBalance;
|
|
7751
|
+
let debitKey;
|
|
7701
7752
|
res.setHeader("X-Hive-Credit-Cost", String(creditCost));
|
|
7702
7753
|
if (creditCost > 0) {
|
|
7703
7754
|
const debit = await debitMcpCredits({
|
|
@@ -7741,10 +7792,22 @@ function createStatelessMcpHandler(scope) {
|
|
|
7741
7792
|
debit.balance === null ? "unlimited" : String(debit.balance)
|
|
7742
7793
|
);
|
|
7743
7794
|
keyedBalance = debit.balance;
|
|
7795
|
+
debitKey = debit.idempotencyKey;
|
|
7744
7796
|
}
|
|
7797
|
+
const refund = debitKey ? (reason) => refundKeyedCredit(res, {
|
|
7798
|
+
userId: keyedAuth.userId,
|
|
7799
|
+
debitIdempotencyKey: debitKey,
|
|
7800
|
+
toolName: reason.toolName,
|
|
7801
|
+
runtimeStatus: reason.runtimeStatus,
|
|
7802
|
+
transport: "mcp"
|
|
7803
|
+
}) : void 0;
|
|
7745
7804
|
if (subjectContext) {
|
|
7746
7805
|
const materialized = await materializeSubjectContext(subjectContext);
|
|
7747
7806
|
if (!materialized.ok) {
|
|
7807
|
+
await refund?.({
|
|
7808
|
+
toolName: executedToolName,
|
|
7809
|
+
runtimeStatus: "failing"
|
|
7810
|
+
}).catch(() => void 0);
|
|
7748
7811
|
return {
|
|
7749
7812
|
type: materialized.status === 403 ? "authentication_error" : "internal_error",
|
|
7750
7813
|
code: materialized.code,
|
|
@@ -7768,7 +7831,8 @@ function createStatelessMcpHandler(scope) {
|
|
|
7768
7831
|
return {
|
|
7769
7832
|
type: "billing",
|
|
7770
7833
|
credits_used: creditCost,
|
|
7771
|
-
...creditCost > 0 && { credits_remaining: keyedBalance }
|
|
7834
|
+
...creditCost > 0 && { credits_remaining: keyedBalance },
|
|
7835
|
+
...refund && { refund }
|
|
7772
7836
|
};
|
|
7773
7837
|
} : anonymousLane ? async (executedToolName) => {
|
|
7774
7838
|
const creditCost = getMcpCreditCost(executedToolName);
|
|
@@ -7790,10 +7854,36 @@ function createStatelessMcpHandler(scope) {
|
|
|
7790
7854
|
runtimeStatus: "failing"
|
|
7791
7855
|
};
|
|
7792
7856
|
}
|
|
7857
|
+
if (!anonCallHeld) {
|
|
7858
|
+
const quota = await consumeAnonMaterialQuota(
|
|
7859
|
+
anonymousLane.ipHash
|
|
7860
|
+
);
|
|
7861
|
+
if (!quota.allowed) {
|
|
7862
|
+
return {
|
|
7863
|
+
type: "rate_limit_error",
|
|
7864
|
+
code: "ANON_QUOTA_EXCEEDED",
|
|
7865
|
+
message: ANON_QUOTA_EXHAUSTED_MESSAGE,
|
|
7866
|
+
runtimeStatus: "rate_limited"
|
|
7867
|
+
};
|
|
7868
|
+
}
|
|
7869
|
+
anonCallHeld = true;
|
|
7870
|
+
anonymousLane.quotaRemaining = quota.remaining;
|
|
7871
|
+
}
|
|
7872
|
+
anonCallBilled = true;
|
|
7793
7873
|
return {
|
|
7794
7874
|
type: "billing",
|
|
7795
7875
|
credits_used: creditCost,
|
|
7796
|
-
credits_remaining: anonymousLane.quotaRemaining ?? null
|
|
7876
|
+
credits_remaining: anonymousLane.quotaRemaining ?? null,
|
|
7877
|
+
refund: async () => {
|
|
7878
|
+
const remaining = await refundAnonCall(
|
|
7879
|
+
res,
|
|
7880
|
+
anonymousLane.ipHash
|
|
7881
|
+
);
|
|
7882
|
+
if (remaining === void 0) return { refunded: false };
|
|
7883
|
+
anonCallHeld = false;
|
|
7884
|
+
anonymousLane.quotaRemaining = remaining;
|
|
7885
|
+
return { refunded: true, creditsRemaining: remaining };
|
|
7886
|
+
}
|
|
7797
7887
|
};
|
|
7798
7888
|
} : void 0
|
|
7799
7889
|
}).getServer();
|
|
@@ -7820,6 +7910,10 @@ function createStatelessMcpHandler(scope) {
|
|
|
7820
7910
|
() => transport.handleRequest(req, res, body)
|
|
7821
7911
|
)
|
|
7822
7912
|
);
|
|
7913
|
+
if (anonymousLane && anonCallHeld && !anonCallBilled) {
|
|
7914
|
+
anonCallHeld = false;
|
|
7915
|
+
await refundAnonCall(res, anonymousLane.ipHash);
|
|
7916
|
+
}
|
|
7823
7917
|
secureLogger.debug("MCP request completed", {
|
|
7824
7918
|
sessionId: sessionCorrelationId,
|
|
7825
7919
|
scope: scope.kind === "root" ? "root" : `category:${scope.category}`
|
|
@@ -8341,6 +8435,7 @@ var anonymousHeroExecuteMiddleware = asyncHandler(
|
|
|
8341
8435
|
return;
|
|
8342
8436
|
}
|
|
8343
8437
|
res.setHeader("X-Quota-Remaining", String(quota.remaining));
|
|
8438
|
+
let refundAttempted = false;
|
|
8344
8439
|
const result = await executeEndpoint(heroEndpoint, body?.args ?? {}, {
|
|
8345
8440
|
transport: "rest",
|
|
8346
8441
|
requestId: req.requestId,
|
|
@@ -8349,7 +8444,12 @@ var anonymousHeroExecuteMiddleware = asyncHandler(
|
|
|
8349
8444
|
beforeExecution: async () => ({
|
|
8350
8445
|
type: "billing",
|
|
8351
8446
|
credits_used: getMcpCreditCost(toolName),
|
|
8352
|
-
credits_remaining: quota.remaining
|
|
8447
|
+
credits_remaining: quota.remaining,
|
|
8448
|
+
refund: async () => {
|
|
8449
|
+
refundAttempted = true;
|
|
8450
|
+
const remaining = await refundAnonCall(res, ipHash);
|
|
8451
|
+
return remaining === void 0 ? { refunded: false } : { refunded: true, creditsRemaining: remaining };
|
|
8452
|
+
}
|
|
8353
8453
|
}),
|
|
8354
8454
|
analytics: {
|
|
8355
8455
|
principalRaw: `anon:${ipHash}`,
|
|
@@ -8358,6 +8458,9 @@ var anonymousHeroExecuteMiddleware = asyncHandler(
|
|
|
8358
8458
|
isInternal: isMonitorSecretRequest(req)
|
|
8359
8459
|
}
|
|
8360
8460
|
});
|
|
8461
|
+
if (!result.ok && !refundAttempted) {
|
|
8462
|
+
await refundAnonCall(res, ipHash);
|
|
8463
|
+
}
|
|
8361
8464
|
const meta = buildRestExecutionMeta(
|
|
8362
8465
|
toolName,
|
|
8363
8466
|
result.durationMs,
|
|
@@ -8413,6 +8516,14 @@ app.post(
|
|
|
8413
8516
|
const endpointArgs = authReq.resolvedRestToolArgs ?? { ...args ?? {} };
|
|
8414
8517
|
const keyedBeforeExecution = async (endpoint) => {
|
|
8415
8518
|
const blocked = await debitApiKeyCreditForExecution(req, res);
|
|
8519
|
+
const debitKey = authReq.creditDebitedKey;
|
|
8520
|
+
const refund = debitKey && authReq.userId ? (reason) => refundKeyedCredit(res, {
|
|
8521
|
+
userId: authReq.userId,
|
|
8522
|
+
debitIdempotencyKey: debitKey,
|
|
8523
|
+
toolName: reason.toolName,
|
|
8524
|
+
runtimeStatus: reason.runtimeStatus,
|
|
8525
|
+
transport: "rest"
|
|
8526
|
+
}) : void 0;
|
|
8416
8527
|
if (blocked) {
|
|
8417
8528
|
if (blocked.code === "QUOTA_EXCEEDED") {
|
|
8418
8529
|
recordPaywall(req, {
|
|
@@ -8431,6 +8542,10 @@ app.post(
|
|
|
8431
8542
|
authReq.hiveSubjectContext
|
|
8432
8543
|
);
|
|
8433
8544
|
if (!materialized.ok) {
|
|
8545
|
+
await refund?.({
|
|
8546
|
+
toolName: endpoint.tool.name,
|
|
8547
|
+
runtimeStatus: "failing"
|
|
8548
|
+
}).catch(() => void 0);
|
|
8434
8549
|
return {
|
|
8435
8550
|
type: materialized.status === 403 ? "authentication_error" : "internal_error",
|
|
8436
8551
|
code: materialized.code,
|
|
@@ -8458,7 +8573,8 @@ app.post(
|
|
|
8458
8573
|
credits_used: creditCost,
|
|
8459
8574
|
...creditCost > 0 && remainingHeader !== void 0 && {
|
|
8460
8575
|
credits_remaining: String(remainingHeader) === "unlimited" ? null : Number(remainingHeader)
|
|
8461
|
-
}
|
|
8576
|
+
},
|
|
8577
|
+
...refund && { refund }
|
|
8462
8578
|
};
|
|
8463
8579
|
};
|
|
8464
8580
|
const heroEndpoint = HERO_TOOL_NAMES.has(executionToolName) ? getRestHeroEndpoint(executionToolName) : void 0;
|
package/build/stdio.js
CHANGED
|
@@ -92,9 +92,13 @@ Showing ${rangeStart}-${rangeEnd} of ${totalFiltered} tools
|
|
|
92
92
|
async function searchTools(query) {
|
|
93
93
|
const allTools = await loadToolCatalog();
|
|
94
94
|
const q = query.toLowerCase();
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
const score = (t) => {
|
|
96
|
+
const desc = (t.description ?? "").split(/not recommended for:|don't use when:|common mistakes:/i)[0].toLowerCase();
|
|
97
|
+
if (t.name.toLowerCase().includes(q)) return 3;
|
|
98
|
+
if ((t.title ?? "").toLowerCase().includes(q)) return 2;
|
|
99
|
+
return desc.includes(q) ? 1 : 0;
|
|
100
|
+
};
|
|
101
|
+
const matches = allTools.map((t) => ({ t, s: score(t) })).filter(({ s }) => s > 0).sort((a, b) => b.s - a.s).map(({ t }) => t);
|
|
98
102
|
const items = matches.map((t) => ({
|
|
99
103
|
name: t.name,
|
|
100
104
|
title: t.title,
|
|
@@ -2,7 +2,7 @@ import { createRequire } from 'node:module'; const require = createRequire(impor
|
|
|
2
2
|
import {
|
|
3
3
|
detectInstallMode,
|
|
4
4
|
runUpgrade
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-5IQUEFCD.js";
|
|
6
6
|
import "./chunk-M6REON2I.js";
|
|
7
7
|
import "./chunk-ZXKFJQDE.js";
|
|
8
8
|
import "./chunk-ZDXMZPC6.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hive-intelligence",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Evidence-backed crypto due diligence for AI agents, with sources, freshness, and a runtime receipt on every call.",
|
|
5
5
|
"mcpName": "xyz.hiveintelligence/mcp",
|
|
6
6
|
"type": "module",
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"dependencies": {
|
|
132
132
|
"@cloudflare/cabidela": "^0.2.4",
|
|
133
133
|
"@coingecko/coingecko-typescript": "^8.0.0",
|
|
134
|
-
"@modelcontextprotocol/sdk": "1.
|
|
134
|
+
"@modelcontextprotocol/sdk": "1.32.1",
|
|
135
135
|
"@supabase/supabase-js": "^2.115.0",
|
|
136
136
|
"@types/compression": "^1.8.1",
|
|
137
137
|
"@unkey/api": "2.5.0",
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
"axios": "^1.20.0",
|
|
141
141
|
"ccxt": "^4.5.77",
|
|
142
142
|
"commander": "^15.0.0",
|
|
143
|
-
"compression": "^1.8.
|
|
143
|
+
"compression": "^1.8.2",
|
|
144
144
|
"cors": "2.8.6",
|
|
145
145
|
"dotenv": "17.4.2",
|
|
146
146
|
"express": "^5.2.1",
|
|
@@ -159,25 +159,25 @@
|
|
|
159
159
|
"github-actionlint": {
|
|
160
160
|
"adm-zip": "0.6.1"
|
|
161
161
|
},
|
|
162
|
-
"@modelcontextprotocol/sdk": {
|
|
163
|
-
"express-rate-limit": "8.5.2"
|
|
164
|
-
},
|
|
165
162
|
"esbuild": "0.28.1",
|
|
166
|
-
"fast-uri": "3.1.
|
|
167
|
-
"hono": "4.
|
|
168
|
-
"ip-address": "10.
|
|
169
|
-
"qs": "6.16.0"
|
|
163
|
+
"fast-uri": "3.1.8",
|
|
164
|
+
"hono": "4.13.13",
|
|
165
|
+
"ip-address": "10.7.3",
|
|
166
|
+
"qs": "6.16.0",
|
|
167
|
+
"proxy-addr": "2.0.8",
|
|
168
|
+
"undici": "7.29.1",
|
|
169
|
+
"source-map-js": "1.2.2"
|
|
170
170
|
},
|
|
171
171
|
"devDependencies": {
|
|
172
172
|
"@types/cors": "^2.8.19",
|
|
173
173
|
"@types/express": "^5.0.6",
|
|
174
174
|
"@types/node": "^24.13.3",
|
|
175
|
-
"@vitest/coverage-v8": "4.1.
|
|
175
|
+
"@vitest/coverage-v8": "4.1.11",
|
|
176
176
|
"cross-env": "10.1.0",
|
|
177
177
|
"github-actionlint": "1.7.12",
|
|
178
178
|
"tsup": "8.5.1",
|
|
179
179
|
"typescript": "^7.0.2",
|
|
180
|
-
"vitest": "^4.1.
|
|
180
|
+
"vitest": "^4.1.11"
|
|
181
181
|
},
|
|
182
182
|
"bin": {
|
|
183
183
|
"hive": "bin/hive-mcp.js",
|
package/build/serve-MOP4WYH6.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
|
|
2
|
-
import "./chunk-OMO7XLC5.js";
|
|
3
|
-
|
|
4
|
-
// src/cli/serve.ts
|
|
5
|
-
import dotenv from "dotenv";
|
|
6
|
-
async function startStdio(envFile) {
|
|
7
|
-
dotenv.config({ path: envFile || ".env", quiet: true });
|
|
8
|
-
console.log = (...args) => console.error("[LOG]", ...args);
|
|
9
|
-
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
10
|
-
const { createHiveMcpServer, SERVER_NAME, SERVER_VERSION } = await import("./mcpServer-LNRRWXSV.js");
|
|
11
|
-
const { getPendingUpdateVersion } = await import("./update-check-36QU6PKA.js");
|
|
12
|
-
const transport = new StdioServerTransport();
|
|
13
|
-
const pendingUpdate = getPendingUpdateVersion();
|
|
14
|
-
const instructionsSuffix = pendingUpdate ? `A newer Hive version (${pendingUpdate}) is available; this server is running ${SERVER_VERSION}. Tell the user to run "hive upgrade" and restart this client to get the latest tools and data.` : void 0;
|
|
15
|
-
const mcpServer = createHiveMcpServer(
|
|
16
|
-
{ kind: "root" },
|
|
17
|
-
{ instructionsSuffix }
|
|
18
|
-
);
|
|
19
|
-
const server = mcpServer.getServer();
|
|
20
|
-
let isShuttingDown = false;
|
|
21
|
-
const shutdown = async () => {
|
|
22
|
-
if (isShuttingDown) return;
|
|
23
|
-
isShuttingDown = true;
|
|
24
|
-
const forceTimer = setTimeout(() => process.exit(1), 3e3);
|
|
25
|
-
forceTimer.unref();
|
|
26
|
-
try {
|
|
27
|
-
await server.close();
|
|
28
|
-
} catch {
|
|
29
|
-
}
|
|
30
|
-
process.exit(0);
|
|
31
|
-
};
|
|
32
|
-
process.on("SIGINT", shutdown);
|
|
33
|
-
process.on("SIGTERM", shutdown);
|
|
34
|
-
process.stdin.on("end", shutdown);
|
|
35
|
-
await server.connect(transport);
|
|
36
|
-
console.error(
|
|
37
|
-
`Hive MCP stdio server connected (${SERVER_NAME} v${SERVER_VERSION})`
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
async function startHttp(port, envFile) {
|
|
41
|
-
dotenv.config({ path: envFile || ".env", quiet: true });
|
|
42
|
-
process.env.PORT = String(port);
|
|
43
|
-
const { startHttpServer } = await import("./server.js");
|
|
44
|
-
await startHttpServer();
|
|
45
|
-
}
|
|
46
|
-
export {
|
|
47
|
-
startHttp,
|
|
48
|
-
startStdio
|
|
49
|
-
};
|