mcp: serveur MCP officiel hfmarketdata-mcp (14 outils, 2 ressources, 3 prompts, stdio) + tests vitest + tarball téléchargeable
- TypeScript, @modelcontextprotocol/sdk + zod, fetch natif, Node >= 20
- outils : search_symbols, get_bars, get_futures_contracts, get_futures_chain, get_continuous, get_term_structure, get_options_chain, get_coverage, get_financial_statements, get_ratios, get_ratios_daily, screen_fundamentals, get_filings, subscribe_filings (websocket borné)
- sorties compactes {columns,rows}, résumé tête/queue au-delà de 200 lignes, en-têtes X-RateLimit-* et 429 explicités, erreurs uniformes
- README vitrine (Claude Code / Cursor / Codex / Claude Desktop), guide d'enregistrement de la démo, smoke test live
- hfmarketdata/web/public/downloads/hfmarketdata-mcp-1.0.0.tgz (npm pack) servi par le SPA fallback
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
25 changed files +4,926 −0
added
hfmarketdata/web/public/downloads/.gitignore
+4 −0
@@ -0,0 +1,4 @@ | ||
| 1 | +# Distributables served at https://www.hfmarketdata.io/downloads/ — committed on purpose | |
| 2 | +# (the repository root ignores *.zip for data archives; re-include ours here). | |
| 3 | +!*.zip | |
| 4 | +!*.tgz | |
added
hfmarketdata/web/public/downloads/hfmarketdata-mcp-1.0.0.tgz
+0 −0
Binary file not shown.
added
mcp/.gitignore
+3 −0
@@ -0,0 +1,3 @@ | ||
| 1 | +node_modules/ | |
| 2 | +dist/ | |
| 3 | +*.tgz | |
added
mcp/LICENSE
+21 −0
@@ -0,0 +1,21 @@ | ||
| 1 | +MIT License | |
| 2 | + | |
| 3 | +Copyright (c) 2026 Simon-Pierre Boucher | |
| 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. | |
added
mcp/README.md
+185 −0
@@ -0,0 +1,185 @@ | ||
| 1 | +<p align="center"> | |
| 2 | + <img src="docs/demo.gif" alt="hfmarketdata-mcp demo — asking Claude Code for the CL term structure" width="820" /> | |
| 3 | +</p> | |
| 4 | + | |
| 5 | +<h1 align="center">hfmarketdata-mcp</h1> | |
| 6 | + | |
| 7 | +<p align="center"> | |
| 8 | + The official <a href="https://modelcontextprotocol.io">MCP</a> server for <a href="https://www.hfmarketdata.io">HF Market Data</a> — | |
| 9 | + 1-minute to daily bars for stocks, ETFs, futures, crypto, indices and FX since 2007, individual futures contracts, custom continuous series, | |
| 10 | + term structures, options chains with Greeks and point-in-time SEC fundamentals, straight into Claude Code, Cursor, Codex or any MCP client. | |
| 11 | +</p> | |
| 12 | + | |
| 13 | +<p align="center"> | |
| 14 | + <a href="https://www.npmjs.com/package/hfmarketdata-mcp"><img alt="npm" src="https://img.shields.io/npm/v/hfmarketdata-mcp?color=5ee7a5&label=npm" /></a> | |
| 15 | + <img alt="node" src="https://img.shields.io/badge/node-%E2%89%A5%2020-5ee7a5" /> | |
| 16 | + <img alt="MCP" src="https://img.shields.io/badge/MCP-stdio-37b3ff" /> | |
| 17 | + <img alt="tools" src="https://img.shields.io/badge/tools-14-37b3ff" /> | |
| 18 | + <img alt="tests" src="https://img.shields.io/badge/vitest-45%20passing-5ee7a5" /> | |
| 19 | + <a href="./LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-lightgrey" /></a> | |
| 20 | +</p> | |
| 21 | + | |
| 22 | +--- | |
| 23 | + | |
| 24 | +## Quickstart (60 seconds) | |
| 25 | + | |
| 26 | +```bash | |
| 27 | +# 1. Install (pick one) | |
| 28 | +npm i -g hfmarketdata-mcp # from npm (once published) | |
| 29 | +npm i -g https://www.hfmarketdata.io/downloads/hfmarketdata-mcp-1.0.0.tgz # direct tarball, works today | |
| 30 | + | |
| 31 | +# 2. Check the connection (keyless works out of the box: 30 requests/hour) | |
| 32 | +hfmarketdata-mcp --selftest | |
| 33 | +# OK https://www.hfmarketdata.io (312 ms, keyless) — datasets: stock, etf, futures, futures_contracts, crypto, index, fx, options | |
| 34 | + | |
| 35 | +# 3. Add it to Claude Code | |
| 36 | +claude mcp add hfmarketdata -e HFMD_API_KEY=hfmd_live_… -- npx -y hfmarketdata-mcp | |
| 37 | +``` | |
| 38 | + | |
| 39 | +Then just ask: | |
| 40 | + | |
| 41 | +> *"Plot me the CL term structure"* · *"Compare ESZ25 and ESH26 over 30 days"* · *"Screen US stocks with PE<15 and FCF yield>6% and show their last 3 quarters"* | |
| 42 | + | |
| 43 | +A free account (`https://www.hfmarketdata.io/signup`) gives you an API key and **120 requests / minute** instead of 30 / hour. Set it as `HFMD_API_KEY`; the server never logs it. | |
| 44 | + | |
| 45 | +## Tools | |
| 46 | + | |
| 47 | +| Tool | What it does | Backed by | | |
| 48 | +|---|---|---| | |
| 49 | +| `search_symbols` | Find tickers (stock/etf/crypto/index/fx), futures roots or optionable underlyings | `/v1/{asset}/tickers`, `/v1/futures/roots`, `/v1/options/tickers` | | |
| 50 | +| `get_bars` | OHLCV bars 1min…1day for one or many symbols; vendor continuous futures; individual contracts (`ESZ25`) | `/v1/bars/{asset}/{ticker}`, `/v1/bars/{asset}?tickers=`, `/v1/futures/contract/{symbol}/bars` | | |
| 51 | +| `get_futures_contracts` | Every expiration of a root with expiry / FND / status / volume / OI | `/v1/futures/{root}/contracts` | | |
| 52 | +| `get_futures_chain` | Listed contracts as of a date, front month first | `/v1/futures/{root}/chain` | | |
| 53 | +| `get_continuous` | Server-built continuous series: `roll=volume\|open_interest\|calendar`, `adjust=none\|back_adjusted\|ratio`, `depth` | `/v1/futures/{root}/continuous` | | |
| 54 | +| `get_term_structure` | The curve on a date (prices, spreads, OI) — contango / backwardation | `/v1/futures/{root}/term-structure` | | |
| 55 | +| `get_options_chain` | EOD chain with IV and Greeks, filters by expiry / strikes / side; `list_expirations` | `/v1/options/chain/{t}`, `/v1/options/expirations/{t}` | | |
| 56 | +| `get_coverage` | What exists for a contract or a ticker's fundamentals, gaps included | `/v1/futures/contract/{s}/coverage`, `/v1/fundamentals/{t}/coverage` | | |
| 57 | +| `get_financial_statements` | Income / balance / cash-flow, annual or quarterly, point-in-time; single XBRL fact history with `concept` | `/v1/fundamentals/{t}/statements`, `/v1/fundamentals/{t}/facts/{concept}` | | |
| 58 | +| `get_ratios` | Latest P/E, P/B, EV/EBITDA, FCF yield, ROE, margins, leverage… | `/v1/fundamentals/{t}/ratios` | | |
| 59 | +| `get_ratios_daily` | Daily ratio history recomputed with the fundamentals known that day | `/v1/fundamentals/{t}/ratios/daily` | | |
| 60 | +| `screen_fundamentals` | `filters="pe<15,roe>0.15,fcf_yield>0.06"` + `sort="fcf_yield:desc"` (+ `as_of`) | `/v1/fundamentals/screener` | | |
| 61 | +| `get_filings` | 10-K / 10-Q / 8-K / 4 / 13F… with URLs | `/v1/fundamentals/{t}/filings` | | |
| 62 | +| `subscribe_filings` | Opens `wss://…/v1/stream`, subscribes to `filings`, returns up to N messages within a bounded time window | websocket | | |
| 63 | + | |
| 64 | +**Resources:** `hfmarketdata://status` (live dataset inventory) · `hfmarketdata://limits` (tiers + your headroom). | |
| 65 | +**Prompts:** `term-structure-analysis(root, as_of?, compare_to?)` · `compare-contracts(symbol_a, symbol_b, days?)` · `fundamentals-snapshot(ticker, quarters?)`. | |
| 66 | + | |
| 67 | +### Behaviour every tool shares | |
| 68 | + | |
| 69 | +- `HFMD_BASE_URL` (default `https://www.hfmarketdata.io`) and `HFMD_API_KEY` (optional) are the only configuration. | |
| 70 | +- `format=json` is always requested; both the v1 envelope `{count,data}` and the v2 envelope `{data,meta}` are understood. | |
| 71 | +- Outputs are compact tables `{"columns":[…],"rows":[[…]]}`. The default `limit` is 500 rows (max 5 000); above **200 rows** the tool returns the count, the first/last 15 rows, per-column numeric ranges and a hint to narrow the request — so a careless "all 1-minute bars since 2010" cannot flood the context. | |
| 72 | +- Rate-limit headroom (`X-RateLimit-Remaining-*`, reset) is appended to every result; a **429** comes back as a clear message with `Retry-After` and the keyless → key upgrade hint. | |
| 73 | +- Errors are uniform: `HF Market Data error <status> <CODE>: <message> [Docs: …]`, whether the API answered with the v2 `{"error":{code,message,docs}}` envelope or the legacy `{"detail"}`. | |
| 74 | +- `subscribe_filings` is bounded by design (`max_messages` ≤ 100, `timeout_seconds` ≤ 120) and closes the socket when it returns; it needs Node ≥ 22 (global `WebSocket`) or Node 20 with `--experimental-websocket`. | |
| 75 | +- Read-only: no tool ever writes anything anywhere. | |
| 76 | + | |
| 77 | +## Configuration snippets | |
| 78 | + | |
| 79 | +### Claude Code | |
| 80 | + | |
| 81 | +```bash | |
| 82 | +claude mcp add hfmarketdata -e HFMD_API_KEY=hfmd_live_… -- npx -y hfmarketdata-mcp | |
| 83 | +# tarball install instead of npm: | |
| 84 | +npm i -g https://www.hfmarketdata.io/downloads/hfmarketdata-mcp-1.0.0.tgz && claude mcp add hfmarketdata -e HFMD_API_KEY=hfmd_live_… -- hfmarketdata-mcp | |
| 85 | +``` | |
| 86 | + | |
| 87 | +Or in `.mcp.json` at the root of a project (shared with your team): | |
| 88 | + | |
| 89 | +```json | |
| 90 | +{ | |
| 91 | + "mcpServers": { | |
| 92 | + "hfmarketdata": { | |
| 93 | + "command": "npx", | |
| 94 | + "args": ["-y", "hfmarketdata-mcp"], | |
| 95 | + "env": { "HFMD_API_KEY": "hfmd_live_…" } | |
| 96 | + } | |
| 97 | + } | |
| 98 | +} | |
| 99 | +``` | |
| 100 | + | |
| 101 | +### Cursor — `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global) | |
| 102 | + | |
| 103 | +```json | |
| 104 | +{ | |
| 105 | + "mcpServers": { | |
| 106 | + "hfmarketdata": { | |
| 107 | + "command": "npx", | |
| 108 | + "args": ["-y", "hfmarketdata-mcp"], | |
| 109 | + "env": { "HFMD_API_KEY": "hfmd_live_…" } | |
| 110 | + } | |
| 111 | + } | |
| 112 | +} | |
| 113 | +``` | |
| 114 | + | |
| 115 | +One-click (best effort): `cursor://anysphere.cursor-deeplink/mcp/install?name=hfmarketdata&config=<base64 of the JSON object above>` — generated for you on <https://www.hfmarketdata.io/integrations/cursor>. | |
| 116 | + | |
| 117 | +### Codex — `~/.codex/config.toml` | |
| 118 | + | |
| 119 | +```toml | |
| 120 | +[mcp_servers.hfmarketdata] | |
| 121 | +command = "npx" | |
| 122 | +args = ["-y", "hfmarketdata-mcp"] | |
| 123 | +env = { HFMD_API_KEY = "hfmd_live_…" } | |
| 124 | +``` | |
| 125 | + | |
| 126 | +### Claude Desktop — `claude_desktop_config.json` | |
| 127 | + | |
| 128 | +```json | |
| 129 | +{ "mcpServers": { "hfmarketdata": { "command": "npx", "args": ["-y", "hfmarketdata-mcp"], "env": { "HFMD_API_KEY": "hfmd_live_…" } } } } | |
| 130 | +``` | |
| 131 | + | |
| 132 | +Keyless? Simply drop the `env` block. | |
| 133 | + | |
| 134 | +## Example session | |
| 135 | + | |
| 136 | +``` | |
| 137 | +> Compare ESZ25 and ESH26 over 30 days | |
| 138 | + | |
| 139 | +⏺ get_coverage(kind="futures_contract", symbol="ESZ25") … get_bars(asset="futures_contract", symbol="ESZ25", start="2025-08-05") … | |
| 140 | +⏺ Over the last 30 sessions ESH26 traded at a 61.5 → 58.0 point premium to ESZ25 (calendar spread narrowing 3.5 pts as | |
| 141 | + financing expectations eased). Volume is still 96 % in ESZ25; the roll window usually opens ~8 sessions before the | |
| 142 | + December expiry (2025-12-19). One session (2025-09-01, Labor Day) is missing in both legs — not interpolated. | |
| 143 | +``` | |
| 144 | + | |
| 145 | +## Development | |
| 146 | + | |
| 147 | +```bash | |
| 148 | +npm install | |
| 149 | +npm test # vitest — 45 tests, every tool mocked (fetch + websocket) | |
| 150 | +npm run build # tsc → dist/ | |
| 151 | +node dist/index.js --selftest | |
| 152 | +node scripts/live-smoke.mjs # real stdio round-trip against www.hfmarketdata.io | |
| 153 | +npm run inspect # MCP Inspector UI | |
| 154 | +``` | |
| 155 | + | |
| 156 | +### Release | |
| 157 | + | |
| 158 | +```bash | |
| 159 | +npm version 1.0.x | |
| 160 | +npm run build && npm test | |
| 161 | +npm pack # → hfmarketdata-mcp-1.0.x.tgz (this is what /downloads serves) | |
| 162 | +npm publish --dry-run # inspect the file list | |
| 163 | +npm publish --access public # requires the maintainer's npm login (npm login / NPM_TOKEN) | |
| 164 | +``` | |
| 165 | + | |
| 166 | +Until the package is on the npm registry, `npx -y hfmarketdata-mcp` resolves nothing: use the tarball URL above or `npm i -g ./hfmarketdata-mcp-1.0.0.tgz`. | |
| 167 | + | |
| 168 | +## Project layout | |
| 169 | + | |
| 170 | +``` | |
| 171 | +src/index.ts bin — stdio transport, --help/--version/--selftest | |
| 172 | +src/server.ts createServer(): 14 tools · 2 resources · 3 prompts | |
| 173 | +src/tools.ts tool catalogue (zod schemas + handlers), runTool() | |
| 174 | +src/client.ts fetch wrapper: auth, format=json, rate headers, uniform HfmdError | |
| 175 | +src/format.ts compact tables, head/tail summaries | |
| 176 | +src/stream.ts bounded websocket consumer | |
| 177 | +src/resources.ts hfmarketdata://status · hfmarketdata://limits | |
| 178 | +src/prompts.ts term-structure-analysis · compare-contracts · fundamentals-snapshot | |
| 179 | +test/ vitest (mocked fetch + fake WebSocket + in-memory MCP transport) | |
| 180 | +scripts/ live-smoke.mjs · record-demo.md | |
| 181 | +``` | |
| 182 | + | |
| 183 | +## Licence | |
| 184 | + | |
| 185 | +MIT © Simon-Pierre Boucher — data by [FirstRate Data](https://firstratedata.com) and SEC EDGAR, served by [HF Market Data](https://www.hfmarketdata.io). Questions: contact@spboucher.ai. | |
added
mcp/docs/README.md
+5 −0
@@ -0,0 +1,5 @@ | ||
| 1 | +# docs/ | |
| 2 | + | |
| 3 | +`demo.gif` — the README hero animation. Not recorded yet: follow `../scripts/record-demo.md` | |
| 4 | +(vhs tape included) and commit the result here, then copy it to | |
| 5 | +`hfmarketdata/web/public/downloads/mcp-demo.gif` for the Integrations page. | |
added
mcp/package-lock.json
+2847 −0
Large diff (2,847 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/package.json
+65 −0
Large diff (65 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/scripts/live-smoke.mjs
+21 −0
Large diff (21 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/scripts/record-demo.md
+54 −0
Large diff (54 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/src/client.ts
+206 −0
Large diff (206 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/src/format.ts
+136 −0
Large diff (136 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/src/index.ts
+62 −0
Large diff (62 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/src/prompts.ts
+96 −0
Large diff (96 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/src/resources.ts
+61 −0
Large diff (61 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/src/server.ts
+77 −0
Large diff (77 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/src/stream.ts
+79 −0
Large diff (79 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/src/tools.ts
+429 −0
Large diff (429 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/test/client.test.ts
+74 −0
Large diff (74 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/test/format.test.ts
+58 −0
Large diff (58 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/test/helpers.ts
+88 −0
Large diff (88 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/test/server.test.ts
+77 −0
Large diff (77 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/test/tools.test.ts
+252 −0
Large diff (252 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/tsconfig.json
+18 −0
Large diff (18 lines) is not loaded by default to keep the page fast.Load diff
added
mcp/vitest.config.ts
+8 −0
Large diff (9 lines) is not loaded by default to keep the page fast.Load diff