@cyanheads/finnhub-mcp-server
Real-time US-equity quotes, company fundamentals, earnings, analyst trends, and financial news via Finnhub. STDIO or Streamable HTTP.
6 Tools • 2 Resources
Overview
Real-time US stock data from Finnhub: quotes, company fundamentals, earnings, analyst recommendations, and financial news. Look up a company by name, then pull live pricing, valuation, or news for it.
Ticker inputs are trimmed and uppercased; punctuation such as BRK.B is preserved. Earnings calendar filters may be omitted or blank for market-wide results; earnings history and company news require a nonblank symbol. Search queries retain their original spelling, and market news ignores symbol.
Tools
Resources
The news-category reference mirrors the category enum on finnhub_get_news. The finnhub guide also ships with plugin installs, npm, Docker, and the desktop bundle.
Capability reference
finnhub_search_symbols tool
- Search by company name or ticker fragment with
query (1–20 characters) and limit (1–50, default 10).
- Returns likely-US Common Stock matches first, with an
isLikelyUS symbol-format heuristic, total match count, and truncation disclosure. Quote and profile responses remain authoritative.
finnhub_get_quote tool
- Requires
symbol; returns current price, change, session open/high/low, previous close, and an ISO 8601 quote time.
priceIsLive distinguishes a live price from the prior close; marketOpen, session, and holiday are nullable when market status is unavailable. Unknown ticker → symbol_not_found; international or paid-only symbol → not_us_or_paid.
finnhub_get_company tool
- Requires
symbol; returns company profile, nullable headline fundamentals (P/E, EPS, 52-week range, beta, dividend yield, margins, growth, ROE), and sector peers.
- Failed metrics or peers appear in
partial; the profile determines symbol_not_found and not_us_or_paid errors.
finnhub_get_earnings tool
history requires symbol and returns past quarters' actual/estimate EPS and surprise, newest first. calendar accepts from / to (default today through +14 days) and an optional symbol, returning release dates, EPS/revenue estimates, and report times.
limit (1–100, default 50) caps rows with total and truncation disclosure. History without a symbol → missing_symbol; international or paid-only symbol → not_us_or_paid.
finnhub_get_news tool
company requires symbol and accepts a date range (default last 7 days). market uses category: general, forex, crypto, or merger (see finnhub://news-categories).
- Returns headline, source, ISO 8601 datetime, summary, and URL, newest first.
limit (1–100, default 15) caps articles with total and truncation disclosure; company mode without a symbol → missing_symbol, international or paid-only symbol → not_us_or_paid.
finnhub_get_recommendations tool
- Per-month strong-buy / buy / hold / sell / strong-sell counts, newest first; history depth depends on Finnhub coverage.
limit (1–24, default 12) caps available rows; raising it cannot retrieve history absent from Finnhub. Reports total months and discloses truncation.
- Empty result →
no_coverage; it cannot distinguish an invalid symbol from a valid symbol without coverage. International or paid-only symbol → not_us_or_paid.
finnhub://news-categories resource
- Returns the four valid
finnhub_get_news market-mode categories (general, forex, crypto, merger) with one-line descriptions, as application/json
- Convenience mirror — fully covered by the
category enum's .describe() on finnhub_get_news, so tool-only clients lose nothing
- Live data (quotes, news, earnings) is intentionally not exposed as a resource — it's time-sensitive, so freshness lives only in the tools
Features
The finnhub-guide skill helps agents combine tool results into company and earnings briefings while preserving dates, missing values, and endpoint coverage limits. MCP clients can discover it through skills/list or read its skill://finnhub-guide/SKILL.md resource.
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Finnhub-specific:
- Single rate-aware Finnhub client — token injected server-side (never a tool input), with timeout and retry calibrated to the 60 req/min free tier
- Live market-status pairing on quotes so a closed-market price is reported as the prior close, never as live
- Status classification at the service boundary: 403 → a clear
not_us_or_paid domain error, 401 → loud configuration failure at first call (not "no data"), 429/5xx → retried
finnhub_get_company fans out profile + metrics + peers in parallel and degrades to partial results when a leg fails
Agent-friendly output:
- Honest sparsity — every fundamental is nullable and absent values stay null; Finnhub's thinly-covered names are surfaced as-is, never zero-filled or fabricated
- Two distinct "not available" signals —
symbol_not_found (all-zero quote / empty profile sentinel) vs. not_us_or_paid (international or paid-only, HTTP 403). An empty profile can also reflect missing instrument coverage.
- ETFs, funds, or trusts may lack company profiles, earnings history, or analyst recommendations. Empty responses retain ticker verification guidance and suggest
finnhub_get_quote for price data without promising quote availability.
- Typed error contracts with recovery hints on every failure, plus the
isLikelyUS search heuristic so an agent can prioritize likely free-tier symbols
- Capped lists report their total count and disclose truncation, so an agent knows when more data exists
Getting started
This server requires a free Finnhub API key (Dashboard → API key). The free tier covers US equities in real time at 60 req/min.
Each user must obtain their own API key. Use is subject to Finnhub's Terms of Service — the free tier is for personal use only, and redistributing or sharing access to Finnhub data with third parties requires written approval from Finnhub.
Add it to Claude Code:
For other clients, add this to your MCP configuration file:
For Docker or a source build, see Running the server.
Configuration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
See .env.example for the full list of optional overrides.
Running the server
Local development
Requires Bun v1.4.0 or higher (or Node.js v24+), and a free Finnhub API key.
-
Build and run:
-
Run checks and tests:
Docker
The image defaults to HTTP transport, stateless session mode, and logs to /var/log/finnhub-mcp-server. For stdio, add -i -e MCP_TRANSPORT_TYPE=stdio to docker run. To build locally, run docker build -t finnhub-mcp-server .; OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Development guide
See CLAUDE.md / AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catch in tool logic
- Use
ctx.log for request-scoped logging, ctx.state for tenant-scoped storage
- Register new tools and resources via the barrels in
src/mcp-server/*/definitions/index.ts
- Wrap the Finnhub API: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
License
Apache-2.0 — see LICENSE for details.