spb/hfmarketdata
Public
Open high-frequency market data platform — FirstRate full-history downloader, DuckDB/Parquet lake, open REST API and React docs platform (www.hfmarketdata.io)
JavaScript 53.7%
Python 38.3%
CSS 4.6%
TypeScript 3.1%
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>45<h1 align="center">hfmarketdata-mcp</h1>67<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>1213<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>2122---2324## Quickstart (60 seconds)2526```bash27# 1. Install (pick one)28npm i -g hfmarketdata-mcp # from npm (once published)29npm i -g https://www.hfmarketdata.io/downloads/hfmarketdata-mcp-1.0.0.tgz # direct tarball, works today3031# 2. Check the connection (keyless works out of the box: 30 requests/hour)32hfmarketdata-mcp --selftest33# OK https://www.hfmarketdata.io (312 ms, keyless) — datasets: stock, etf, futures, futures_contracts, crypto, index, fx, options3435# 3. Add it to Claude Code36claude mcp add hfmarketdata -e HFMD_API_KEY=hfmd_live_… -- npx -y hfmarketdata-mcp37```3839Then just ask:4041> *"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"*4243The platform is entirely free. Keyless mode has low hourly limits (30 requests / hour); a free API key (free account at `https://www.hfmarketdata.io/signup`) gives **120 requests / minute**, and higher limits are granted on request by e-mail to contact@spboucher.ai (also free). Set the key as `HFMD_API_KEY`; the server never logs it. Details: <https://www.hfmarketdata.io/limits>.4445## Tools4647| 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 |6364**Resources:** `hfmarketdata://status` (live dataset inventory) · `hfmarketdata://limits` (rate limits + your headroom).65**Prompts:** `term-structure-analysis(root, as_of?, compare_to?)` · `compare-contracts(symbol_a, symbol_b, days?)` · `fundamentals-snapshot(ticker, quarters?)`.6667### Behaviour every tool shares6869- `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 a reminder that a free API key lifts the low keyless limits.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.7677## Configuration snippets7879### Claude Code8081```bash82claude mcp add hfmarketdata -e HFMD_API_KEY=hfmd_live_… -- npx -y hfmarketdata-mcp83# tarball install instead of npm:84npm i -g https://www.hfmarketdata.io/downloads/hfmarketdata-mcp-1.0.0.tgz && claude mcp add hfmarketdata -e HFMD_API_KEY=hfmd_live_… -- hfmarketdata-mcp85```8687Or in `.mcp.json` at the root of a project (shared with your team):8889```json90{91 "mcpServers": {92 "hfmarketdata": {93 "command": "npx",94 "args": ["-y", "hfmarketdata-mcp"],95 "env": { "HFMD_API_KEY": "hfmd_live_…" }96 }97 }98}99```100101### Cursor — `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global)102103```json104{105 "mcpServers": {106 "hfmarketdata": {107 "command": "npx",108 "args": ["-y", "hfmarketdata-mcp"],109 "env": { "HFMD_API_KEY": "hfmd_live_…" }110 }111 }112}113```114115One-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>.116117### Codex — `~/.codex/config.toml`118119```toml120[mcp_servers.hfmarketdata]121command = "npx"122args = ["-y", "hfmarketdata-mcp"]123env = { HFMD_API_KEY = "hfmd_live_…" }124```125126### Claude Desktop — `claude_desktop_config.json`127128```json129{ "mcpServers": { "hfmarketdata": { "command": "npx", "args": ["-y", "hfmarketdata-mcp"], "env": { "HFMD_API_KEY": "hfmd_live_…" } } } }130```131132Keyless? Simply drop the `env` block.133134## Example session135136```137> Compare ESZ25 and ESH26 over 30 days138139⏺ 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 as141 financing expectations eased). Volume is still 96 % in ESZ25; the roll window usually opens ~8 sessions before the142 December expiry (2025-12-19). One session (2025-09-01, Labor Day) is missing in both legs — not interpolated.143```144145## Development146147```bash148npm install149npm test # vitest — 45 tests, every tool mocked (fetch + websocket)150npm run build # tsc → dist/151node dist/index.js --selftest152node scripts/live-smoke.mjs # real stdio round-trip against www.hfmarketdata.io153npm run inspect # MCP Inspector UI154```155156### Release157158```bash159npm version 1.0.x160npm run build && npm test161npm pack # → hfmarketdata-mcp-1.0.x.tgz (this is what /downloads serves)162npm publish --dry-run # inspect the file list163npm publish --access public # requires the maintainer's npm login (npm login / NPM_TOKEN)164```165166Until 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`.167168## Project layout169170```171src/index.ts bin — stdio transport, --help/--version/--selftest172src/server.ts createServer(): 14 tools · 2 resources · 3 prompts173src/tools.ts tool catalogue (zod schemas + handlers), runTool()174src/client.ts fetch wrapper: auth, format=json, rate headers, uniform HfmdError175src/format.ts compact tables, head/tail summaries176src/stream.ts bounded websocket consumer177src/resources.ts hfmarketdata://status · hfmarketdata://limits178src/prompts.ts term-structure-analysis · compare-contracts · fundamentals-snapshot179test/ vitest (mocked fetch + fake WebSocket + in-memory MCP transport)180scripts/ live-smoke.mjs · record-demo.md181```182183## Licence184185MIT © 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.186