@finchagentic/mcp 4.7.1 → 4.7.3
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 +74 -39
- package/dist/_zod-helpers.js +10 -0
- package/dist/cli-doctor.js +300 -0
- package/dist/cli-env.js +91 -0
- package/dist/cli-install.js +236 -0
- package/dist/cli-login.js +101 -0
- package/dist/cli-orders.js +175 -0
- package/dist/cli-setup.js +270 -0
- package/dist/cli-ui.js +168 -0
- package/dist/cli-vault.js +75 -0
- package/dist/cli.js +61 -1152
- package/dist/config.js +3 -2
- package/dist/enrichment-router.js +5 -18
- package/dist/finch-output.js +30 -29
- package/dist/finch-status.js +105 -40
- package/dist/index.js +0 -0
- package/dist/local-vault.js +5 -12
- package/dist/output-schemas.js +3 -12
- package/dist/project.js +4 -13
- package/dist/server.js +13 -35
- package/dist/tool-filter.js +4 -13
- package/dist/tools/_solidity-scan.js +5 -14
- package/dist/tools/agents.js +14 -26
- package/dist/tools/deep-research-constants.js +33 -0
- package/dist/tools/deep-research-firecrawl.js +88 -0
- package/dist/tools/deep-research-planning.js +249 -0
- package/dist/tools/deep-research-synthesis.js +343 -0
- package/dist/tools/deep-research-text.js +158 -0
- package/dist/tools/deep-research-tools.js +90 -0
- package/dist/tools/deep-research.js +47 -938
- package/dist/tools/defi.js +4 -3
- package/dist/tools/insider.js +4 -14
- package/dist/tools/insight.js +7 -6
- package/dist/tools/market.js +16 -15
- package/dist/tools/memory.js +57 -62
- package/dist/tools/monitor.js +7 -6
- package/dist/tools/os.js +7 -85
- package/dist/tools/research.js +7 -6
- package/dist/tools/rh-mcp-constants.js +65 -0
- package/dist/tools/rh-mcp-dex.js +107 -0
- package/dist/tools/rh-mcp-provider.js +127 -0
- package/dist/tools/rh-mcp-resolve.js +137 -0
- package/dist/tools/rh-mcp-risk.js +230 -0
- package/dist/tools/rh-mcp-safety.js +234 -0
- package/dist/tools/rh-mcp-swap.js +181 -0
- package/dist/tools/rh-mcp-tools.js +137 -0
- package/dist/tools/rh-mcp.js +75 -1191
- package/dist/tools/scanner.js +10 -9
- package/dist/tools/stake.js +7 -20
- package/dist/tools/vault.js +52 -59
- package/package.json +12 -9
package/dist/config.js
CHANGED
|
@@ -88,8 +88,9 @@ function writeConfig(patch) {
|
|
|
88
88
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(updated, null, 2), { mode: 0o600 });
|
|
89
89
|
}
|
|
90
90
|
function getSavedToken() {
|
|
91
|
-
//
|
|
92
|
-
|
|
91
|
+
// FINCH_API_KEY (persistent finch_sk_* key) wins - MCP clients should hold
|
|
92
|
+
// a key, not a session token that expires and silently disconnects them.
|
|
93
|
+
return process.env.FINCH_API_KEY ?? env("FINCH_SESSION_TOKEN", "FINCH_SESSION_TOKEN") ?? readConfig().sessionToken;
|
|
93
94
|
}
|
|
94
95
|
/** Accept finch_sk_* (new) and noel_sk_* (backend still issues these). */
|
|
95
96
|
function isApiKey(value) {
|
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// New behavior: detect the topic domain and hit primary-source APIs in
|
|
8
|
-
// parallel before synthesis. Inject results as "AUTHORITATIVE LIVE DATA"
|
|
9
|
-
// the LLM is instructed to lead with.
|
|
10
|
-
//
|
|
11
|
-
// All APIs used here are free, public, no auth required:
|
|
12
|
-
// - DefiLlama, CoinGecko (crypto)
|
|
13
|
-
// - HackerNews Algolia (tech news, ~real-time)
|
|
14
|
-
// - GitHub search (repos, no auth needed for public read)
|
|
15
|
-
// - arXiv (academic papers)
|
|
16
|
-
// - Wikipedia REST (foundational facts)
|
|
17
|
-
//
|
|
18
|
-
// All calls are best-effort with short timeouts - if any fail, the
|
|
19
|
-
// synthesis runs without that block.
|
|
2
|
+
// Enrichment router for deep_research synthesis - detects topic domain and
|
|
3
|
+
// hits free primary-source APIs in parallel (DefiLlama/CoinGecko, HN
|
|
4
|
+
// Algolia, GitHub search, arXiv, Wikipedia), injected as "AUTHORITATIVE
|
|
5
|
+
// LIVE DATA" so the LLM leads with real data instead of filling thin
|
|
6
|
+
// scraped pages with plausible fiction. Best-effort, short timeouts.
|
|
20
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
8
|
exports.enrichQuery = enrichQuery;
|
|
22
9
|
exports.todayContext = todayContext;
|
package/dist/finch-output.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatMoney = formatMoney;
|
|
4
|
+
exports.truncate = truncate;
|
|
5
|
+
exports.processResponse = processResponse;
|
|
2
6
|
/**
|
|
3
7
|
* Output quality post-processor (CallTool choke point).
|
|
4
8
|
* Normalizes every tool response before it reaches the client:
|
|
@@ -10,38 +14,35 @@
|
|
|
10
14
|
* shapes - the client renders those natively.
|
|
11
15
|
*/
|
|
12
16
|
const MAX_LINES = 200;
|
|
13
|
-
|
|
14
|
-
const MONEY_RE = /\$\s?([\d,]+\.\d{4,})/g; // $0.00012345 -> $0.00012 (4dp cap)
|
|
15
|
-
const ZEROS_RE = /\$0\.0+\d{0,2}(?=\b)/g; // leave tiny prices alone
|
|
16
|
-
|
|
17
|
+
const MONEY_RE = /\$\s?([\d,]+\.\d{4,})/g; // $0.00012345 -> $0.00012 (4dp cap)
|
|
17
18
|
function formatMoney(text) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
// Cap runaway precision: $0.00345678 -> $0.00346. Keeps tokens readable.
|
|
20
|
+
return text.replace(MONEY_RE, (m, num) => {
|
|
21
|
+
const n = Number(num.replace(/,/g, ""));
|
|
22
|
+
if (!Number.isFinite(n))
|
|
23
|
+
return m;
|
|
24
|
+
const trimmed = n.toFixed(4).replace(/0+$/, "").replace(/\.$/, "");
|
|
25
|
+
return `$${trimmed}`;
|
|
26
|
+
});
|
|
25
27
|
}
|
|
26
|
-
|
|
27
28
|
function truncate(text) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
const lines = text.split("\n");
|
|
30
|
+
if (lines.length <= MAX_LINES)
|
|
31
|
+
return text;
|
|
32
|
+
const head = lines.slice(0, MAX_LINES).join("\n");
|
|
33
|
+
return `${head}\n\n… ${lines.length - MAX_LINES} more lines — narrow your query (smaller limit, fewer fields) for the full output.`;
|
|
32
34
|
}
|
|
33
|
-
|
|
34
35
|
function processResponse(response) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
if (!response || response.isError)
|
|
37
|
+
return response;
|
|
38
|
+
const first = response.content?.[0];
|
|
39
|
+
if (!first || first.type !== "text" || typeof first.text !== "string")
|
|
40
|
+
return response;
|
|
41
|
+
let text = first.text;
|
|
42
|
+
text = formatMoney(text);
|
|
43
|
+
text = truncate(text);
|
|
44
|
+
if (text !== first.text) {
|
|
45
|
+
return { ...response, content: [{ ...first, text }, ...response.content.slice(1)] };
|
|
46
|
+
}
|
|
47
|
+
return response;
|
|
45
48
|
}
|
|
46
|
-
|
|
47
|
-
module.exports = { processResponse, formatMoney, truncate };
|
package/dist/finch-status.js
CHANGED
|
@@ -1,37 +1,96 @@
|
|
|
1
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.FINCH_STATUS_TOOL = void 0;
|
|
37
|
+
exports.handleFinchStatus = handleFinchStatus;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
2
40
|
const config_js_1 = require("./config.js");
|
|
3
41
|
const convex_js_1 = require("./convex.js");
|
|
42
|
+
// Same pattern as server.ts's own PKG_VERSION - fs.readFileSync, not
|
|
43
|
+
// require(), since this project's eslint config forbids require() imports.
|
|
44
|
+
function readPkgVersion() {
|
|
45
|
+
try {
|
|
46
|
+
const raw = fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8");
|
|
47
|
+
return JSON.parse(raw).version ?? "unknown";
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return "unknown";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Local-only, no-auth-required status check. Replaces the old finch_status
|
|
54
|
+
// (which lived in tools/os.ts, made 6 Promise.allSettled backend calls, and
|
|
55
|
+
// silently defaulted every field to zero/basic on ANY failure - including a
|
|
56
|
+
// 401 - producing a dashboard that read "empty but healthy" instead of
|
|
57
|
+
// surfacing the real problem). This version makes exactly ONE cheap authed
|
|
58
|
+
// call when a token is configured, and reports the REAL auth state instead.
|
|
4
59
|
exports.FINCH_STATUS_TOOL = {
|
|
5
60
|
name: "finch_status",
|
|
6
|
-
description: "Check Finch MCP is working - no sign-in needed. Returns the version, how many tools are available,
|
|
61
|
+
description: "Check Finch MCP is working - no sign-in needed. Returns the version, how many tools are available, " +
|
|
62
|
+
"whether the session token is configured, and a ready-to-paste MCP client config snippet. Run this FIRST " +
|
|
63
|
+
"if anything feels off: it tells you instantly whether the problem is auth (missing token), network " +
|
|
64
|
+
"(backend unreachable), or the tool itself.",
|
|
7
65
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
8
66
|
annotations: { title: "Finch status", readOnlyHint: true, openWorldHint: false },
|
|
9
67
|
};
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// it makes ONE cheap authed call (/memory/profile) and reports the REAL
|
|
13
|
-
// auth state instead of a fake-healthy dashboard (the old Promise.allSettled
|
|
14
|
-
// version swallowed 401s and showed empty-but-healthy, which hid expired
|
|
15
|
-
// credentials entirely).
|
|
16
|
-
exports.handleFinchStatus = async function handleFinchStatus() {
|
|
17
|
-
const pkg = require("./../package.json");
|
|
68
|
+
async function handleFinchStatus(toolCount) {
|
|
69
|
+
const version = readPkgVersion();
|
|
18
70
|
let tokenSet = false;
|
|
19
71
|
let authState = "none";
|
|
20
72
|
let authDetail = "";
|
|
21
73
|
try {
|
|
22
74
|
tokenSet = Boolean((0, config_js_1.getSavedToken)());
|
|
23
|
-
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
tokenSet = false;
|
|
78
|
+
}
|
|
24
79
|
if (tokenSet) {
|
|
25
80
|
try {
|
|
26
81
|
const data = await (0, convex_js_1.callConvex)("/memory/profile", "GET", undefined, "finch_status", 8000, true);
|
|
27
82
|
authState = (data?.status === "ok") ? "valid" : "rejected";
|
|
28
|
-
if (authState === "rejected")
|
|
29
|
-
|
|
83
|
+
if (authState === "rejected") {
|
|
84
|
+
authDetail = "the session token was rejected by the backend - re-copy it from app.finchagentic.com";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
30
88
|
const msg = String(err?.message ?? err);
|
|
31
89
|
if (msg.includes("Authentication required")) {
|
|
32
90
|
authState = "invalid";
|
|
33
91
|
authDetail = "the backend rejected the token as expired or invalid - re-copy it from app.finchagentic.com";
|
|
34
|
-
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
35
94
|
authState = "unreachable";
|
|
36
95
|
authDetail = msg.slice(0, 120);
|
|
37
96
|
}
|
|
@@ -41,41 +100,47 @@ exports.handleFinchStatus = async function handleFinchStatus() {
|
|
|
41
100
|
mcpServers: {
|
|
42
101
|
finch: {
|
|
43
102
|
command: "npx",
|
|
44
|
-
args: ["-y",
|
|
103
|
+
args: ["-y", `@finchagentic/mcp@${version}`],
|
|
45
104
|
env: { FINCH_SESSION_TOKEN: "<your token>" },
|
|
46
105
|
},
|
|
47
106
|
},
|
|
48
107
|
}, null, 2);
|
|
49
108
|
const lines = tokenSet && authState === "valid"
|
|
50
109
|
? [
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
"-
|
|
110
|
+
`**Finch MCP v${version}** - runtime layer for agentic AI`,
|
|
111
|
+
"",
|
|
112
|
+
"- Session token: ✅ valid (verified against the backend)",
|
|
113
|
+
`- Tools: **${toolCount}** registered (surface depends on FINCH_TOOLS filter)`,
|
|
54
114
|
"- Resources: finch://vault/<key> - Prompts: crypto-thesis and friends",
|
|
55
115
|
"- Tool presets: FINCH_PRESET=core|defi|research|memory (default core) - FINCH_TOOLS=all for everything",
|
|
56
116
|
"",
|
|
57
|
-
"All set. Good first calls: `memory_add` (persist a note instantly), `
|
|
117
|
+
"All set. Good first calls: `memory_add` (persist a note instantly), `get_market_data` (live prices), `deep_research` (multi-step reports, streaming progress).",
|
|
58
118
|
]
|
|
59
119
|
: tokenSet
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
120
|
+
? [
|
|
121
|
+
`**Finch MCP v${version}** - runtime layer for agentic AI`,
|
|
122
|
+
"",
|
|
123
|
+
`- Session token: ⚠️ configured but **${authState}**`,
|
|
124
|
+
authDetail ? `- ${authDetail}` : "",
|
|
125
|
+
"- Tools are registered, but every backend-backed call will fail until the token is replaced.",
|
|
126
|
+
"",
|
|
127
|
+
"**Fix:** re-copy a fresh token from app.finchagentic.com, update FINCH_SESSION_TOKEN in your MCP config, restart the client.",
|
|
128
|
+
]
|
|
129
|
+
: [
|
|
130
|
+
`**Finch MCP v${version}** - runtime layer for agentic AI`,
|
|
131
|
+
"",
|
|
132
|
+
"- Session token: ❌ not set",
|
|
133
|
+
"",
|
|
134
|
+
"**To sign in (60 seconds):**",
|
|
135
|
+
"",
|
|
136
|
+
"1. Sign in at https://app.finchagentic.com (wallet or Google)",
|
|
137
|
+
"2. Copy your session token from the app",
|
|
138
|
+
"3. Add to your MCP client config:",
|
|
139
|
+
"```json",
|
|
140
|
+
configJson,
|
|
141
|
+
"```",
|
|
142
|
+
"",
|
|
143
|
+
"Once the token is set, restart the MCP client and re-run this tool.",
|
|
144
|
+
];
|
|
145
|
+
return { content: [{ type: "text", text: lines.filter((l) => l !== undefined).join("\n") }] };
|
|
146
|
+
}
|
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/local-vault.js
CHANGED
|
@@ -54,18 +54,11 @@ const path = __importStar(require("path"));
|
|
|
54
54
|
const crypto = __importStar(require("crypto"));
|
|
55
55
|
const config_js_1 = require("./config.js");
|
|
56
56
|
const _text_search_js_1 = require("./_text-search.js");
|
|
57
|
-
// Fully-local, user-owned
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
// version), same spirit as codebase-memory-mcp's local-first SQLite store.
|
|
63
|
-
//
|
|
64
|
-
// Every exported function returns objects shaped like the Convex /vault/*
|
|
65
|
-
// responses so tools/vault.ts can swap the data source with a one-line branch
|
|
66
|
-
// and reuse all of its existing rendering. Not-found cases THROW an Error whose
|
|
67
|
-
// message contains "not found", matching how callConvex surfaces a 404 (the
|
|
68
|
-
// vault handlers already catch and format that).
|
|
57
|
+
// Fully-local, user-owned vault backend (`vaultBackend: "local"`) - versioned
|
|
58
|
+
// artifacts on disk under ~/.finch/vault/, no account/Convex/network. Every
|
|
59
|
+
// export returns Convex /vault/*-shaped objects so tools/vault.ts can swap
|
|
60
|
+
// data source with a one-line branch. Not-found throws an Error containing
|
|
61
|
+
// "not found", matching callConvex's own 404 format.
|
|
69
62
|
const VAULT_DIR = path.join(os.homedir(), ".finch", "vault");
|
|
70
63
|
// Local vault is enabled purely by config - it needs no server, just the
|
|
71
64
|
// filesystem. Returns null (→ "use Convex") when the user hasn't opted in.
|
package/dist/output-schemas.js
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Central registry of MCP tool `outputSchema` declarations (spec 2025-06-18).
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// for backward compatibility). Keeping every schema in one file - rather than
|
|
7
|
-
// inline on each tool definition across ~25 modules - makes the machine-readable
|
|
8
|
-
// surface reviewable in one place, mirrors how annotations.ts centralises
|
|
9
|
-
// behavioural hints, and lets a new tool opt in by adding one entry here plus a
|
|
10
|
-
// structuredContent return in its handler (no tool-definition edit needed).
|
|
11
|
-
//
|
|
12
|
-
// Attached to the listed tools by withAnnotations() (annotations.ts) at
|
|
13
|
-
// tools/list time. Only tools whose handler genuinely emits matching
|
|
14
|
-
// structuredContent belong here.
|
|
3
|
+
// One file instead of inline per tool (mirrors annotations.ts). Attached by
|
|
4
|
+
// withAnnotations() at tools/list time - only tools whose handler actually
|
|
5
|
+
// emits matching structuredContent belong here.
|
|
15
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
7
|
exports.OUTPUT_SCHEMAS = void 0;
|
|
17
8
|
const number_null = { type: ["number", "null"] };
|
package/dist/project.js
CHANGED
|
@@ -4,19 +4,10 @@ exports.isLocalVaultActive = isLocalVaultActive;
|
|
|
4
4
|
exports.resolveProjectId = resolveProjectId;
|
|
5
5
|
const convex_js_1 = require("./convex.js");
|
|
6
6
|
const local_vault_js_1 = require("./local-vault.js");
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// convex/projects.ts's resolveOrCreateProjectForUser) so the match/dedup
|
|
12
|
-
// logic exists in exactly one place, shared with the webapp's own project
|
|
13
|
-
// picker.
|
|
14
|
-
//
|
|
15
|
-
// Local-vault mode (vaultBackend: "local") has no project concept at all -
|
|
16
|
-
// it's a flat, unauthenticated file store on the user's own machine with no
|
|
17
|
-
// server to resolve a name against. Callers should check
|
|
18
|
-
// isLocalVaultActive() first and skip resolution entirely rather than call
|
|
19
|
-
// this and get a confusing network-style failure.
|
|
7
|
+
// No persistent "active project" state here - callers name the project by
|
|
8
|
+
// string each call; resolution/auto-create happens server-side (POST
|
|
9
|
+
// /projects/resolve), shared with the webapp's own picker. Local-vault mode
|
|
10
|
+
// has no project concept at all - check isLocalVaultActive() first.
|
|
20
11
|
function isLocalVaultActive() {
|
|
21
12
|
return !!(0, local_vault_js_1.getLocalVaultConfig)();
|
|
22
13
|
}
|
package/dist/server.js
CHANGED
|
@@ -45,6 +45,8 @@ const resources_js_1 = require("./resources.js");
|
|
|
45
45
|
const prompts_js_1 = require("./prompts.js");
|
|
46
46
|
const tool_filter_js_1 = require("./tool-filter.js");
|
|
47
47
|
const annotations_js_1 = require("./annotations.js");
|
|
48
|
+
const finch_status_js_1 = require("./finch-status.js");
|
|
49
|
+
const finch_output_js_1 = require("./finch-output.js");
|
|
48
50
|
// Read version from package.json so the server announces the same version
|
|
49
51
|
// MCP clients see in the npm tarball. Falls back to "unknown" if the file
|
|
50
52
|
// can't be loaded - never blocks server startup.
|
|
@@ -58,8 +60,6 @@ const PKG_VERSION = (() => {
|
|
|
58
60
|
}
|
|
59
61
|
})();
|
|
60
62
|
const market_js_1 = require("./tools/market.js");
|
|
61
|
-
const finch_output_js_1 = require("./finch-output.js");
|
|
62
|
-
const finch_status_js_1 = require("./finch-status.js");
|
|
63
63
|
const defi_js_1 = require("./tools/defi.js");
|
|
64
64
|
const automation_js_1 = require("./tools/automation.js");
|
|
65
65
|
const insight_js_1 = require("./tools/insight.js");
|
|
@@ -132,8 +132,7 @@ exports.ALL_TOOLS = [
|
|
|
132
132
|
...rh_orders_js_1.RH_ORDER_TOOLS, // 5 - rh_dca_create, rh_bracket_create, rh_orders_list, rh_order_cancel, rh_orders_tick (RH automated DCA/TP/SL)
|
|
133
133
|
...rh_bridge_js_1.BRIDGE_TOOLS, // 1 - rh_stock_bridge (tokenized stock vs real equity)
|
|
134
134
|
...memory_js_1.MEMORY_TOOLS, // 9 - memory_add, memory_search, memory_context, memory_profile, memory_list, memory_delete, memory_insight, memory_extract, memory_consolidate. memory_publish removed - promised a "Memory Marketplace" that doesn't exist at any layer (no browse route, no query, no UI), see tools/memory.ts
|
|
135
|
-
...os_js_1.OS_TOOLS
|
|
136
|
-
// 2 - finch_diagnostics, finch_shell_chat
|
|
135
|
+
...os_js_1.OS_TOOLS, // 3 - finch_status, finch_diagnostics, finch_shell_chat
|
|
137
136
|
...research_js_1.RESEARCH_TOOLS, // 2 - web_scrape, web_search
|
|
138
137
|
...deep_research_js_1.DEEP_RESEARCH_TOOLS, // 1 - deep_research (search → scrape → rank → cited evidence pack; caller synthesises)
|
|
139
138
|
...research_compare_js_1.RESEARCH_COMPARE_TOOLS, // 1 - research_compare (diff two reports across time)
|
|
@@ -143,21 +142,10 @@ exports.ALL_TOOLS = [
|
|
|
143
142
|
...chronicle_js_1.CHRONICLE_TOOLS, // 4 - chronicle_add, chronicle_list, chronicle_search, chronicle_stats
|
|
144
143
|
...packets_js_1.PACKET_TOOLS, // 4 - packet_create, packet_run, packet_list, packet_share
|
|
145
144
|
...stake_js_1.STAKE_TOOLS, // 5 - stake_finch_status, stake_finch, unstake_finch, claim_vested_rewards, stake_auto_restake (custodial wallet; requires `finch login`)
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
// marketplace that doesn't exist, after stake_auto_restake was added,
|
|
151
|
-
// after claim_vested_rewards was added to close the gap where the
|
|
152
|
-
// stake-lifecycle notification told users to "run claimVestedRewards" but
|
|
153
|
-
// no MCP tool by that name existed, after code_session_save was added so
|
|
154
|
-
// coding sessions persist the same way deep_research already auto-saves
|
|
155
|
-
// research, and after list_projects was added alongside `workspaceProject`
|
|
156
|
-
// support on vault_save/agent_spawn - MCP tools can now file into the same
|
|
157
|
-
// Projects the webapp Agents page organizes by, resolved/auto-created
|
|
158
|
-
// server-side via POST /projects/resolve; ALL_TOOLS.length is the only
|
|
159
|
-
// number that can't lie). Per-category counts above are best-effort
|
|
160
|
-
// documentation, not load-bearing anywhere.
|
|
145
|
+
// Total tool count: use ALL_TOOLS.length, not a hardcoded number here -
|
|
146
|
+
// this comment has drifted stale repeatedly. Per-category counts above
|
|
147
|
+
// are best-effort docs, not load-bearing.
|
|
148
|
+
finch_status_js_1.FINCH_STATUS_TOOL, // 1 - finch_status now lives in finch-status.ts, not OS_TOOLS - see that file's header for why
|
|
161
149
|
];
|
|
162
150
|
exports.HANDLER_MAP = new Map([
|
|
163
151
|
...market_js_1.MARKET_TOOLS.map(t => [t.name, market_js_1.handleMarketTool]),
|
|
@@ -189,6 +177,7 @@ exports.HANDLER_MAP = new Map([
|
|
|
189
177
|
...chronicle_js_1.CHRONICLE_TOOLS.map(t => [t.name, (n, a) => (0, chronicle_js_1.handleChronicle)(n, a)]),
|
|
190
178
|
...packets_js_1.PACKET_TOOLS.map(t => [t.name, (n, a) => (0, packets_js_1.handlePacket)(n, a)]),
|
|
191
179
|
...stake_js_1.STAKE_TOOLS.map(t => [t.name, stake_js_1.handleStakeTool]),
|
|
180
|
+
[finch_status_js_1.FINCH_STATUS_TOOL.name, ((_name, _args) => (0, finch_status_js_1.handleFinchStatus)(exports.ALL_TOOLS.length))],
|
|
192
181
|
]);
|
|
193
182
|
// `instructions` is returned in the initialize result - it tells the client
|
|
194
183
|
// (and, through it, the model) what this server is and how to reach for it.
|
|
@@ -218,10 +207,7 @@ exports.server = new index_js_1.Server({ name: "finch", version: PKG_VERSION },
|
|
|
218
207
|
// withAnnotations attaches MCP behavioural hints (readOnly/destructive/etc) so
|
|
219
208
|
// clients can auto-run reads and prompt before destructive/fund-moving calls.
|
|
220
209
|
exports.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
221
|
-
tools:
|
|
222
|
-
finch_status_js_1.FINCH_STATUS_TOOL,
|
|
223
|
-
...(0, annotations_js_1.withAnnotations)((0, tool_filter_js_1.filterTools)(exports.ALL_TOOLS)),
|
|
224
|
-
],
|
|
210
|
+
tools: (0, annotations_js_1.withAnnotations)((0, tool_filter_js_1.filterTools)(exports.ALL_TOOLS)),
|
|
225
211
|
}));
|
|
226
212
|
// MCP Resources - vault entries surface as `finch://vault/<key>`.
|
|
227
213
|
// Clients can pull them via the standard resource flow instead of a Tool
|
|
@@ -289,9 +275,6 @@ exports.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (reques
|
|
|
289
275
|
return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
|
|
290
276
|
}
|
|
291
277
|
}
|
|
292
|
-
if (name === "finch_status") {
|
|
293
|
-
return finch_status_js_1.handleFinchStatus();
|
|
294
|
-
}
|
|
295
278
|
const handler = exports.HANDLER_MAP.get(name);
|
|
296
279
|
if (!handler) {
|
|
297
280
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
@@ -299,20 +282,15 @@ exports.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (reques
|
|
|
299
282
|
try {
|
|
300
283
|
// Hard timeout guard: a hung tool must never wedge the client session.
|
|
301
284
|
// 180s covers deep_research's multi-stage pipeline with margin.
|
|
302
|
-
const HARD_TIMEOUT_MS =
|
|
285
|
+
const HARD_TIMEOUT_MS = 180000;
|
|
303
286
|
let timer;
|
|
304
287
|
const timeoutPromise = new Promise((_, reject) => {
|
|
305
|
-
timer = setTimeout(() => reject(new Error(
|
|
306
|
-
`Tool timed out after 180s (${name}). The operation may still complete server-side - check the app before re-running.`
|
|
307
|
-
)), HARD_TIMEOUT_MS);
|
|
288
|
+
timer = setTimeout(() => reject(new Error(`Tool timed out after 180s (${name}). The operation may still complete server-side - check the app before re-running.`)), HARD_TIMEOUT_MS);
|
|
308
289
|
});
|
|
309
|
-
const result = await Promise.race([
|
|
310
|
-
handler(name, args),
|
|
311
|
-
timeoutPromise,
|
|
312
|
-
]);
|
|
290
|
+
const result = await Promise.race([handler(name, args), timeoutPromise]);
|
|
313
291
|
clearTimeout(timer);
|
|
314
292
|
if (result)
|
|
315
|
-
return (0, finch_output_js_1.processResponse)(result);
|
|
293
|
+
return (0, finch_output_js_1.processResponse)(result) ?? result;
|
|
316
294
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
317
295
|
}
|
|
318
296
|
catch (err) {
|
package/dist/tool-filter.js
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.filterTools = filterTools;
|
|
4
|
-
// Tool-subset filter.
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// Tool-subset filter. Full handler map stays intact (any tool can still be
|
|
5
|
+
// invoked by name); only the LIST response sent to clients is trimmed by
|
|
6
|
+
// FINCH_TOOLS, to cut LLM context cost. Default = "core".
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
// chronicle, status). Opt-in presets let token-conscious users cut LLM
|
|
10
|
-
// context cost while keeping the full surface accessible by name:
|
|
11
|
-
//
|
|
12
|
-
// FINCH_TOOLS=core runtime essentials (memory, vault, agents)
|
|
13
|
-
// FINCH_TOOLS=defi Base + market + DeFi execution
|
|
14
|
-
// FINCH_TOOLS=research research + memory + vault
|
|
15
|
-
// FINCH_TOOLS=memory memory + vault + agents only
|
|
16
|
-
// FINCH_TOOLS=memory,defi comma-separated combination
|
|
17
|
-
// FINCH_TOOLS=all every registered tool
|
|
8
|
+
// FINCH_TOOLS=core|defi|research|memory|all, or comma-separated
|
|
18
9
|
//
|
|
19
10
|
// Unknown presets fall back to all to avoid silently hiding tools.
|
|
20
11
|
// Each preset's regex is checked against every tool name in ALL_TOOLS by
|
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Static heuristic scanner for Solidity audit grounding
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// source BEFORE the LLM call and forces the LLM to address each finding
|
|
8
|
-
// (either confirm the risk or explain why it's a false positive). The
|
|
9
|
-
// resulting report leads with "automated static checks", then "LLM review
|
|
10
|
-
// over those findings", then a mandatory disclaimer.
|
|
11
|
-
//
|
|
12
|
-
// This is NOT a substitute for a professional audit. It catches obvious
|
|
13
|
-
// antipatterns. Subtle vulnerabilities (reentrancy guarded by state ordering,
|
|
14
|
-
// signature replay, oracle manipulation under non-obvious conditions) still
|
|
15
|
-
// need human review or specialized tooling (Slither, Mythril, Echidna).
|
|
2
|
+
// Static heuristic scanner for Solidity audit grounding - runs a
|
|
3
|
+
// regex/pattern scan before the LLM call and forces it to address each
|
|
4
|
+
// finding, instead of letting it claim "looks safe" with no structural
|
|
5
|
+
// basis. Not a substitute for a professional audit (Slither/Mythril/
|
|
6
|
+
// Echidna) - catches obvious antipatterns only.
|
|
16
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
8
|
exports.AUDIT_DISCLAIMER = void 0;
|
|
18
9
|
exports.staticScanSolidity = staticScanSolidity;
|
package/dist/tools/agents.js
CHANGED
|
@@ -9,6 +9,7 @@ const llm_js_1 = require("../llm.js");
|
|
|
9
9
|
const local_vault_js_1 = require("../local-vault.js");
|
|
10
10
|
const memory_js_1 = require("./memory.js");
|
|
11
11
|
const project_js_1 = require("../project.js");
|
|
12
|
+
const _zod_helpers_js_1 = require("../_zod-helpers.js");
|
|
12
13
|
// ─── Agent Learning Memory (v3.25) ──────────────────────────────────────────
|
|
13
14
|
// After every agent_update, an LLM reviews the new progress in context of the
|
|
14
15
|
// agent's goal + prior learnings to extract a single repeatable insight. The
|
|
@@ -104,23 +105,10 @@ function withAgentLock(agentName, fn) {
|
|
|
104
105
|
});
|
|
105
106
|
return next;
|
|
106
107
|
}
|
|
107
|
-
// list_agents/hire_agent
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
// always 404'd. Re-add them (and the matching handler blocks below) only
|
|
112
|
-
// alongside building those two routes for real.
|
|
113
|
-
//
|
|
114
|
-
// Same story, same fix, applied again here: agent_identity, agent_schedule,
|
|
115
|
-
// agent_unschedule, agent_pause, agent_resume and agent_runs called
|
|
116
|
-
// /agents/identity, /agents/schedule, /agents/unschedule, /agents/pause and
|
|
117
|
-
// /agents/runs - none of which exist in http.ts, and none of which have any
|
|
118
|
-
// backing data model in schema.ts (no agent-identity table, no scheduler,
|
|
119
|
-
// no run-history table; there isn't even a cron for it in crons.ts). This
|
|
120
|
-
// isn't a missing route, it's an unbuilt subsystem, so the tools were
|
|
121
|
-
// removed rather than stubbed. Re-add only alongside building that
|
|
122
|
-
// autonomous-scheduling backend for real: identity/schedule storage, a cron
|
|
123
|
-
// that actually wakes agents up, and run-history writes.
|
|
108
|
+
// list_agents/hire_agent/agent_identity/agent_schedule/agent_unschedule/
|
|
109
|
+
// agent_pause/agent_resume/agent_runs deleted - their backend routes never
|
|
110
|
+
// existed (dangling comments in http.ts, no actual route/data model). Not a
|
|
111
|
+
// missing route, an unbuilt subsystem. Re-add only alongside building it.
|
|
124
112
|
exports.AGENT_TOOLS = [
|
|
125
113
|
{
|
|
126
114
|
name: "agent_spawn",
|
|
@@ -226,9 +214,9 @@ function buildAgentLedger(name, versions) {
|
|
|
226
214
|
}
|
|
227
215
|
async function handleAgentTool(name, args) {
|
|
228
216
|
if (name === "agent_spawn") {
|
|
229
|
-
const parsed =
|
|
230
|
-
if (!parsed.
|
|
231
|
-
return
|
|
217
|
+
const parsed = (0, _zod_helpers_js_1.parseOrError)(SpawnAgentSchema, args);
|
|
218
|
+
if (!parsed.ok)
|
|
219
|
+
return parsed.error;
|
|
232
220
|
const { name: agentName, goal, context, workspaceProject } = parsed.data;
|
|
233
221
|
const content = JSON.stringify({
|
|
234
222
|
goal,
|
|
@@ -269,9 +257,9 @@ async function handleAgentTool(name, args) {
|
|
|
269
257
|
};
|
|
270
258
|
}
|
|
271
259
|
if (name === "agent_recall") {
|
|
272
|
-
const parsed =
|
|
273
|
-
if (!parsed.
|
|
274
|
-
return
|
|
260
|
+
const parsed = (0, _zod_helpers_js_1.parseOrError)(RecallAgentSchema, args);
|
|
261
|
+
if (!parsed.ok)
|
|
262
|
+
return parsed.error;
|
|
275
263
|
const localVault = (0, local_vault_js_1.getLocalVaultConfig)();
|
|
276
264
|
let data;
|
|
277
265
|
try {
|
|
@@ -334,9 +322,9 @@ async function handleAgentTool(name, args) {
|
|
|
334
322
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
335
323
|
}
|
|
336
324
|
if (name === "agent_update") {
|
|
337
|
-
const parsed =
|
|
338
|
-
if (!parsed.
|
|
339
|
-
return
|
|
325
|
+
const parsed = (0, _zod_helpers_js_1.parseOrError)(UpdateAgentSchema, args);
|
|
326
|
+
if (!parsed.ok)
|
|
327
|
+
return parsed.error;
|
|
340
328
|
const { name: agentName, progress, findings, status = "active", nextStep } = parsed.data;
|
|
341
329
|
return withAgentLock(agentName, async () => {
|
|
342
330
|
const localVault = (0, local_vault_js_1.getLocalVaultConfig)();
|