@finchagentic/mcp 4.6.5 → 4.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +2 -2
- package/dist/finch-output.js +47 -0
- package/dist/finch-status.js +81 -0
- package/dist/index.js +1 -1
- package/dist/server.js +26 -4
- package/dist/tool-filter.js +3 -1
- package/dist/tools/memory.js +8 -8
- package/dist/tools/miroshark.js +1 -1
- package/dist/tools/os.js +2 -2
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -64,7 +64,7 @@ const CORE_TOOL_COUNT = (() => {
|
|
|
64
64
|
process.env.FINCH_TOOLS = prev;
|
|
65
65
|
}
|
|
66
66
|
})();
|
|
67
|
-
const CONVEX_SITE = process.env.FINCH_CONVEX_URL ?? "https://
|
|
67
|
+
const CONVEX_SITE = process.env.FINCH_CONVEX_URL ?? "https://valuable-fish-533.convex.site";
|
|
68
68
|
const PKG_VERSION = (() => {
|
|
69
69
|
try {
|
|
70
70
|
const raw = fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8");
|
|
@@ -896,7 +896,7 @@ async function doctorFlow() {
|
|
|
896
896
|
checks.push({
|
|
897
897
|
name: "Backend reachable", status: "✗",
|
|
898
898
|
detail: `${CONVEX_SITE} → ${err.message}`,
|
|
899
|
-
fix: `Network issue or wrong URL. Default: https://
|
|
899
|
+
fix: `Network issue or wrong URL. Default: https://valuable-fish-533.convex.site`,
|
|
900
900
|
});
|
|
901
901
|
}
|
|
902
902
|
// 3. Auth state
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Output quality post-processor (CallTool choke point).
|
|
4
|
+
* Normalizes every tool response before it reaches the client:
|
|
5
|
+
* 1. Money/percent/date formatting inside the text payload (safe regex,
|
|
6
|
+
* only touches patterns that are unambiguous).
|
|
7
|
+
* 2. Long-response triage: >200 lines get a "showing first N" head +
|
|
8
|
+
* pointer instead of silently dumping (context window hygiene).
|
|
9
|
+
* 3. Never touches isError responses or JSON-only structuredContent-only
|
|
10
|
+
* shapes - the client renders those natively.
|
|
11
|
+
*/
|
|
12
|
+
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
|
+
function formatMoney(text) {
|
|
18
|
+
// Cap runaway precision: $0.00345678 -> $0.00346. Keeps tokens readable.
|
|
19
|
+
return text.replace(MONEY_RE, (m, num) => {
|
|
20
|
+
const n = Number(num.replace(/,/g, ""));
|
|
21
|
+
if (!Number.isFinite(n)) return m;
|
|
22
|
+
const trimmed = n.toFixed(4).replace(/0+$/, "").replace(/\.$/, "");
|
|
23
|
+
return `$${trimmed}`;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function truncate(text) {
|
|
28
|
+
const lines = text.split("\n");
|
|
29
|
+
if (lines.length <= MAX_LINES) return text;
|
|
30
|
+
const head = lines.slice(0, MAX_LINES).join("\n");
|
|
31
|
+
return `${head}\n\n… ${lines.length - MAX_LINES} more lines — narrow your query (smaller limit, fewer fields) for the full output.`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function processResponse(response) {
|
|
35
|
+
if (!response || response.isError) return response;
|
|
36
|
+
const first = response.content?.[0];
|
|
37
|
+
if (!first || first.type !== "text" || typeof first.text !== "string") return response;
|
|
38
|
+
let text = first.text;
|
|
39
|
+
text = formatMoney(text);
|
|
40
|
+
text = truncate(text);
|
|
41
|
+
if (text !== first.text) {
|
|
42
|
+
return { ...response, content: [{ ...first, text }] };
|
|
43
|
+
}
|
|
44
|
+
return response;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = { processResponse, formatMoney, truncate };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const config_js_1 = require("./config.js");
|
|
3
|
+
const convex_js_1 = require("./convex.js");
|
|
4
|
+
exports.FINCH_STATUS_TOOL = {
|
|
5
|
+
name: "finch_status",
|
|
6
|
+
description: "Check Finch MCP is working - no sign-in needed. Returns the version, how many tools are available, whether the session token is configured, and a ready-to-paste MCP client config snippet. Run this FIRST if anything feels off: it tells you instantly whether the problem is auth (missing token), network (backend unreachable), or the tool itself.",
|
|
7
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
8
|
+
annotations: { title: "Finch status", readOnlyHint: true, openWorldHint: false },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// `finch_status` handler - never throws on auth; when a token is configured
|
|
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");
|
|
18
|
+
let tokenSet = false;
|
|
19
|
+
let authState = "none";
|
|
20
|
+
let authDetail = "";
|
|
21
|
+
try {
|
|
22
|
+
tokenSet = Boolean((0, config_js_1.getSavedToken)());
|
|
23
|
+
} catch { tokenSet = false; }
|
|
24
|
+
if (tokenSet) {
|
|
25
|
+
try {
|
|
26
|
+
const data = await (0, convex_js_1.callConvex)("/memory/profile", "GET", undefined, "finch_status", 8000, true);
|
|
27
|
+
authState = (data?.status === "ok") ? "valid" : "rejected";
|
|
28
|
+
if (authState === "rejected") authDetail = "the session token was rejected by the backend - re-copy it from app.finchagentic.com";
|
|
29
|
+
} catch (err) {
|
|
30
|
+
const msg = String(err?.message ?? err);
|
|
31
|
+
if (msg.includes("Authentication required")) {
|
|
32
|
+
authState = "invalid";
|
|
33
|
+
authDetail = "the backend rejected the token as expired or invalid - re-copy it from app.finchagentic.com";
|
|
34
|
+
} else {
|
|
35
|
+
authState = "unreachable";
|
|
36
|
+
authDetail = msg.slice(0, 120);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const configJson = JSON.stringify({
|
|
41
|
+
mcpServers: {
|
|
42
|
+
finch: {
|
|
43
|
+
command: "npx",
|
|
44
|
+
args: ["-y", "@finchagentic/mcp@" + pkg.version],
|
|
45
|
+
env: { FINCH_SESSION_TOKEN: "<your token>" },
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
}, null, 2);
|
|
49
|
+
const lines = tokenSet && authState === "valid"
|
|
50
|
+
? [
|
|
51
|
+
"**Finch MCP v" + pkg.version + "** - runtime layer for agentic AI", "",
|
|
52
|
+
"- Session token: \u2705 valid (verified against the backend)",
|
|
53
|
+
"- Tools: **116** registered (surface depends on FINCH_TOOLS filter)",
|
|
54
|
+
"- Resources: finch://vault/<key> - Prompts: crypto-thesis and friends",
|
|
55
|
+
"- Tool presets: FINCH_PRESET=core|defi|research|memory (default core) - FINCH_TOOLS=all for everything",
|
|
56
|
+
"",
|
|
57
|
+
"All set. Good first calls: `memory_add` (persist a note instantly), `get_market` (live prices), `deep_research` (multi-step reports, streaming progress).",
|
|
58
|
+
]
|
|
59
|
+
: tokenSet
|
|
60
|
+
? [
|
|
61
|
+
"**Finch MCP v" + pkg.version + "** - runtime layer for agentic AI", "",
|
|
62
|
+
`- Session token: \u26a0\ufe0f configured but **${authState}**`,
|
|
63
|
+
authDetail ? `- ${authDetail}` : "",
|
|
64
|
+
"- Tools are registered, but every backend-backed call will fail until the token is replaced.",
|
|
65
|
+
"",
|
|
66
|
+
"**Fix:** re-copy a fresh token from app.finchagentic.com, update FINCH_SESSION_TOKEN in your MCP config, restart the client.",
|
|
67
|
+
]
|
|
68
|
+
: [
|
|
69
|
+
"**Finch MCP v" + pkg.version + "** - runtime layer for agentic AI", "",
|
|
70
|
+
"- Session token: \u274c not set", "",
|
|
71
|
+
"**To sign in (60 seconds):**", "",
|
|
72
|
+
"1. Sign in at https://app.finchagentic.com (wallet or Google)",
|
|
73
|
+
"2. Copy your session token from the app",
|
|
74
|
+
"3. Add to your MCP client config:",
|
|
75
|
+
"```json",
|
|
76
|
+
configJson,
|
|
77
|
+
"```", "",
|
|
78
|
+
"Once the token is set, restart the MCP client and re-run this tool.",
|
|
79
|
+
];
|
|
80
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
81
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -54,7 +54,7 @@ const PKG_VERSION = (() => {
|
|
|
54
54
|
return "unknown";
|
|
55
55
|
}
|
|
56
56
|
})();
|
|
57
|
-
const CONVEX_SITE = process.env.FINCH_CONVEX_URL ?? "https://
|
|
57
|
+
const CONVEX_SITE = process.env.FINCH_CONVEX_URL ?? "https://valuable-fish-533.convex.site";
|
|
58
58
|
// ── ANSI helpers ──────────────────────────────────────────────────────────────
|
|
59
59
|
const C = {
|
|
60
60
|
cyan: "\x1b[36m",
|
package/dist/server.js
CHANGED
|
@@ -58,6 +58,8 @@ const PKG_VERSION = (() => {
|
|
|
58
58
|
}
|
|
59
59
|
})();
|
|
60
60
|
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");
|
|
61
63
|
const defi_js_1 = require("./tools/defi.js");
|
|
62
64
|
const automation_js_1 = require("./tools/automation.js");
|
|
63
65
|
const insight_js_1 = require("./tools/insight.js");
|
|
@@ -130,7 +132,8 @@ exports.ALL_TOOLS = [
|
|
|
130
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)
|
|
131
133
|
...rh_bridge_js_1.BRIDGE_TOOLS, // 1 - rh_stock_bridge (tokenized stock vs real equity)
|
|
132
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
|
|
133
|
-
...os_js_1.OS_TOOLS
|
|
135
|
+
...os_js_1.OS_TOOLS.filter((t) => t.name !== "finch_status"), // finch_status lives in finch-status.js (dedup)
|
|
136
|
+
// 2 - finch_diagnostics, finch_shell_chat
|
|
134
137
|
...research_js_1.RESEARCH_TOOLS, // 2 - web_scrape, web_search
|
|
135
138
|
...deep_research_js_1.DEEP_RESEARCH_TOOLS, // 1 - deep_research (search → scrape → rank → cited evidence pack; caller synthesises)
|
|
136
139
|
...research_compare_js_1.RESEARCH_COMPARE_TOOLS, // 1 - research_compare (diff two reports across time)
|
|
@@ -215,7 +218,10 @@ exports.server = new index_js_1.Server({ name: "finch", version: PKG_VERSION },
|
|
|
215
218
|
// withAnnotations attaches MCP behavioural hints (readOnly/destructive/etc) so
|
|
216
219
|
// clients can auto-run reads and prompt before destructive/fund-moving calls.
|
|
217
220
|
exports.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
218
|
-
tools:
|
|
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
|
+
],
|
|
219
225
|
}));
|
|
220
226
|
// MCP Resources - vault entries surface as `finch://vault/<key>`.
|
|
221
227
|
// Clients can pull them via the standard resource flow instead of a Tool
|
|
@@ -283,14 +289,30 @@ exports.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (reques
|
|
|
283
289
|
return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
|
|
284
290
|
}
|
|
285
291
|
}
|
|
292
|
+
if (name === "finch_status") {
|
|
293
|
+
return finch_status_js_1.handleFinchStatus();
|
|
294
|
+
}
|
|
286
295
|
const handler = exports.HANDLER_MAP.get(name);
|
|
287
296
|
if (!handler) {
|
|
288
297
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
289
298
|
}
|
|
290
299
|
try {
|
|
291
|
-
|
|
300
|
+
// Hard timeout guard: a hung tool must never wedge the client session.
|
|
301
|
+
// 180s covers deep_research's multi-stage pipeline with margin.
|
|
302
|
+
const HARD_TIMEOUT_MS = 180_000;
|
|
303
|
+
let timer;
|
|
304
|
+
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);
|
|
308
|
+
});
|
|
309
|
+
const result = await Promise.race([
|
|
310
|
+
handler(name, args),
|
|
311
|
+
timeoutPromise,
|
|
312
|
+
]);
|
|
313
|
+
clearTimeout(timer);
|
|
292
314
|
if (result)
|
|
293
|
-
return result;
|
|
315
|
+
return (0, finch_output_js_1.processResponse)(result);
|
|
294
316
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
295
317
|
}
|
|
296
318
|
catch (err) {
|
package/dist/tool-filter.js
CHANGED
|
@@ -37,7 +37,9 @@ function filterTools(allTools) {
|
|
|
37
37
|
// Default is "core" - keeps LLM context cost low while everything
|
|
38
38
|
// is still callable by name. Power users opt back in via
|
|
39
39
|
// FINCH_TOOLS=all. Explicit empty env still means "all" for back-compat.
|
|
40
|
-
|
|
40
|
+
// FINCH_PRESET is the friendly alias (single preset name only); FINCH_TOOLS
|
|
41
|
+
// stays the power-user env (comma-separated combos + all).
|
|
42
|
+
const raw = (process.env.FINCH_TOOLS ?? process.env.FINCH_PRESET ?? "core").trim().toLowerCase();
|
|
41
43
|
const env = raw === "" ? "core" : raw;
|
|
42
44
|
if (env === "all")
|
|
43
45
|
return allTools;
|
package/dist/tools/memory.js
CHANGED
|
@@ -302,7 +302,7 @@ exports.MEMORY_TOOLS = [
|
|
|
302
302
|
"Unlike vault_save, memory_add is instant: no versioning, no type required. " +
|
|
303
303
|
"Use for notes, decisions, preferences, or anything you want to find later. " +
|
|
304
304
|
"Pass sourceUrl to fetch and index any web page, GitHub repo, or Notion page automatically - " +
|
|
305
|
-
"searchable in ~30s. Retrieval is
|
|
305
|
+
"searchable in ~30s. Retrieval is hybrid (semantic embeddings fused with keyword search, reranked by recency and pinned weight) - " +
|
|
306
306
|
"'what did I say about ETH yield?' finds notes containing those words or close variants, " +
|
|
307
307
|
"not unrelated phrasing with the same meaning. " +
|
|
308
308
|
"Auto-deduplicates: identical content in your recent 50 memories is skipped (override with force:true). " +
|
|
@@ -324,11 +324,11 @@ exports.MEMORY_TOOLS = [
|
|
|
324
324
|
},
|
|
325
325
|
{
|
|
326
326
|
name: "memory_search",
|
|
327
|
-
description: "
|
|
328
|
-
"
|
|
329
|
-
"
|
|
330
|
-
"
|
|
331
|
-
"
|
|
327
|
+
description: "Search your stored memories. Hybrid retrieval: semantic embeddings fused with keyword " +
|
|
328
|
+
"search (Reciprocal Rank Fusion), reranked by recency - notes lose ~30% relevance per quarter - " +
|
|
329
|
+
"with pinned notes immune to decay. Understands meaning, not just words: 'low risk crypto yield' " +
|
|
330
|
+
"matches a note phrased as 'conservative DeFi strategies'. Exact-token lookups (env var names, " +
|
|
331
|
+
"contract addresses) also work via the lexical side.",
|
|
332
332
|
inputSchema: {
|
|
333
333
|
type: "object",
|
|
334
334
|
properties: {
|
|
@@ -342,7 +342,7 @@ exports.MEMORY_TOOLS = [
|
|
|
342
342
|
name: "memory_context",
|
|
343
343
|
description: "Retrieve the most relevant memories for a topic, formatted as AI-ready context. " +
|
|
344
344
|
"Use at the start of research tasks to prime with everything stored about a topic. " +
|
|
345
|
-
"
|
|
345
|
+
"Hybrid retrieval: embeddings + keyword, fused and reranked - phrasing can differ from the note. " +
|
|
346
346
|
"you expect were actually used when the memory was saved.",
|
|
347
347
|
inputSchema: {
|
|
348
348
|
type: "object",
|
|
@@ -758,7 +758,7 @@ async function handleMemoryTool(name, args) {
|
|
|
758
758
|
`• memory_add (URL indexing) - ✅`,
|
|
759
759
|
`• Google Drive / Gmail / Notion - connect at finchagentic.com`,
|
|
760
760
|
``,
|
|
761
|
-
`**Capabilities:**
|
|
761
|
+
`**Capabilities:** Hybrid retrieval (semantic + keyword, RRF fusion) with time-decay ranking; pinned notes bypass decay.`,
|
|
762
762
|
].join("\n"),
|
|
763
763
|
}],
|
|
764
764
|
structuredContent: buildMemoryProfile(data),
|
package/dist/tools/miroshark.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.MIROSHARK_TOOLS = void 0;
|
|
4
4
|
exports.handleMirosharkTool = handleMirosharkTool;
|
|
5
5
|
const config_js_1 = require("../config.js");
|
|
6
|
-
const CONVEX_SITE = process.env.FINCH_CONVEX_URL ?? "https://
|
|
6
|
+
const CONVEX_SITE = process.env.FINCH_CONVEX_URL ?? "https://valuable-fish-533.convex.site";
|
|
7
7
|
exports.MIROSHARK_TOOLS = [
|
|
8
8
|
{
|
|
9
9
|
name: "miroshark_simulate",
|
package/dist/tools/os.js
CHANGED
|
@@ -7,7 +7,7 @@ const token_gate_js_1 = require("../token-gate.js");
|
|
|
7
7
|
const wallet_js_1 = require("../wallet.js");
|
|
8
8
|
const local_memory_js_1 = require("../local-memory.js");
|
|
9
9
|
const config_js_1 = require("../config.js");
|
|
10
|
-
const CONVEX_SITE = process.env.FINCH_CONVEX_URL ?? "https://
|
|
10
|
+
const CONVEX_SITE = process.env.FINCH_CONVEX_URL ?? "https://valuable-fish-533.convex.site";
|
|
11
11
|
exports.OS_TOOLS = [
|
|
12
12
|
{
|
|
13
13
|
name: "finch_status",
|
|
@@ -114,7 +114,7 @@ async function handleOsTool(name, args) {
|
|
|
114
114
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
115
115
|
}
|
|
116
116
|
case "finch_diagnostics": {
|
|
117
|
-
const CONVEX_URL = process.env.FINCH_CONVEX_URL ?? "https://
|
|
117
|
+
const CONVEX_URL = process.env.FINCH_CONVEX_URL ?? "https://valuable-fish-533.convex.site";
|
|
118
118
|
// Ping root of each service — any non-5xx means the host is up
|
|
119
119
|
const FC_URL = "https://api.firecrawl.dev";
|
|
120
120
|
const SM_URL = "https://api.supermemory.ai";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finchagentic/mcp",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.1",
|
|
4
4
|
"description": "The runtime layer for Agentic AI. Persistent memory, autonomous agents, and workflows that survive every session.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
50
50
|
"ethers": "^6.17.0",
|
|
51
|
-
"zod": "^4.
|
|
51
|
+
"zod": "^4.6.5"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@eslint/js": "^9.39.1",
|