@finchagentic/mcp 4.6.1 → 4.6.2

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.
Files changed (58) hide show
  1. package/package.json +5 -6
  2. package/dist/_http-cache.js +0 -96
  3. package/dist/_text-search.js +0 -39
  4. package/dist/agent-loop.js +0 -301
  5. package/dist/annotations.js +0 -122
  6. package/dist/cli.js +0 -1391
  7. package/dist/clink-input.js +0 -15
  8. package/dist/config.js +0 -132
  9. package/dist/convex.js +0 -175
  10. package/dist/dex-pair.js +0 -54
  11. package/dist/enrichment-router.js +0 -315
  12. package/dist/index.js +0 -258
  13. package/dist/llm.js +0 -298
  14. package/dist/local-memory-file.js +0 -150
  15. package/dist/local-memory.js +0 -135
  16. package/dist/local-vault.js +0 -456
  17. package/dist/output-schemas.js +0 -605
  18. package/dist/project.js +0 -36
  19. package/dist/prompts.js +0 -111
  20. package/dist/public-url.js +0 -107
  21. package/dist/resources.js +0 -111
  22. package/dist/server.js +0 -322
  23. package/dist/signal-gate.js +0 -57
  24. package/dist/token-decimals.js +0 -26
  25. package/dist/token-gate.js +0 -88
  26. package/dist/tool-filter.js +0 -53
  27. package/dist/tools/_solidity-scan.js +0 -313
  28. package/dist/tools/agents.js +0 -441
  29. package/dist/tools/automation.js +0 -354
  30. package/dist/tools/base-mcp.js +0 -466
  31. package/dist/tools/base.js +0 -283
  32. package/dist/tools/chronicle.js +0 -268
  33. package/dist/tools/coder.js +0 -94
  34. package/dist/tools/deep-research.js +0 -1421
  35. package/dist/tools/defi.js +0 -292
  36. package/dist/tools/equity.js +0 -372
  37. package/dist/tools/events.js +0 -182
  38. package/dist/tools/github.js +0 -564
  39. package/dist/tools/insider.js +0 -264
  40. package/dist/tools/insight.js +0 -630
  41. package/dist/tools/market.js +0 -555
  42. package/dist/tools/memory.js +0 -1059
  43. package/dist/tools/miroshark.js +0 -350
  44. package/dist/tools/monitor.js +0 -319
  45. package/dist/tools/os.js +0 -236
  46. package/dist/tools/packets.js +0 -296
  47. package/dist/tools/research-chain.js +0 -226
  48. package/dist/tools/research-compare.js +0 -280
  49. package/dist/tools/research.js +0 -188
  50. package/dist/tools/rh-bridge.js +0 -148
  51. package/dist/tools/rh-mcp.js +0 -1448
  52. package/dist/tools/rh-orders.js +0 -556
  53. package/dist/tools/scanner.js +0 -564
  54. package/dist/tools/stake.js +0 -369
  55. package/dist/tools/vault.js +0 -1020
  56. package/dist/tools/wallet.js +0 -200
  57. package/dist/types.js +0 -2
  58. package/dist/wallet.js +0 -372
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dedupClinkInput = dedupClinkInput;
4
- // Deduplicates doubled input from a known Clink v1.7.6 terminal bug (garbled/
5
- // doubled keystrokes, e.g. "finch_sk_xxfinch_sk_xx" -> "finch_sk_xx"). Used by
6
- // every raw-input prompt in cli.ts (login, setup wizard provider/URL prompts)
7
- // before validating what the user typed.
8
- function dedupClinkInput(s) {
9
- if (s.length > 0 && s.length % 2 === 0) {
10
- const half = s.length / 2;
11
- if (s.slice(0, half) === s.slice(half))
12
- return s.slice(0, half);
13
- }
14
- return s;
15
- }
package/dist/config.js DELETED
@@ -1,132 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.env = env;
37
- exports.readConfig = readConfig;
38
- exports.writeConfig = writeConfig;
39
- exports.getSavedToken = getSavedToken;
40
- exports.isApiKey = isApiKey;
41
- exports.hydrateEnvFromConfig = hydrateEnvFromConfig;
42
- const fs = __importStar(require("fs"));
43
- const os = __importStar(require("os"));
44
- const path = __importStar(require("path"));
45
- const CONFIG_DIR = path.join(os.homedir(), ".finch");
46
- const LEGACY_DIR = path.join(os.homedir(), ".finch");
47
- const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
48
- const LEGACY_FILE = path.join(LEGACY_DIR, "config.json");
49
- /** Prefer FINCH_* env, fall back to legacy FINCH_* during rebrand. */
50
- function env(name, legacy) {
51
- const primary = process.env[name];
52
- if (primary !== undefined && primary !== "")
53
- return primary;
54
- if (legacy) {
55
- const v = process.env[legacy];
56
- if (v !== undefined && v !== "")
57
- return v;
58
- }
59
- // Auto-map FINCH_X → FINCH_X when legacy not passed
60
- if (name.startsWith("FINCH_")) {
61
- const auto = "FINCH_" + name.slice("FINCH_".length);
62
- const v = process.env[auto];
63
- if (v !== undefined && v !== "")
64
- return v;
65
- }
66
- return undefined;
67
- }
68
- function readConfig() {
69
- try {
70
- if (fs.existsSync(CONFIG_FILE)) {
71
- return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf8"));
72
- }
73
- // migrate-read: still pick up old ~/.finch/config.json
74
- if (fs.existsSync(LEGACY_FILE)) {
75
- return JSON.parse(fs.readFileSync(LEGACY_FILE, "utf8"));
76
- }
77
- }
78
- catch {
79
- // Missing/corrupt config file - treat as no saved config.
80
- }
81
- return {};
82
- }
83
- function writeConfig(patch) {
84
- const current = readConfig();
85
- const updated = { ...current, ...patch };
86
- if (!fs.existsSync(CONFIG_DIR))
87
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
88
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2), { mode: 0o600 });
89
- }
90
- function getSavedToken() {
91
- // env var always wins over saved config
92
- return env("FINCH_SESSION_TOKEN", "FINCH_SESSION_TOKEN") ?? readConfig().sessionToken;
93
- }
94
- /** Accept finch_sk_* (new) and noel_sk_* (backend still issues these). */
95
- function isApiKey(value) {
96
- if (!value)
97
- return false;
98
- return value.startsWith("finch_sk_") || value.startsWith("noel_sk_");
99
- }
100
- // Injects provider keys saved via `finch setup` into process.env, so both
101
- // the interactive CLI and the MCP server process (spawned fresh by Claude
102
- // Desktop/Cursor/etc, which never sees ~/.finch/config.json otherwise)
103
- // pick them up the same way. An env var already set by the parent process
104
- // always wins - this only fills gaps, never overrides.
105
- function hydrateEnvFromConfig() {
106
- const cfg = readConfig();
107
- if (!process.env.BANKR_API_KEY && cfg.bankrApiKey)
108
- process.env.BANKR_API_KEY = cfg.bankrApiKey;
109
- if (!process.env.ANTHROPIC_API_KEY && cfg.anthropicApiKey)
110
- process.env.ANTHROPIC_API_KEY = cfg.anthropicApiKey;
111
- if (!process.env.OPENAI_API_KEY && cfg.openaiApiKey)
112
- process.env.OPENAI_API_KEY = cfg.openaiApiKey;
113
- if (!process.env.OPENAI_BASE_URL && cfg.openaiBaseUrl)
114
- process.env.OPENAI_BASE_URL = cfg.openaiBaseUrl;
115
- // Bridge legacy env into FINCH_* so the rest of the codebase can read one name.
116
- const bridges = [
117
- ["FINCH_SESSION_TOKEN", "FINCH_SESSION_TOKEN"],
118
- ["FINCH_API_KEY", "FINCH_API_KEY"],
119
- ["FINCH_CONVEX_URL", "FINCH_CONVEX_URL"],
120
- ["FINCH_TOOLS", "FINCH_TOOLS"],
121
- ["FINCH_PROVIDER", "FINCH_PROVIDER"],
122
- ["FINCH_MODEL", "FINCH_MODEL"],
123
- ["FINCH_RPC_URL", "FINCH_RPC_URL"],
124
- ["FINCH_BROADCAST_RPC", "FINCH_BROADCAST_RPC"],
125
- ["FINCH_WALLET_PASSPHRASE", "FINCH_WALLET_PASSPHRASE"],
126
- ["FINCH_PAYMENT_HEADER", "FINCH_PAYMENT_HEADER"],
127
- ];
128
- for (const [fin, leg] of bridges) {
129
- if (!process.env[fin] && process.env[leg])
130
- process.env[fin] = process.env[leg];
131
- }
132
- }
package/dist/convex.js DELETED
@@ -1,175 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PaymentRequiredError = exports.CONVEX_SITE = void 0;
4
- exports.buildPaymentHeader = buildPaymentHeader;
5
- exports.callConvex = callConvex;
6
- exports.callConvexRaw = callConvexRaw;
7
- const wallet_js_1 = require("./wallet.js");
8
- const config_js_1 = require("./config.js");
9
- exports.CONVEX_SITE = process.env.FINCH_CONVEX_URL ?? "https://befitting-porcupine-276.convex.site";
10
- const RETRY_STATUSES = new Set([429, 500, 502, 503, 504]);
11
- const RETRY_DELAYS = [500, 1000, 2000];
12
- class PaymentRequiredError extends Error {
13
- constructor(details) {
14
- super("Payment required");
15
- this.name = "PaymentRequiredError";
16
- this.details = details;
17
- }
18
- }
19
- exports.PaymentRequiredError = PaymentRequiredError;
20
- function buildPaymentHeader(txHash, requestId) {
21
- return Buffer.from(`${txHash}:${requestId}`).toString("base64");
22
- }
23
- async function attemptConvex(url, method, headers, body, timeoutMs = 30000) {
24
- return fetch(url, {
25
- method,
26
- headers,
27
- body: body ? JSON.stringify(body) : undefined,
28
- signal: AbortSignal.timeout(timeoutMs),
29
- });
30
- }
31
- async function callConvex(path, method, body, toolName = "unknown", timeoutMs = 30000,
32
- // Fund-moving mutations (stake, unstake, claim rewards, a real - non-
33
- // dryRun - automation trigger) are NOT idempotent server-side: there is
34
- // no request-id dedup on the backend, so silently retrying a POST whose
35
- // response was merely lost (a network blip or client-side timeout AFTER
36
- // the server already processed it) can double-execute a real transfer.
37
- // Pass true here for any such call - it trades the convenience of an
38
- // automatic retry for never risking a duplicate execution; the caller
39
- // sees a clear "may have already gone through" error instead and can
40
- // check status before deciding to retry by hand.
41
- noRetry = false) {
42
- const url = `${exports.CONVEX_SITE}${path}`;
43
- const headers = { "Content-Type": "application/json" };
44
- const apiKey = process.env.FINCH_API_KEY;
45
- const sessionToken = (0, config_js_1.getSavedToken)(); // env var → saved config fallback
46
- // Prefer session token (resolved by backend) over API key for Convex API calls
47
- const authHeader = sessionToken
48
- ? `Bearer ${sessionToken}`
49
- : apiKey
50
- ? `Bearer ${apiKey}`
51
- : null;
52
- if (authHeader) {
53
- headers["Authorization"] = authHeader;
54
- }
55
- else {
56
- try {
57
- const { address, signature, timestamp } = await (0, wallet_js_1.signRequest)(toolName);
58
- headers["X-Wallet-Address"] = address;
59
- headers["X-Wallet-Signature"] = signature;
60
- headers["X-Wallet-Timestamp"] = timestamp;
61
- }
62
- catch {
63
- // continue without wallet headers - server will respond with 401/402
64
- }
65
- }
66
- const paymentHeader = process.env.FINCH_PAYMENT_HEADER;
67
- if (paymentHeader)
68
- headers["X-Payment"] = paymentHeader;
69
- // BYOK headers - user pays for their own AI/service costs
70
- if (process.env.ANTHROPIC_API_KEY)
71
- headers["X-User-Anthropic-Key"] = process.env.ANTHROPIC_API_KEY;
72
- if (process.env.OPENAI_API_KEY)
73
- headers["X-User-OpenAI-Key"] = process.env.OPENAI_API_KEY;
74
- if (process.env.GROK_API_KEY)
75
- headers["X-User-Grok-Key"] = process.env.GROK_API_KEY;
76
- if (process.env.BANKR_API_KEY)
77
- headers["X-User-Bankr-Key"] = process.env.BANKR_API_KEY;
78
- let lastError = null;
79
- const attempts = noRetry ? 1 : RETRY_DELAYS.length;
80
- for (let attempt = 0; attempt < attempts; attempt++) {
81
- if (attempt > 0) {
82
- await new Promise((r) => setTimeout(r, RETRY_DELAYS[attempt - 1]));
83
- }
84
- let res;
85
- try {
86
- res = await attemptConvex(url, method, headers, body, timeoutMs);
87
- }
88
- catch (err) {
89
- // Ambiguous: the request may never have reached the server, or it may
90
- // have been received and even processed before the connection died -
91
- // there's no way to tell from here. Safe to retry for read-only/
92
- // idempotent calls; for a fund-moving one, retrying risks resending a
93
- // mutation that already landed.
94
- lastError = noRetry
95
- ? new Error(`${err?.message ?? err} - request may or may not have completed (no response received). Check status before retrying manually.`)
96
- : err;
97
- continue;
98
- }
99
- if (res.status === 402) {
100
- const b = await res.json().catch(() => ({}));
101
- throw new PaymentRequiredError(b);
102
- }
103
- if (res.status === 401) {
104
- const b = await res.json().catch(() => ({}));
105
- throw new Error(`🔑 ${b.message || "Authentication required"}\n\n` +
106
- `→ Sign in at: ${b.url || "https://finchagentic.com"}\n\n` +
107
- `Hint: ${b.hint || 'Add FINCH_SESSION_TOKEN=… to the env block in your MCP config'}\n\n` +
108
- `${b.alternative ? `Alternative: ${b.alternative}` : ""}`);
109
- }
110
- if (RETRY_STATUSES.has(res.status) && attempt < attempts - 1) {
111
- // Capture the actual body so a deterministic error (e.g. "unknown
112
- // token") that happens to come back on a 500 still surfaces its real
113
- // message if retries exhaust - previously this discarded the body
114
- // entirely and threw a bare "Finch API error: 500", hiding exactly the
115
- // information the caller needed to fix the request.
116
- const bodyText = await res.text().catch(() => "");
117
- lastError = new Error(`Finch API error ${res.status}: ${bodyText.slice(0, 300) || "(no body)"}`);
118
- continue;
119
- }
120
- // noRetry + a retryable status on the one and only attempt: the server
121
- // definitely received this one (unlike the network-exception case
122
- // above), so it may have partially or fully processed it before
123
- // erroring - same "check before retrying" caution, worded for the case
124
- // where we know a response did come back.
125
- if (RETRY_STATUSES.has(res.status) && noRetry) {
126
- const bodyText = await res.text().catch(() => "");
127
- throw new Error(`Finch API error ${res.status}: ${bodyText.slice(0, 300) || "(no body)"} - the server received this request and may have processed it before erroring. Check status before retrying manually.`);
128
- }
129
- if (!res.ok)
130
- throw new Error(`Finch API error: ${res.status} ${await res.text()}`);
131
- return res.json();
132
- }
133
- throw lastError ?? new Error("Request failed after retries");
134
- }
135
- // Variant that returns the response body as raw text. Used for endpoints
136
- // that stream non-JSON content like /vault/blob (large vault entries that
137
- // were offloaded to Convex File Storage).
138
- async function callConvexRaw(path, toolName = "unknown", timeoutMs = 60000) {
139
- const url = `${exports.CONVEX_SITE}${path}`;
140
- const headers = {};
141
- const apiKey = process.env.FINCH_API_KEY;
142
- const sessionToken = (0, config_js_1.getSavedToken)();
143
- // Same precedence as callConvex() above - prefer session token over API
144
- // key. These two functions previously disagreed (this one checked apiKey
145
- // first), so the same env/config could pick a different credential
146
- // depending on which helper a tool happened to call.
147
- const authHeader = sessionToken
148
- ? `Bearer ${sessionToken}`
149
- : apiKey
150
- ? `Bearer ${apiKey}`
151
- : null;
152
- if (authHeader) {
153
- headers["Authorization"] = authHeader;
154
- }
155
- else {
156
- try {
157
- const { address, signature, timestamp } = await (0, wallet_js_1.signRequest)(toolName);
158
- headers["X-Wallet-Address"] = address;
159
- headers["X-Wallet-Signature"] = signature;
160
- headers["X-Wallet-Timestamp"] = timestamp;
161
- }
162
- catch {
163
- // No local wallet available to sign with - continue without wallet
164
- // headers, server will respond with 401/402 if auth was required.
165
- }
166
- }
167
- const res = await fetch(url, {
168
- method: "GET",
169
- headers,
170
- signal: AbortSignal.timeout(timeoutMs),
171
- });
172
- if (!res.ok)
173
- throw new Error(`Finch API error: ${res.status}`);
174
- return res.text();
175
- }
package/dist/dex-pair.js DELETED
@@ -1,54 +0,0 @@
1
- "use strict";
2
- /**
3
- * Pick the DexScreener pair whose numbers actually describe the token asked for.
4
- *
5
- * `priceUsd`, `marketCap`, `fdv`, `priceChange` and `txns` on a pair all describe
6
- * the BASE token. Taking the deepest pair regardless of side therefore reports a
7
- * different token entirely, and does it convincingly — the caller's own contract
8
- * address is still printed alongside. Two real cases:
9
- *
10
- * - Canonical USDC on Base. Its deepest pair is `AERO/USDC`, so asking for
11
- * USDC returned Aerodrome at $0.4332 with an $840M FDV.
12
- * - NVDA on Robinhood Chain. Its deepest pair is `AI/NVDA`, so it reported AI
13
- * at $0.0063 as though that were NVDA at $205 — and that price fed the
14
- * take-profit and stop-loss triggers.
15
- *
16
- * Base-side pairs are preferred by depth. When a token only ever appears as the
17
- * quote, its price is still derivable as `basePriceUsd / basePriceInOurToken`,
18
- * so the pair is rebuilt with the sides swapped and the fields that describe the
19
- * other token's flow dropped rather than passed off as ours.
20
- */
21
- Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.pickTokenPair = pickTokenPair;
23
- const depth = (p) => p.liquidity?.usd ?? 0;
24
- function pickTokenPair(pairs, tokenAddress) {
25
- const want = tokenAddress.toLowerCase();
26
- const all = pairs ?? [];
27
- const baseSide = all
28
- .filter((p) => p.baseToken?.address?.toLowerCase() === want)
29
- .sort((a, b) => depth(b) - depth(a));
30
- if (baseSide.length)
31
- return baseSide[0];
32
- const q = all
33
- .filter((p) => p.quoteToken?.address?.toLowerCase() === want)
34
- .sort((a, b) => depth(b) - depth(a))[0];
35
- if (!q)
36
- return null;
37
- const baseUsd = Number(q.priceUsd);
38
- const baseInOurs = Number(q.priceNative);
39
- if (!isFinite(baseUsd) || !isFinite(baseInOurs) || baseInOurs <= 0)
40
- return null;
41
- return {
42
- ...q,
43
- baseToken: q.quoteToken,
44
- quoteToken: q.baseToken,
45
- priceUsd: String(baseUsd / baseInOurs),
46
- priceNative: undefined,
47
- // Supply-based and direction-based figures belong to the other token.
48
- marketCap: undefined,
49
- fdv: undefined,
50
- txns: undefined,
51
- priceChange: undefined,
52
- derivedFromQuoteSide: true,
53
- };
54
- }