@finchagentic/mcp 4.0.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.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +345 -0
  3. package/dist/_http-cache.js +96 -0
  4. package/dist/agent-loop.js +231 -0
  5. package/dist/annotations.js +113 -0
  6. package/dist/cli.js +1195 -0
  7. package/dist/clink-input.js +15 -0
  8. package/dist/config.js +132 -0
  9. package/dist/convex.js +151 -0
  10. package/dist/dex-pair.js +54 -0
  11. package/dist/enrichment-router.js +315 -0
  12. package/dist/index.js +256 -0
  13. package/dist/llm.js +323 -0
  14. package/dist/local-memory.js +102 -0
  15. package/dist/local-vault.js +454 -0
  16. package/dist/output-schemas.js +551 -0
  17. package/dist/prompts.js +111 -0
  18. package/dist/public-url.js +107 -0
  19. package/dist/resources.js +116 -0
  20. package/dist/server.js +300 -0
  21. package/dist/signal-gate.js +57 -0
  22. package/dist/token-decimals.js +26 -0
  23. package/dist/token-gate.js +88 -0
  24. package/dist/tool-filter.js +44 -0
  25. package/dist/tools/_solidity-scan.js +313 -0
  26. package/dist/tools/agents.js +729 -0
  27. package/dist/tools/automation.js +314 -0
  28. package/dist/tools/base-mcp.js +478 -0
  29. package/dist/tools/base.js +269 -0
  30. package/dist/tools/chronicle.js +268 -0
  31. package/dist/tools/coder.js +94 -0
  32. package/dist/tools/deep-research.js +1416 -0
  33. package/dist/tools/defi.js +291 -0
  34. package/dist/tools/equity.js +364 -0
  35. package/dist/tools/events.js +182 -0
  36. package/dist/tools/framework.js +150 -0
  37. package/dist/tools/github.js +514 -0
  38. package/dist/tools/insider.js +264 -0
  39. package/dist/tools/insight.js +634 -0
  40. package/dist/tools/market.js +555 -0
  41. package/dist/tools/memory.js +1046 -0
  42. package/dist/tools/miroshark.js +343 -0
  43. package/dist/tools/monitor.js +319 -0
  44. package/dist/tools/os.js +226 -0
  45. package/dist/tools/packets.js +296 -0
  46. package/dist/tools/research-chain.js +226 -0
  47. package/dist/tools/research-compare.js +280 -0
  48. package/dist/tools/research.js +188 -0
  49. package/dist/tools/rh-bridge.js +148 -0
  50. package/dist/tools/rh-mcp.js +1411 -0
  51. package/dist/tools/rh-orders.js +471 -0
  52. package/dist/tools/scanner.js +534 -0
  53. package/dist/tools/vault.js +764 -0
  54. package/dist/tools/wallet.js +200 -0
  55. package/dist/types.js +2 -0
  56. package/dist/wallet.js +184 -0
  57. package/package.json +87 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 noelclaw
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,345 @@
1
+ <div align="center">
2
+
3
+ <!-- Hero Banner SVG (self-contained, no external image) -->
4
+ <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAwIiBoZWlnaHQ9IjMwMCIgdmlld0JveD0iMCAwIDEyMDAgMzAwIj4KICA8ZGVmcz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iYmciIHgxPSIwIiB5MT0iMCIgeDI9IjAiIHkyPSIxIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojMGEwYTBhO3N0b3Atb3BhY2l0eToxIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iMSIgc3R5bGU9InN0b3AtY29sb3I6IzFhMWEyNTtzdG9wLW9wYWNpdHk6MSIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudCBpZD0iZ2xvdyIgY3g9IjUwJSIgY3k9IjUwJSIgcj0iNTAlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdHlsZT0ic3RvcC1jb2xvcjojMjU2M0VCO3N0b3Atb3BhY2l0eTowLjMiLz4KICAgICAgPHN0b3Agb2Zmc2V0PSIxIiBzdHlsZT0ic3RvcC1jb2xvcjojMjU2M0VCO3N0b3Atb3BhY2l0eTowIi8+CiAgICA8L3JhZGlhbEdyYWRpZW50PgogIDwvZGVmcz4KICA8cmVjdCB3aWR0aD0iMTIwMCIgaGVpZ2h0PSIzMDAiIGZpbGw9InVybCgjYmcpIi8+CiAgPGNpcmNsZSBjeD0iNjAwIiBjeT0iMTUwIiByPSIyMDAiIGZpbGw9InVybCgjZ2xvdykiLz4KICA8dGV4dCB4PSI2MDAiIHk9IjEyMCIgZm9udC1mYW1pbHk9InN5c3RlbS11aSwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSI1NiIgZm9udC13ZWlnaHQ9IjgwMCIgZmlsbD0iI2YwZjZmYyIgdGV4dC1hbmNob3I9Im1pZGRsZSIgbGV0dGVyLXNwYWNpbmc9Ii0wLjAzZW0iPk5vZWxDbGF3PC90ZXh0PgogIDx0ZXh0IHg9IjYwMCIgeT0iMTY1IiBmb250LWZhbWlseT0ic3lzdGVtLXVpLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjIwIiBmb250LXdlaWdodD0iNDAwIiBmaWxsPSIjOTNjNWZkIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5UaGUgcnVudGltZSBsYXllciBmb3IgQWdlbnRpYyBBSTwvdGV4dD4KICA8dGV4dCB4PSI2MDAiIHk9IjE5NSIgZm9udC1mYW1pbHk9InN5c3RlbS11aSwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgZm9udC13ZWlnaHQ9IjQwMCIgZmlsbD0iIzY0NzQ4YiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+MTIxIHRvb2xzIOKAlCBwZXJzaXN0ZW50IG1lbW9yeSDigJQgYWdlbnRzIOKAlCB3b3JrZmxvd3Mg4oCUIERlRmkgb24gQmFzZTwvdGV4dD4KPC9zdmc+" alt="Finch" width="100%">
5
+
6
+ </div>
7
+
8
+ ---
9
+
10
+ <div align="center">
11
+
12
+ # The runtime layer for Agentic AI.
13
+
14
+ **Your AI remembers, keeps working, and survives every session.**
15
+
16
+ </div>
17
+
18
+ ---
19
+
20
+ > Most AI assistants disappear when the conversation ends. Finch gives them persistent state — memory that accumulates, agents that keep running, vaults that version knowledge, and workflows that continue after you close the chat.
21
+
22
+ ## Table of Contents
23
+
24
+ - [What's New](#whats-new)
25
+ - [Three Pillars](#three-pillars)
26
+ - [Install](#install)
27
+ - [In Practice](#in-practice)
28
+ - [Configuration](#configuration)
29
+ - [Security](#security-boundaries)
30
+ - [Comparison](#why-this-is-different)
31
+ - [Troubleshooting](#troubleshooting)
32
+ - [Links](#links)
33
+
34
+ ---
35
+
36
+ ## What's New
37
+
38
+ | Feature | Description |
39
+ |---------|-------------|
40
+ | **🔒 Fully local** | Run the whole runtime on your own machine — **vault + memory on your own disk** (versioned, encrypted, no account), wallet keys local, your LLM does the thinking. Nothing phones home. `finch setup` to enable, `finch vault` to inspect. → [Run it fully local](#run-it-fully-local) |
41
+ | **Local Memory** | Run memory tools on a free, self-hosted [supermemory](https://github.com/supermemoryai/supermemory) server on your own machine — zero cost, private, no Finch account needed. `finch setup` to enable. |
42
+ | **OpenAI BYOK** | OpenAI joins Bankr/Anthropic/Grok as a direct LLM provider. `OPENAI_BASE_URL` also lets you point at any self-hosted OpenAI-compatible gateway (LiteLLM, vLLM, Ollama, OpenRouter, your own VPS). |
43
+ | **`finch setup`** | New guided CLI wizard — pick an LLM provider and/or enable local memory in one flow. |
44
+ | **Finch Terminal** | Tool calling from chat — spawn agents, save to vault, search memory, estimate + execute swaps, create automations. All from a single prompt. |
45
+ | **`execute_swap`** | Execute token swaps on Base mainnet from Finch Terminal. Enforces estimate → preview → confirm → execute flow. Routes via 0x Permit2. |
46
+ | **7 Agents** | Noel (AI OS), CoinGecko (market data), Sage (research), Forge (code), Quill (creative), Spectre (trading), Atlas (general) |
47
+ | **Multi-Provider Chat** | Bankr → Anthropic → OpenAI → Grok → Finch proxy fallback |
48
+ | **ConnectMcpModal** | Onboarding flow: auto-generate API key + copy install command from webapp |
49
+ | **Security Hardened** | 8 security boundaries, wallet decrypt-failure protection, 4 other vulnerability fixes (auth, OTP, private key) |
50
+ | **Knowledge Graph** | Vault entries link into a typed graph (`references`, `derived_from`, `supersedes`, `related`, `continues`) — auto-built from `[[wikilinks]]` + `#tags`, with backlinks. Data layer only for now; visual graph is planned. |
51
+ | **Ecosystem** | CI/CD, CodeQL, Dependabot, Husky, Dockerfile, coverage reporting, semantic release, TypeDoc |
52
+
53
+ ---
54
+
55
+ ## Three Pillars
56
+
57
+ <table>
58
+ <tr>
59
+ <td width="33%" valign="top">
60
+
61
+ ### Memory
62
+ Semantic, versioned, deduplicated.
63
+
64
+ Your AI remembers what you told it last week, last month, in a different session — and ranks recent context above stale notes via 90-day half-life decay. Run `finch setup` to switch to a free, self-hosted local backend instead of the Finch-hosted proxy.
65
+
66
+ ```bash
67
+ remember: I prefer conservative DeFi strategies, max 5% APY
68
+ → ✓ saved to memory
69
+ auto-loaded in future sessions
70
+ ```
71
+
72
+ </td>
73
+ <td width="33%" valign="top">
74
+
75
+ ### Agents
76
+ Named, persistent, identity-bound.
77
+
78
+ Spawn an agent with a goal, recall it weeks later, audit every state change. Each agent can hold its own Base wallet address.
79
+
80
+ ```bash
81
+ spawn an agent called market-researcher
82
+ goal: track Base chain protocols weekly
83
+ → 🤖 agent spawned
84
+ recall anytime with agent_recall
85
+ ```
86
+
87
+ </td>
88
+ <td width="33%" valign="top">
89
+
90
+ ### Workflows
91
+ Packets, automations, monitors, deep research.
92
+
93
+ Anything that runs on a schedule or continues after the chat ends.
94
+
95
+ ```bash
96
+ set up a daily monitor for
97
+ AI agent infrastructure news
98
+ → ✓ monitor created
99
+ runs daily 08:00 UTC
100
+ findings auto-saved to vault
101
+ ```
102
+
103
+ </td>
104
+ </tr>
105
+ </table>
106
+
107
+ ---
108
+
109
+ ## Install
110
+
111
+ ### One-command auto-install (any MCP client)
112
+ ```bash
113
+ npx -y -p @finchagentic/mcp@4.0.0 finch install
114
+ ```
115
+ > Detects Claude Desktop, Cursor, Windsurf, VS Code, and Zed, and configures each automatically. **Claude Code** is configured with the dedicated `claude mcp add` command below (its config lives outside the desktop-app path this scan checks).
116
+
117
+ ### Claude Code
118
+ ```bash
119
+ claude mcp add finch -s user -- npx -y -p @finchagentic/mcp@4.0.0 finch-mcp
120
+ ```
121
+
122
+ ### Cursor / Windsurf / Claude Desktop
123
+ ```json
124
+ {
125
+ "mcpServers": {
126
+ "finch": {
127
+ "command": "npx",
128
+ "args": ["-y", "-p", "@finchagentic/mcp@4.0.0", "finch-mcp"]
129
+ }
130
+ }
131
+ }
132
+ ```
133
+
134
+ ### VS Code
135
+ `mcp.json` uses the `servers` key (not `mcpServers`), and each entry needs `"type": "stdio"`:
136
+ ```json
137
+ {
138
+ "servers": {
139
+ "finch": {
140
+ "type": "stdio",
141
+ "command": "npx",
142
+ "args": ["-y", "-p", "@finchagentic/mcp@4.0.0", "finch-mcp"]
143
+ }
144
+ }
145
+ }
146
+ ```
147
+
148
+ ### Zed
149
+ In `settings.json` under `context_servers` (each entry needs `"source": "custom"`):
150
+ ```json
151
+ {
152
+ "context_servers": {
153
+ "finch": {
154
+ "source": "custom",
155
+ "command": "npx",
156
+ "args": ["-y", "-p", "@finchagentic/mcp@4.0.0", "finch-mcp"]
157
+ }
158
+ }
159
+ }
160
+ ```
161
+
162
+ <details>
163
+ <summary>Config file paths</summary>
164
+
165
+ | Client | Path |
166
+ |--------|------|
167
+ | Claude Desktop (Mac) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
168
+ | Claude Desktop (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
169
+ | Cursor | `.cursor/mcp.json` |
170
+ | Windsurf | `~/.codeium/windsurf/mcp_config.json` |
171
+ | Zed | `.config/zed/settings.json` |
172
+ | VS Code | `.vscode/mcp.json` |
173
+
174
+ </details>
175
+
176
+ > No LLM API key required — not to start, and not for any tool. Tools load on first use.
177
+
178
+ > **Always pin the version** (`@finchagentic/mcp@4.0.0`, never `@latest`) — this MCP has wallet, credential, and backend persistence capabilities. See [Security Boundaries](#security-boundaries).
179
+
180
+ ---
181
+
182
+ ## Run it fully local
183
+
184
+ Finch is the runtime; **your LLM is the brain, and your data stays yours.** You can run the whole thing on your own machine — no Finch account, no cloud, nothing leaving your laptop.
185
+
186
+ **Turn it on:**
187
+ ```bash
188
+ npx -y -p @finchagentic/mcp@4.0.0 finch setup
189
+ # → answer "y" to "Enable local vault" (and, optionally, local memory)
190
+ ```
191
+
192
+ **What runs local:**
193
+
194
+ | Piece | Where it lives | Notes |
195
+ |-------|----------------|-------|
196
+ | **Vault** | `~/.finch/vault/` | Versioned artifacts + knowledge graph. Credentials AES-256-GCM encrypted. Plain files — copy, `git`, or sync them anywhere. |
197
+ | **Memory** | self-hosted [supermemory](https://github.com/supermemoryai/supermemory) | Semantic recall on your machine. Optional; without it, vault search falls back to local full-text. |
198
+ | **Wallet** | `~/.finch/wallet.json` | Keys never leave your machine. |
199
+ | **The brain** | your MCP client's model | Claude Code, Cursor, etc. **No BYOK LLM key needed** — the model is already yours. |
200
+ | **Public-data tools** | direct API calls | Market, scanner, SEC, GitHub, Robinhood Chain reads — keyless from day one. |
201
+
202
+ **Your data is a plain folder.** Back it up with `cp`, version it with `git`, sync it however you like — it never syncs anywhere on its own.
203
+
204
+ ```bash
205
+ finch vault # where it is, what's in it, how to back it up
206
+ finch doctor # confirm "Local vault: on" and everything else
207
+ ```
208
+
209
+ **What still needs an account** (inherently server-side, can't be local): scheduled/cron agents, cross-device sync, and the community marketplace. Everything else works with zero sign-in.
210
+
211
+ ---
212
+
213
+ ## In Practice
214
+
215
+ ```
216
+ > what have you found so far on AI agent infrastructure?
217
+ → Pulls from vault: 3 reports across 7 days · summarizes key themes
218
+
219
+ > give me a bull vs bear thesis on ETH, save it
220
+ → Full analysis written + auto-saved to vault as v1
221
+
222
+ > swap 50 USDC to ETH
223
+ → [estimate_swap] Quote: 0.027 ETH · slippage 0.5% · gas ~$0.03
224
+ → Confirm swap? (yes/no)
225
+ → [execute_swap confirmed=true]
226
+ → ✅ Swap executed · tx 0xabc... · view on Basescan
227
+
228
+ > spawn an agent to track Base DeFi weekly
229
+ → 🤖 Agent 'base-tracker' created · runs every Monday 09:00 UTC
230
+ ```
231
+
232
+ ---
233
+
234
+ ## 121 Tools Across the Runtime
235
+
236
+ | Pillar | Categories | Count |
237
+ |--------|-----------|:-----:|
238
+ | Memory | Memory · Vault · Chronicle | 29 |
239
+ | Agents | Agents · Hire | 12 |
240
+ | Workflows | Automation · Monitors · Packets · Deep Research · Research Compare/Chain · OS | 19 |
241
+ | Execution | Base DeFi (base_mcp_*) · Robinhood Chain (rh_*) · Stocks (SEC) · Market · Scanner · Web · GitHub · Code Audit · Wallet | 61 |
242
+
243
+ > Run `finch doctor` for a 5-second health check showing exactly what's wired and what isn't.
244
+
245
+ ---
246
+
247
+ ## Configuration
248
+
249
+ <details>
250
+ <summary>Environment Variables (click to expand)</summary>
251
+
252
+ **No LLM key is required — for any tool.** Tools reach the network, read chains, hold state and execute
253
+ transactions, then hand the result back to *your* client's model to reason over. None of them run inference of
254
+ their own, so none of them can be broken by a missing key.
255
+
256
+ A key makes Finch a *host* rather than a set of hands. That is only three things:
257
+
258
+ - `finch run` — the CLI agent loop, which has no client model to borrow
259
+ - **scheduled / cron agents** — they wake with no session attached
260
+ - `deep_research mode:"report"` — opt-in server-written prose; the default `mode:"sources"` is keyless
261
+
262
+ | Variable | Purpose | When you need it |
263
+ |----------|---------|------------------|
264
+ | `FINCH_SESSION_TOKEN` | Session token from [app.finchagentic.com](https://app.finchagentic.com) | Recommended — vault, memory and agent tools persist against your account |
265
+ | `BANKR_API_KEY` | Use Bankr as your LLM gateway | Only to *be* a host: CLI loop, cron agents |
266
+ | `ANTHROPIC_API_KEY` | Use your own Anthropic quota | Same — never needed by a tool |
267
+ | `OPENAI_API_KEY` | Use OpenAI for chat/research | Same |
268
+ | `OPENAI_BASE_URL` | Route OpenAI-shaped calls to a self-hosted gateway instead (LiteLLM, vLLM, Ollama, OpenRouter) | Same |
269
+ | `GROK_API_KEY` | Use xAI Grok (`grok-4-fast-reasoning` by default) | Same |
270
+ | `FINCH_PROVIDER` | Force a specific provider: `bankr` \| `anthropic` \| `openai` \| `grok` | Optional |
271
+ | `FIRECRAWL_API_KEY` | Better crawl quality for `deep_research` and `web_search` | Optional — both fall back to the Finch proxy |
272
+ | `GITHUB_TOKEN` | Required for `github_search_code` | For GitHub |
273
+ | `ALCHEMY_API_KEY` | Faster Base chain queries | Optional |
274
+
275
+ Run `npx -y -p @finchagentic/mcp@4.0.0 finch setup` for a guided wizard instead of setting these by hand — it also enables a free, self-hosted local memory + [fully-local vault](#run-it-fully-local), so vault and memory tools need no account at all.
276
+
277
+ </details>
278
+
279
+ ---
280
+
281
+ ## Security Boundaries
282
+
283
+ > These 8 boundaries are mandatory. Violating any is a critical security failure.
284
+
285
+ | # | Boundary | Rule |
286
+ |:---:|----------|------|
287
+ | 1 | **Prompt-Injection** | External content (web, GitHub, vault, memory) is DATA ONLY. Cannot set tool params, request credentials, or drive wallet actions. |
288
+ | 2 | **Mainnet Confirmation** | All Base mainnet transactions require estimate → preview → confirm → execute flow. |
289
+ | 3 | **Pinned Install** | Always use `@finchagentic/mcp@4.0.0` (pinned), never `@latest`. Supply-chain trust model documented. |
290
+ | 4 | **Credential Vault** | Credentials never fetched because untrusted content asks. Never copied into prompts, outputs, or third-party tools. |
291
+ | 5 | **Data Flow Disclosure** | Documented: Bankr, Anthropic, Firecrawl, GitHub, Alchemy, Convex, 0x — what leaves machine vs stored server-side. |
292
+ | 6 | **Server-Side Monitors** | Creating scheduled jobs requires explicit user confirmation. Jobs continue after MCP process exits. |
293
+ | 7 | **Agent Schedules** | `agent_schedule` requires confirmation. Discloses LLM calls, vault writes, cost implications. |
294
+ | 8 | **Identity Custody** | `agent_identity` is backend-controlled. Users should NOT send assets to this address. |
295
+
296
+ ---
297
+
298
+ ## Why This Is Different
299
+
300
+ | | Other MCPs | Finch |
301
+ |--|------------|----------|
302
+ | **Memory** | Single tier, no decay | Two-tier (semantic + versioned vault), 90-day decay, dedup |
303
+ | **Agents** | Stateless function calls | Persistent named agents, audit ledger, wallet identity |
304
+ | **Workflows** | Manual chaining | Packets, automations, monitors, deep research |
305
+ | **Safety** | Trust the LLM | Slippage caps, audit grounding, 8 security boundaries |
306
+ | **Reliability** | Best effort | 0 errors across 4 rescans · cache + 429 backoff |
307
+
308
+ ---
309
+
310
+ ## Troubleshooting
311
+
312
+ | Problem | Fix |
313
+ |---------|-----|
314
+ | Tools not appearing | Restart your MCP client after adding the config |
315
+ | Old version loading | `npx clear-npx-cache` then restart |
316
+ | `web_search` fails | Set `FIRECRAWL_API_KEY` |
317
+ | Swap refused | Price impact exceeded cap — call `estimate_swap` first |
318
+ | Rate limit (429) | Auto-retries with backoff — no action needed |
319
+ | Diagnose anything | `finch doctor` |
320
+
321
+ ---
322
+
323
+ ## Links
324
+
325
+ | | |
326
+ | ---------- | ------------------------------------------------------------------------------ |
327
+ | **App** | [app.finchagentic.com](https://app.finchagentic.com) |
328
+ | **Docs** | [docs.finch.fun](https://docs.finch.fun) |
329
+ | **npm** | [npmjs.com/package/@finchagentic/mcp](https://www.npmjs.com/package/@finchagentic/mcp) |
330
+ | **GitHub** | [github.com/finch/mcp](https://github.com/finch/mcp) |
331
+ | **X** | [@finch](https://x.com/finch) |
332
+
333
+ ---
334
+
335
+ <div align="center">
336
+
337
+ ### Star History
338
+
339
+ [![Star History Chart](https://api.star-history.com/svg?repos=finch/mcp&type=Date)](https://star-history.com/#finch/mcp&Date)
340
+
341
+ ---
342
+
343
+ **MIT License** · Built with by the Finch team
344
+
345
+ </div>
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ // Shared cache + 429-backoff wrapper for external HTTP calls.
3
+ // Designed for read-heavy public APIs like CoinGecko (free tier: 30 req/min)
4
+ // and DexScreener - agent loops + parallel tool calls were tripping rate
5
+ // limits in production. Cache hit returns the prior body without a network
6
+ // round-trip; cache miss does a fetch with bounded retries on 429/503.
7
+ //
8
+ // The cache is in-process only - every MCP server process keeps its own
9
+ // LRU. That's intentional: tokens get fresh data on cold start, no shared
10
+ // state to invalidate across users.
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.cachedFetch = cachedFetch;
13
+ exports.clearHttpCache = clearHttpCache;
14
+ exports.httpCacheStats = httpCacheStats;
15
+ const DEFAULT_TTL_MS = 45000; // 45s - fresh enough for prices, generous enough to absorb a flurry
16
+ const DEFAULT_MAX_ENTRIES = 200;
17
+ const DEFAULT_RETRY_DELAYS_MS = [500, 1500, 4000];
18
+ const cache = new Map();
19
+ function cacheKey(url, init) {
20
+ // POST bodies are part of the key so two POSTs with different params don't collide.
21
+ if (!init || !init.body || init.method === "GET")
22
+ return `GET ${url}`;
23
+ return `${init.method ?? "POST"} ${url} ${typeof init.body === "string" ? init.body : ""}`;
24
+ }
25
+ function evictExpired() {
26
+ const now = Date.now();
27
+ for (const [k, v] of cache) {
28
+ if (v.expiresAt < now)
29
+ cache.delete(k);
30
+ }
31
+ // LRU-ish eviction - Map preserves insertion order, so the first keys are oldest.
32
+ while (cache.size > DEFAULT_MAX_ENTRIES) {
33
+ const firstKey = cache.keys().next().value;
34
+ if (firstKey === undefined)
35
+ break;
36
+ cache.delete(firstKey);
37
+ }
38
+ }
39
+ async function cachedFetch(url, init = {}, opts = {}) {
40
+ const ttl = opts.ttlMs ?? DEFAULT_TTL_MS;
41
+ const retryDelays = opts.retryDelaysMs ?? DEFAULT_RETRY_DELAYS_MS;
42
+ const timeout = opts.timeoutMs ?? 15000;
43
+ evictExpired();
44
+ const key = cacheKey(url, init);
45
+ if (!opts.bypassCache) {
46
+ const hit = cache.get(key);
47
+ if (hit && hit.expiresAt > Date.now()) {
48
+ // Refresh recency - re-insert moves it to the end of the Map.
49
+ cache.delete(key);
50
+ cache.set(key, hit);
51
+ return { ok: hit.status >= 200 && hit.status < 300, status: hit.status, text: hit.body, fromCache: true };
52
+ }
53
+ }
54
+ let lastStatus = 0;
55
+ let lastText = "";
56
+ for (let attempt = 0; attempt <= retryDelays.length; attempt++) {
57
+ try {
58
+ const res = await fetch(url, { ...init, signal: AbortSignal.timeout(timeout) });
59
+ const text = await res.text();
60
+ lastStatus = res.status;
61
+ lastText = text;
62
+ // Cache successful responses + 404s (404 is "definitively not found" - no point retrying).
63
+ if (res.ok || res.status === 404) {
64
+ cache.set(key, { body: text, status: res.status, expiresAt: Date.now() + ttl });
65
+ return { ok: res.ok, status: res.status, text, fromCache: false };
66
+ }
67
+ // Retry on 429 (rate limit) and 5xx (transient server errors).
68
+ if (res.status === 429 || res.status >= 500) {
69
+ const delay = retryDelays[attempt];
70
+ if (delay === undefined)
71
+ break;
72
+ // Honor server's Retry-After if provided (CoinGecko sends this).
73
+ const retryAfter = res.headers.get("retry-after");
74
+ const waitMs = retryAfter ? Math.min(parseInt(retryAfter) * 1000, 30000) : delay;
75
+ await new Promise((r) => setTimeout(r, waitMs));
76
+ continue;
77
+ }
78
+ // Non-retryable client error (400/401/403) - surface to caller without retry.
79
+ return { ok: false, status: res.status, text, fromCache: false };
80
+ }
81
+ catch (err) {
82
+ lastText = err instanceof Error ? err.message : String(err);
83
+ const delay = retryDelays[attempt];
84
+ if (delay === undefined)
85
+ break;
86
+ await new Promise((r) => setTimeout(r, delay));
87
+ }
88
+ }
89
+ return { ok: false, status: lastStatus, text: lastText, fromCache: false };
90
+ }
91
+ function clearHttpCache() {
92
+ cache.clear();
93
+ }
94
+ function httpCacheStats() {
95
+ return { size: cache.size, maxEntries: DEFAULT_MAX_ENTRIES };
96
+ }