@finchagentic/mcp 4.4.1 → 4.5.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 +8 -7
- package/dist/cli.js +139 -0
- package/dist/convex.js +31 -4
- package/dist/tools/agents.js +1 -1
- package/dist/tools/automation.js +5 -1
- package/dist/tools/rh-orders.js +13 -6
- package/dist/tools/stake.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,13 +29,13 @@ Always pin the version. Never use `@latest`.
|
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
31
|
# One-command installer (detects common MCP clients)
|
|
32
|
-
npx -y -p @finchagentic/mcp@4.
|
|
32
|
+
npx -y -p @finchagentic/mcp@4.5.0 finch install
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
### Claude Code
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
claude mcp add finch -s user -- npx -y -p @finchagentic/mcp@4.
|
|
38
|
+
claude mcp add finch -s user -- npx -y -p @finchagentic/mcp@4.5.0 finch-mcp
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
### Cursor / Windsurf / Claude Desktop
|
|
@@ -45,7 +45,7 @@ claude mcp add finch -s user -- npx -y -p @finchagentic/mcp@4.4.1 finch-mcp
|
|
|
45
45
|
"mcpServers": {
|
|
46
46
|
"finch": {
|
|
47
47
|
"command": "npx",
|
|
48
|
-
"args": ["-y", "-p", "@finchagentic/mcp@4.
|
|
48
|
+
"args": ["-y", "-p", "@finchagentic/mcp@4.5.0", "finch-mcp"]
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -59,7 +59,7 @@ claude mcp add finch -s user -- npx -y -p @finchagentic/mcp@4.4.1 finch-mcp
|
|
|
59
59
|
"finch": {
|
|
60
60
|
"type": "stdio",
|
|
61
61
|
"command": "npx",
|
|
62
|
-
"args": ["-y", "-p", "@finchagentic/mcp@4.
|
|
62
|
+
"args": ["-y", "-p", "@finchagentic/mcp@4.5.0", "finch-mcp"]
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -87,6 +87,7 @@ No LLM API key is required to start — 111 of 116 tools are plain reads/writes/
|
|
|
87
87
|
finch doctor # health check
|
|
88
88
|
finch setup # local vault / memory / providers
|
|
89
89
|
finch vault # inspect local vault
|
|
90
|
+
finch orders # schedule Robinhood Chain DCA / TP-SL order ticks
|
|
90
91
|
```
|
|
91
92
|
|
|
92
93
|
Try in your MCP client:
|
|
@@ -123,7 +124,7 @@ Default palette is `core` (lighter context). Full set:
|
|
|
123
124
|
Finch is the runtime. **Your LLM is the brain. Your data stays yours.**
|
|
124
125
|
|
|
125
126
|
```bash
|
|
126
|
-
npx -y -p @finchagentic/mcp@4.
|
|
127
|
+
npx -y -p @finchagentic/mcp@4.5.0 finch setup
|
|
127
128
|
# enable local vault (and optional local memory)
|
|
128
129
|
```
|
|
129
130
|
|
|
@@ -155,7 +156,7 @@ Scheduled/cloud features still need an account. Core memory, vault, and public-d
|
|
|
155
156
|
Guided setup:
|
|
156
157
|
|
|
157
158
|
```bash
|
|
158
|
-
npx -y -p @finchagentic/mcp@4.
|
|
159
|
+
npx -y -p @finchagentic/mcp@4.5.0 finch setup
|
|
159
160
|
```
|
|
160
161
|
|
|
161
162
|
## Security
|
|
@@ -164,7 +165,7 @@ npx -y -p @finchagentic/mcp@4.4.1 finch setup
|
|
|
164
165
|
|:-:|----------|------|
|
|
165
166
|
| 1 | Prompt injection | External content is data only — never instructions |
|
|
166
167
|
| 2 | Mainnet confirm | Estimate → preview → confirm → execute |
|
|
167
|
-
| 3 | Pinned install | Always `@finchagentic/mcp@4.
|
|
168
|
+
| 3 | Pinned install | Always `@finchagentic/mcp@4.5.0`, never `@latest` |
|
|
168
169
|
| 4 | Credential vault | Never paste secrets into prompts or third-party tools |
|
|
169
170
|
| 5 | Data disclosure | Know what leaves the machine (LLM, Firecrawl, GitHub, chain RPCs) |
|
|
170
171
|
| 6 | Server monitors | Scheduled jobs need explicit confirmation |
|
package/dist/cli.js
CHANGED
|
@@ -1127,6 +1127,138 @@ function vaultFlow() {
|
|
|
1127
1127
|
console.log(` ${C.cyan}git -C ${shortDir} init${C.reset} ${C.dim}# version-control it${C.reset}`);
|
|
1128
1128
|
console.log(` ${C.dim}Nothing leaves this machine unless you move it.${C.reset}\n`);
|
|
1129
1129
|
}
|
|
1130
|
+
// ── Robinhood Chain order scheduler ──────────────────────────────────────────
|
|
1131
|
+
//
|
|
1132
|
+
// rh_dca_create/rh_bracket_create (src/tools/rh-orders.ts) only ever write a
|
|
1133
|
+
// LOCAL pending order - nothing executes it. Only rh_orders_tick does, and
|
|
1134
|
+
// per that file's own header comment, "an always-on scheduler must call
|
|
1135
|
+
// rh_orders_tick {execute:true} periodically" - which this package never
|
|
1136
|
+
// actually set up. A user who creates a daily DCA and closes their laptop
|
|
1137
|
+
// got nothing, silently: no error, no warning, the order just sat there.
|
|
1138
|
+
// These three subcommands are that missing scheduler, reusing the existing
|
|
1139
|
+
// tick/lock/kill-switch logic as-is - "wire up the missing piece", not
|
|
1140
|
+
// "build order execution from scratch".
|
|
1141
|
+
async function runOrdersTick(execute) {
|
|
1142
|
+
const { handleRhOrderTool } = await Promise.resolve().then(() => __importStar(require("./tools/rh-orders.js")));
|
|
1143
|
+
const result = await handleRhOrderTool("rh_orders_tick", { execute });
|
|
1144
|
+
const text = result?.content?.[0]?.type === "text" ? result.content[0].text : "(no output)";
|
|
1145
|
+
return { text, isError: !!result?.isError };
|
|
1146
|
+
}
|
|
1147
|
+
function installOrdersScheduler() {
|
|
1148
|
+
// Version-pinned npx invocation, not a hardcoded path to this process's
|
|
1149
|
+
// own binary - matches this package's own "always pin the version, never
|
|
1150
|
+
// @latest" security guidance (README), and survives regardless of whether
|
|
1151
|
+
// the user got here via a global install or a one-off `npx -p`, whose
|
|
1152
|
+
// resolved path may not exist by the time the scheduler fires later.
|
|
1153
|
+
const invocation = `npx -y -p @finchagentic/mcp@${PKG_VERSION} finch orders tick --execute`;
|
|
1154
|
+
if (process.platform === "win32") {
|
|
1155
|
+
const taskName = "FinchOrdersTick";
|
|
1156
|
+
try {
|
|
1157
|
+
child_process.execSync(`schtasks /Create /TN "${taskName}" /TR "${invocation}" /SC MINUTE /MO 15 /F`, { stdio: "pipe" });
|
|
1158
|
+
console.log(`\n ${C.green}✓${C.reset} Registered Windows Task Scheduler task "${taskName}" - ticks every 15 min, survives reboots.`);
|
|
1159
|
+
console.log(` ${C.dim}Remove it:${C.reset} schtasks /Delete /TN "${taskName}" /F`);
|
|
1160
|
+
}
|
|
1161
|
+
catch (err) {
|
|
1162
|
+
console.error(` ${C.red}✗ schtasks failed: ${err.message}${C.reset}`);
|
|
1163
|
+
console.error(` ${C.dim}Try running as Administrator, or use \`finch orders daemon\` instead.${C.reset}\n`);
|
|
1164
|
+
process.exit(1);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
else {
|
|
1168
|
+
const logFile = path.join(os.homedir(), ".finch", "orders-tick.log");
|
|
1169
|
+
const line = `*/15 * * * * ${invocation} >> ${logFile} 2>&1`;
|
|
1170
|
+
try {
|
|
1171
|
+
const existing = (() => {
|
|
1172
|
+
try {
|
|
1173
|
+
return child_process.execSync("crontab -l", { stdio: ["pipe", "pipe", "ignore"] }).toString();
|
|
1174
|
+
}
|
|
1175
|
+
catch {
|
|
1176
|
+
return "";
|
|
1177
|
+
} // no crontab yet for this user - not an error
|
|
1178
|
+
})();
|
|
1179
|
+
if (existing.includes("finch orders tick")) {
|
|
1180
|
+
console.log(`\n ${C.yellow}○${C.reset} A finch orders tick entry already exists in crontab - not adding a duplicate.\n`);
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
const next = existing.trim().length > 0 ? `${existing.trim()}\n${line}\n` : `${line}\n`;
|
|
1184
|
+
child_process.execSync("crontab -", { input: next });
|
|
1185
|
+
console.log(`\n ${C.green}✓${C.reset} Added a crontab entry - ticks every 15 min, survives reboots.`);
|
|
1186
|
+
console.log(` ${C.dim}Remove it:${C.reset} crontab -e ${C.dim}(delete the finch orders line)${C.reset}`);
|
|
1187
|
+
console.log(` ${C.dim}Logs:${C.reset} ${logFile}`);
|
|
1188
|
+
}
|
|
1189
|
+
catch (err) {
|
|
1190
|
+
console.error(` ${C.red}✗ crontab failed: ${err.message}${C.reset}`);
|
|
1191
|
+
console.error(` ${C.dim}Try \`finch orders daemon\` instead.${C.reset}\n`);
|
|
1192
|
+
process.exit(1);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
console.log(` ${C.dim}Only the local wallet's own default key is needed for signing - set FINCH_WALLET_PASSPHRASE as a persistent system env var (not just your shell rc file) if you use one, since scheduled tasks don't inherit an interactive shell's environment.${C.reset}\n`);
|
|
1196
|
+
}
|
|
1197
|
+
async function ordersFlow() {
|
|
1198
|
+
const sub = process.argv[3];
|
|
1199
|
+
if (sub === "tick") {
|
|
1200
|
+
const execute = process.argv.includes("--execute");
|
|
1201
|
+
const { text, isError } = await runOrdersTick(execute);
|
|
1202
|
+
console.log(`\n${text}\n`);
|
|
1203
|
+
if (isError)
|
|
1204
|
+
process.exit(1);
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
if (sub === "daemon") {
|
|
1208
|
+
const intervalFlag = process.argv.indexOf("--interval");
|
|
1209
|
+
const intervalMinutes = intervalFlag !== -1 ? Number(process.argv[intervalFlag + 1]) : 15;
|
|
1210
|
+
if (!(intervalMinutes > 0)) {
|
|
1211
|
+
console.error(` ${C.red}✗ --interval must be a positive number of minutes${C.reset}\n`);
|
|
1212
|
+
process.exit(1);
|
|
1213
|
+
}
|
|
1214
|
+
console.log(`\n ${C.cyan}${C.bold}finch orders daemon${C.reset} ${C.dim}- ticking every ${intervalMinutes}m, Ctrl+C to stop${C.reset}`);
|
|
1215
|
+
console.log(` ${C.dim}Kill-switch: RH_ORDERS_DISABLED=1 or create ~/.finch/rh-orders.OFF${C.reset}`);
|
|
1216
|
+
console.log(` ${C.dim}Note: this only runs while this process stays alive - for something that${C.reset}`);
|
|
1217
|
+
console.log(` ${C.dim}survives reboots/terminal closure, use \`finch orders install-scheduler\` instead.${C.reset}\n`);
|
|
1218
|
+
let running = false; // skip a tick if the previous one is still in flight (slow RPC), don't queue up
|
|
1219
|
+
const tick = async () => {
|
|
1220
|
+
if (running)
|
|
1221
|
+
return;
|
|
1222
|
+
running = true;
|
|
1223
|
+
const ts = new Date().toISOString();
|
|
1224
|
+
try {
|
|
1225
|
+
const { text } = await runOrdersTick(true);
|
|
1226
|
+
console.log(` ${C.dim}[${ts}]${C.reset}`);
|
|
1227
|
+
console.log(text.split("\n").map((l) => ` ${l}`).join("\n") + "\n");
|
|
1228
|
+
}
|
|
1229
|
+
catch (err) {
|
|
1230
|
+
console.error(` ${C.red}[${ts}] tick error: ${err.message ?? err}${C.reset}\n`);
|
|
1231
|
+
}
|
|
1232
|
+
finally {
|
|
1233
|
+
running = false;
|
|
1234
|
+
}
|
|
1235
|
+
};
|
|
1236
|
+
await tick();
|
|
1237
|
+
const timer = setInterval(tick, intervalMinutes * 60000);
|
|
1238
|
+
const shutdown = () => {
|
|
1239
|
+
clearInterval(timer);
|
|
1240
|
+
console.log(`\n ${C.dim}Stopped.${C.reset}\n`);
|
|
1241
|
+
process.exit(0);
|
|
1242
|
+
};
|
|
1243
|
+
process.on("SIGINT", shutdown);
|
|
1244
|
+
process.on("SIGTERM", shutdown);
|
|
1245
|
+
return; // process stays alive via the interval timer
|
|
1246
|
+
}
|
|
1247
|
+
if (sub === "install-scheduler") {
|
|
1248
|
+
installOrdersScheduler();
|
|
1249
|
+
return;
|
|
1250
|
+
}
|
|
1251
|
+
console.log(`
|
|
1252
|
+
${C.cyan}${C.bold}finch orders${C.reset} ${C.dim}- Robinhood Chain DCA/TP-SL orders (rh_dca_create/rh_bracket_create)${C.reset}
|
|
1253
|
+
${C.dim}do nothing on their own until one of these is running - creating an order${C.reset}
|
|
1254
|
+
${C.dim}only ever writes it locally, nothing executes it automatically by itself.${C.reset}
|
|
1255
|
+
|
|
1256
|
+
${C.cyan}Commands:${C.reset}
|
|
1257
|
+
finch orders tick [--execute] Run one tick now and exit (preview by default)
|
|
1258
|
+
finch orders daemon [--interval N] Run in the foreground, ticking every N min (default 15)
|
|
1259
|
+
finch orders install-scheduler Register an OS-level recurring task (Task Scheduler / cron)
|
|
1260
|
+
`);
|
|
1261
|
+
}
|
|
1130
1262
|
// ── Entry point ───────────────────────────────────────────────────────────────
|
|
1131
1263
|
const cmd = process.argv[2];
|
|
1132
1264
|
if (cmd === "install") {
|
|
@@ -1158,6 +1290,12 @@ else if (cmd === "setup") {
|
|
|
1158
1290
|
else if (cmd === "vault") {
|
|
1159
1291
|
vaultFlow();
|
|
1160
1292
|
}
|
|
1293
|
+
else if (cmd === "orders") {
|
|
1294
|
+
ordersFlow().catch((err) => {
|
|
1295
|
+
console.error(` ${C.red}✗ orders error: ${err.message}${C.reset}`);
|
|
1296
|
+
process.exit(1);
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1161
1299
|
else if (cmd === "logout") {
|
|
1162
1300
|
const cfg = (0, config_js_1.readConfig)();
|
|
1163
1301
|
if (!cfg.sessionToken) {
|
|
@@ -1239,6 +1377,7 @@ else if (cmd === "help" || cmd === "--help" || cmd === "-h") {
|
|
|
1239
1377
|
finch doctor Run a full health check + suggest fixes
|
|
1240
1378
|
finch setup Configure your own LLM key and/or local memory + vault
|
|
1241
1379
|
finch vault Show your local vault (location, contents, backup)
|
|
1380
|
+
finch orders Run/schedule Robinhood Chain DCA & TP-SL order ticks
|
|
1242
1381
|
finch help Show this help
|
|
1243
1382
|
|
|
1244
1383
|
${C.dim}Claude Code / Cursor / Windsurf / Codex / Aeon / Antigravity / Zed — anywhere MCP runs.${C.reset}
|
package/dist/convex.js
CHANGED
|
@@ -28,7 +28,17 @@ async function attemptConvex(url, method, headers, body, timeoutMs = 30000) {
|
|
|
28
28
|
signal: AbortSignal.timeout(timeoutMs),
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
async function callConvex(path, method, body, toolName = "unknown", timeoutMs = 30000
|
|
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) {
|
|
32
42
|
const url = `${exports.CONVEX_SITE}${path}`;
|
|
33
43
|
const headers = { "Content-Type": "application/json" };
|
|
34
44
|
const apiKey = process.env.FINCH_API_KEY;
|
|
@@ -66,7 +76,8 @@ async function callConvex(path, method, body, toolName = "unknown", timeoutMs =
|
|
|
66
76
|
if (process.env.BANKR_API_KEY)
|
|
67
77
|
headers["X-User-Bankr-Key"] = process.env.BANKR_API_KEY;
|
|
68
78
|
let lastError = null;
|
|
69
|
-
|
|
79
|
+
const attempts = noRetry ? 1 : RETRY_DELAYS.length;
|
|
80
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
70
81
|
if (attempt > 0) {
|
|
71
82
|
await new Promise((r) => setTimeout(r, RETRY_DELAYS[attempt - 1]));
|
|
72
83
|
}
|
|
@@ -75,7 +86,14 @@ async function callConvex(path, method, body, toolName = "unknown", timeoutMs =
|
|
|
75
86
|
res = await attemptConvex(url, method, headers, body, timeoutMs);
|
|
76
87
|
}
|
|
77
88
|
catch (err) {
|
|
78
|
-
|
|
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;
|
|
79
97
|
continue;
|
|
80
98
|
}
|
|
81
99
|
if (res.status === 402) {
|
|
@@ -89,7 +107,7 @@ async function callConvex(path, method, body, toolName = "unknown", timeoutMs =
|
|
|
89
107
|
`Hint: ${b.hint || 'Add FINCH_SESSION_TOKEN=… to the env block in your MCP config'}\n\n` +
|
|
90
108
|
`${b.alternative ? `Alternative: ${b.alternative}` : ""}`);
|
|
91
109
|
}
|
|
92
|
-
if (RETRY_STATUSES.has(res.status) && attempt <
|
|
110
|
+
if (RETRY_STATUSES.has(res.status) && attempt < attempts - 1) {
|
|
93
111
|
// Capture the actual body so a deterministic error (e.g. "unknown
|
|
94
112
|
// token") that happens to come back on a 500 still surfaces its real
|
|
95
113
|
// message if retries exhaust - previously this discarded the body
|
|
@@ -99,6 +117,15 @@ async function callConvex(path, method, body, toolName = "unknown", timeoutMs =
|
|
|
99
117
|
lastError = new Error(`Finch API error ${res.status}: ${bodyText.slice(0, 300) || "(no body)"}`);
|
|
100
118
|
continue;
|
|
101
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
|
+
}
|
|
102
129
|
if (!res.ok)
|
|
103
130
|
throw new Error(`Finch API error: ${res.status} ${await res.text()}`);
|
|
104
131
|
return res.json();
|
package/dist/tools/agents.js
CHANGED
|
@@ -43,7 +43,7 @@ async function extractLearning(goal, priorUpdates, priorLearnings, latest) {
|
|
|
43
43
|
// the catch below swallows that into a silent skip. This early return just
|
|
44
44
|
// avoids building the prompt for a call we already know will fail.
|
|
45
45
|
const hasLLM = !!(process.env.BANKR_API_KEY || process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.GROK_API_KEY);
|
|
46
|
-
if (!hasLLM
|
|
46
|
+
if (!hasLLM) {
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
49
|
// Build the user prompt with all the context the model needs.
|
package/dist/tools/automation.js
CHANGED
|
@@ -301,7 +301,11 @@ async function handleAutomationTool(name, args) {
|
|
|
301
301
|
if (!parsed.success)
|
|
302
302
|
return { content: [{ type: "text", text: `Invalid input: automationId ${parsed.error.issues[0].message}` }], isError: true };
|
|
303
303
|
const { automationId, dryRun } = parsed.data;
|
|
304
|
-
|
|
304
|
+
// A real (non-dryRun) trigger moves funds if the automation is a
|
|
305
|
+
// swap/send - noRetry so a lost response never risks re-sending the
|
|
306
|
+
// same trigger. A dryRun call does nothing server-side, so retrying
|
|
307
|
+
// it is harmless and stays on the default retry behavior.
|
|
308
|
+
const data = await (0, convex_js_1.callConvex)("/automations/run", "POST", { automationId, dryRun: !!dryRun }, "run_automation", 30000, !dryRun);
|
|
305
309
|
if (data.error) {
|
|
306
310
|
const cat = categorizeError(data.error);
|
|
307
311
|
return {
|
package/dist/tools/rh-orders.js
CHANGED
|
@@ -143,8 +143,11 @@ exports.RH_ORDER_TOOLS = [
|
|
|
143
143
|
name: "rh_dca_create",
|
|
144
144
|
description: "Robinhood Chain — create a DCA plan: buy a fixed ETH amount of a token every N hours, " +
|
|
145
145
|
"up to a total number of buys, capped by maxSpendEth. Token by catalog symbol, crypto " +
|
|
146
|
-
"ticker, or 0x contract address (resolved via DexScreener). Does NOT execute now
|
|
147
|
-
"
|
|
146
|
+
"ticker, or 0x contract address (resolved via DexScreener). Does NOT execute now and does " +
|
|
147
|
+
"NOT run itself automatically — this only saves the plan. It fires only when something calls " +
|
|
148
|
+
"rh_orders_tick {execute:true}, which nothing does on its own. Tell the user to run " +
|
|
149
|
+
"`finch orders install-scheduler` (or `finch orders daemon`) after creating this, or the " +
|
|
150
|
+
"order will just sit there forever. Always confirm the resolved contract address first.",
|
|
148
151
|
inputSchema: {
|
|
149
152
|
type: "object",
|
|
150
153
|
properties: {
|
|
@@ -165,9 +168,11 @@ exports.RH_ORDER_TOOLS = [
|
|
|
165
168
|
{
|
|
166
169
|
name: "rh_bracket_create",
|
|
167
170
|
description: "Robinhood Chain — set take-profit and/or stop-loss on a token you HOLD. When DexScreener " +
|
|
168
|
-
"price crosses tpPriceUsd (≥) or slPriceUsd (≤), the
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
+
"price crosses tpPriceUsd (≥) or slPriceUsd (≤), sellPct% of the current balance sells for " +
|
|
172
|
+
"ETH — but only when something calls rh_orders_tick {execute:true}, which nothing does on " +
|
|
173
|
+
"its own by default. Tell the user to run `finch orders install-scheduler` (or `finch orders " +
|
|
174
|
+
"daemon`) after creating this, or the trigger will never actually fire. Provide at least one " +
|
|
175
|
+
"of tpPriceUsd / slPriceUsd. Only ever sells tokens already in the wallet — never borrows or shorts.",
|
|
171
176
|
inputSchema: {
|
|
172
177
|
type: "object",
|
|
173
178
|
properties: {
|
|
@@ -209,7 +214,9 @@ exports.RH_ORDER_TOOLS = [
|
|
|
209
214
|
description: "Robinhood Chain — evaluate all active orders and act on any that are due (DCA interval " +
|
|
210
215
|
"reached) or triggered (TP/SL price crossed). PREVIEW by default; pass execute:true to " +
|
|
211
216
|
"broadcast real swaps. Refuses to execute when the kill-switch is set (RH_ORDERS_DISABLED=1 " +
|
|
212
|
-
"or ~/.finch/rh-orders.OFF).
|
|
217
|
+
"or ~/.finch/rh-orders.OFF). Nothing calls this automatically — run `finch orders install-scheduler` " +
|
|
218
|
+
"(OS-level recurring task) or `finch orders daemon` (foreground loop) from a terminal to make " +
|
|
219
|
+
"orders actually fire unattended; calling this tool by hand only ticks once.",
|
|
213
220
|
inputSchema: {
|
|
214
221
|
type: "object",
|
|
215
222
|
properties: {
|
package/dist/tools/stake.js
CHANGED
|
@@ -261,7 +261,7 @@ async function handleStakeTool(name, args) {
|
|
|
261
261
|
isError: true,
|
|
262
262
|
};
|
|
263
263
|
}
|
|
264
|
-
const result = await (0, convex_js_1.callConvex)("/mcp/stake/stake", "POST", { amountWei: amountWei.toString(), lockTier }, "stake_finch");
|
|
264
|
+
const result = await (0, convex_js_1.callConvex)("/mcp/stake/stake", "POST", { amountWei: amountWei.toString(), lockTier }, "stake_finch", 30000, true);
|
|
265
265
|
if (result.error)
|
|
266
266
|
return { content: [{ type: "text", text: `Stake failed: ${result.error}` }], isError: true };
|
|
267
267
|
const tier = STAKING_TIERS[lockTier ?? 7];
|
|
@@ -309,7 +309,7 @@ async function handleStakeTool(name, args) {
|
|
|
309
309
|
}
|
|
310
310
|
const lines = [];
|
|
311
311
|
for (const id of targetIds) {
|
|
312
|
-
const result = await (0, convex_js_1.callConvex)("/mcp/stake/unstake", "POST", { stakeId: id }, "unstake_finch");
|
|
312
|
+
const result = await (0, convex_js_1.callConvex)("/mcp/stake/unstake", "POST", { stakeId: id }, "unstake_finch", 30000, true);
|
|
313
313
|
if (result.error) {
|
|
314
314
|
lines.push(`🔴 \`${id}\`: ${result.error}`);
|
|
315
315
|
}
|
|
@@ -330,7 +330,7 @@ async function handleStakeTool(name, args) {
|
|
|
330
330
|
const login = requireLogin();
|
|
331
331
|
if (!login)
|
|
332
332
|
return { content: [{ type: "text", text: NOT_LOGGED_IN_MSG }], isError: true };
|
|
333
|
-
const result = await (0, convex_js_1.callConvex)("/mcp/stake/claim-rewards", "POST", {}, "claim_vested_rewards");
|
|
333
|
+
const result = await (0, convex_js_1.callConvex)("/mcp/stake/claim-rewards", "POST", {}, "claim_vested_rewards", 30000, true);
|
|
334
334
|
if (result.error)
|
|
335
335
|
return { content: [{ type: "text", text: `Claim failed: ${result.error}` }], isError: true };
|
|
336
336
|
return {
|
package/package.json
CHANGED