Skip to main content
Glama
finanal-mcp

finanal-mcp

by Sekharz

finanal-mcp

A minimal, token-efficient MCP server that combines stock prices and fundamentals with the macro and micro narrative around them — so an AI agent can reason about why a stock moved, what people are thinking about it, and what probable scenarios lie ahead.

Why this project exists

Knowing a stock's PE ratio or current price is not enough. The interesting questions are: why did this stock dip today? What does the market narrative say about it? What are the macro tailwinds or headwinds? What could happen next?

Answering those questions requires combining three things simultaneously:

  • Fundamentals and price data — earnings, ratios, revenue growth, institutional flows

  • Real-time news and macro context — what analysts, media, and macro events are saying

  • The narrative — sentiment, concall tone, sector rotation, management guidance

The tools chosen — FMP, Tapetide, and Tavily — are the best available for each of those jobs. FMP is the gold standard for US stock fundamentals. Tapetide is purpose-built for Indian NSE/BSE data with native MCP support. Tavily is a research-grade search engine that retrieves and synthesises real-time financial news.

Why not use the existing MCP servers for these tools directly?

All three providers publish their own MCP servers, but each exposes 50–100+ individual tools. Every tool description gets embedded into the system prompt of every LLM call. With three servers active that's potentially 150–300 tool descriptions injected into every single prompt — input tokens explode, costs spike, and the LLM gets confused by the noise.

This project is the solution: one MCP server, 6 tools maximum. The LLM talks to a single router that knows which underlying API to call, how to call it, and what parameters to use. The input token footprint stays flat no matter how many endpoints exist in the index.

finanal-mcp in one sentence: ask any financial question in plain English — the server finds the right API, calls it, and caches the answer for instant reuse.

Related MCP server: financial-research-agent

Why it is built this way

Decision

Rationale

6 tools maximum

Each tool description is injected into every LLM prompt. Keeping the count to 6 keeps the input token footprint minimal and constant (~159 tokens total), regardless of how many underlying endpoints are indexed.

Slim search_apis responses

search_apis returns only id, source, path, summary, score (~310 tokens for 10 results). Full schema is deferred to get_api_details, only called when the right endpoint is identified. Before this, full rows cost ~1,232 tokens per search call.

Response field trimming in call_api

Known-verbose fields (description, cik, cusip, isin, address, phone, image) are stripped from FMP responses. Cuts a typical /profile response from ~360 to ~149 tokens — the LLM never needed the 3-paragraph company bio.

SQLite + FTS5 BM25 instead of vector embeddings

The endpoint index is ~300 rows. BM25 + finance synonyms hits ~90% accuracy with zero extra dependencies and zero latency. Vector search adds complexity and a model inference call for no measurable gain at this scale.

Finance synonym expansion baked into db.py

"PE ratio", "price to earnings", "valuation multiple" are the same query. Expanding tokens before FTS search avoids the most common failure modes without needing an LLM call.

Tapetide as a proxied MCP server instead of a direct REST client

Tapetide exposes a native MCP server at https://mcp.tapetide.com/mcp. Proxying it over JSON-RPC means we never need to maintain an OpenAPI spec for 49+ Indian market tools — they stay current automatically.

Tavily for news instead of FMP news endpoints

FMP's news APIs require a paid plan (return HTTP 402 on free tier). Tavily's search engine covers US/global news, macro events, and earnings headlines on the free tier with far richer synthesis.

Recipe cache as the first tool call

BM25 is fast but not perfect. Recipes are exact-match quality. Any question answered once correctly is answered instantly forever after, with zero redundant API discovery. A recipe hit skips both search_apis and get_api_details — the two most expensive steps.

uv for all Python

Reproducible builds, fast installs, no system Python pollution. All commands use uv run.

Source routing rules

These rules are enforced both in the search_apis tool description and in seeded recipes, so any LLM using this server learns them from the first call.

Source

Use for

Never use for

tapetide

Indian NSE/BSE: quotes, news, fundamentals, shareholding, FII/DII, screener, concalls

US or global stocks

fmp

US and global stocks: price, financials, earnings, analyst estimates, SEC filings

News (paywalled, returns 402)

tavily

All news and macro: US stock news, Fed/RBI decisions, earnings headlines, any web search

N/A — use as fallback for anything news-shaped

Why not just use prompt caching?

A fair question: FMP, Tapetide, and Tavily each publish their own MCP servers. If you registered all three directly, the LLM would have the full tool list in its context. And since modern LLMs (Claude, GPT-4o) cache the system prompt, subsequent calls would hit the cache at ~90% discount — so it would barely cost anything after the first call, right?

Prompt caching fixes the wallet problem. This architecture fixes the brain problem. Even with perfect cache hits, monolithic tool registrations still fail in three ways:

1. Cache eviction tax (TTL ~5–10 minutes)

Prompt caches are ephemeral. Most providers evict after 5–10 minutes of inactivity. If a user pauses to read, grabs a coffee, or writes a long reply — the cache evicts. The very next turn re-indexes all 150–300 tool schemas at 1.25× the base rate (cache-write premium), and the full cost resets. With 6 tools and ~159 tokens of descriptions, a cache eviction costs fractions of a cent. The TTL problem simply disappears.

2. Model attention tax ("lost in the middle")

Even if holding 200,000 tokens of tool schemas in context is cheap, it is not free for the model's reasoning. When an LLM has to parse 500 tool schemas simultaneously its retrieval accuracy degrades measurably — it hallucinates optional parameters, confuses endpoints with similar names, and dilutes attention on the actual task. By routing through search_apis first, the model only sees the 3–4 tools it actually needs for that specific turn. Attention stays sharp.

3. Context window starvation

Every model has a hard context limit. If 200,000 tokens are permanently occupied by monolithic tool schemas, that is 200,000 fewer tokens available for conversation history, API response payloads, and deep reasoning. For a tool-heavy financial workflow where API responses can be large, this matters.

The compounding win: recipes

The deeper lever is the recipe cache. A recipe hit means the model calls exactly one tool (search_recipes) instead of the usual three (search_recipes → search_apis → get_api_details → call_api). Every question answered correctly makes the next identical question instant and near-zero cost. The system gets cheaper and more accurate over time.

Measured token budget

Component

Tokens

All 6 tool descriptions combined

~159

search_apis response, 10 results (slim)

~310

search_apis response, 10 results (old, full rows)

~1,232

FMP /profile response, trimmed

~149

FMP /profile response, untrimmed

~360

A typical recipe hit (skips search entirely)

~80

Architecture

Copilot / LLM agent
        │
        ▼
  finanal-mcp (stdio)
  ┌─────────────────────────────────────────────┐
  │  search_recipes  ← check cache first        │
  │  search_apis     ← BM25 + synonym index     │
  │  get_api_details ← full schema for endpoint │
  │  search_docs     ← BM25 doc search          │
  │  call_api        ← live API call            │
  │  save_recipe     ← cache successful answer  │
  └──────────────┬──────────────────────────────┘
                 │  routes by source field
       ┌─────────┼──────────┐
       ▼         ▼          ▼
    FMP REST  Tavily REST  Tapetide MCP
    (US/global) (news)     (India NSE/BSE)

Prerequisites

  • Python ≥ 3.14

  • uv — brew install uv or pip install uv

  • API keys for FMP, Tavily, and Tapetide (free tiers available for all three)

Setup

git clone <repo>
cd finanal
uv sync
cp .env.example .env
# Edit .env and fill in your three API keys

Get your keys:

Seed the endpoint index

Run once after cloning (or after pulling updates):

uv run scripts/seed_fmp_scrape.py   # 236 FMP endpoints from official docs
uv run scripts/seed_tavily.py       # 7 Tavily endpoints
uv run scripts/seed_tapetide.py     # 49 Tapetide tool schemas
uv run scripts/enrich_docs.py       # 348 synthetic BM25 docs

Verify with smoke tests

uv run scripts/test_search.py
# Expected: 15/15 ✓ all rank-1

Run the MCP server

uv run python main.py

The server communicates over stdio and is consumed by VS Code / Copilot via the MCP protocol. You do not interact with it directly.

Register in VS Code (user-level — works in all workspaces)

Add to ~/Library/Application Support/Code/User/mcp.json (macOS) or the equivalent user-level mcp.json on your OS:

{
  "servers": {
    "finanal-mcp": {
      "type": "stdio",
      "command": "uv",
      "args": ["run", "python", "main.py"],
      "cwd": "/absolute/path/to/finanal"
    },
    "tapetide-mcp": {
      "type": "http",
      "url": "https://mcp.tapetide.com/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_TAPETIDE_TOKEN",
        "Content-Type": "application/json",
        "Accept": "application/json, text/event-stream"
      }
    }
  }
}

Note: tapetide-mcp is registered separately as an HTTP server so Copilot can call its tools directly (faster path). finanal-mcp proxies through to it as well, but direct registration gives Copilot access to all 49 Tapetide tools without going through the router.

How to use it from Copilot Chat

finanal-mcp is a tool router, not a chat assistant. An LLM agent (Copilot, Claude, etc.) calls its tools to discover and invoke the right financial API. The mandatory workflow:

Step-by-step tool call order

1. search_recipes(query)
   └─ If score < -1.0 → use that recipe directly, skip to call_api. Done.

2. search_apis(query, source="fmp"|"tapetide"|"tavily")
   └─ Returns ranked endpoint list with id, summary, source, parameters.

3. get_api_details(endpoint_id)
   └─ Returns full parameter schema so call_api gets the right args.

4. call_api(endpoint_id, params={...})
   └─ Executes the live API call and returns the data.

5. save_recipe(question, summary, endpoint_ids=[...])
   └─ Always save after a good answer — next identical query is instant.

Example queries and what happens

Query

Route

Tool sequence

"Polycab current price"

tapetide

search_recipes → call_api(tapetide get_stock_quote)

"VRT Vertiv stock price"

fmp

search_recipes → call_api(fmp /profile)

"Polycab latest news"

tapetide

search_recipes → call_api(tapetide get_stock_news)

"Vertiv news 2026"

tavily

search_recipes → call_api(tavily /search, topic=finance)

"RELIANCE PE ratio"

fmp

search_recipes → search_apis → call_api(fmp /ratios)

"India FII DII flows today"

tapetide

search_recipes → call_api(tapetide get_fii_dii_flows)

"US Fed rate decision news"

tavily

search_recipes → call_api(tavily /search, topic=news)

Teaching the server new routing rules

Seed recipes directly:

import db
conn = db.get_conn()
db.upsert_recipe(
    conn,
    question="Get quarterly earnings for an Indian company",
    summary="Use tapetide get_financials (source=tapetide), section='profit_loss'.",
    endpoint_ids=[22],
)
conn.commit()

Or use the save_recipe tool from within a Copilot chat session after a successful answer.

DB state (after full seed)

Source

Endpoints

Notes

fmp

236

Scraped from official FMP docs + community OpenAPI YAML

tapetide

49

Tapetide native MCP tool schemas

tavily

7

Hand-crafted from Tavily OpenAPI spec

Total

292

Docs (BM25)

348

Synthetic per-endpoint + per-tag-group docs

Recipes

6+

Seeded routing rules; grows with use

Key files

main.py                      ← FastMCP server — 6 tools, source-aware call_api routing
db.py                        ← SQLite schema, FTS5 tables, BM25 search, synonym expansion
scripts/seed_fmp_scrape.py   ← Primary FMP seed (236 endpoints from scraped docs)
scripts/seed_fmp.py          ← Secondary FMP seed (community OpenAPI YAML, 181 endpoints)
scripts/seed_tavily.py       ← Tavily endpoint seed
scripts/seed_tapetide.py     ← Tapetide tool schema seed
scripts/enrich_docs.py       ← Synthetic BM25 doc generation (348 docs)
scripts/test_search.py       ← Smoke tests (15/15 expected)
specs/tavily.yaml            ← Hand-crafted Tavily OpenAPI spec
data/finanal.db              ← SQLite database (gitignored)
.env.example                 ← API key template
.github/copilot-instructions.md ← Copilot tool workflow instructions

Available Tools

6 tools
call_apiB

Call a live API endpoint by endpoint_id and params.

Inputs: endpoint_id (required), params. Returns: object

get_api_detailsB

Get full metadata/schema for an endpoint by id.

Inputs: endpoint_id (required). Returns: object

save_recipeC

Save a solved recipe to cache.

Inputs: summary (required), question (required), doc_ids, endpoint_ids. Returns: object

search_apisA

Search API endpoints across fmp, tapetide, and tavily. Source routing: tapetide=India NSE/BSE, fmp=US/global stocks, tavily=all news. Pass source='tapetide'|'fmp'|'tavily' to restrict. Returns slim rows (id, source, path, summary, score) — call get_api_details for full schema.

Inputs: query (required), limit, source. Returns: result

search_docsC

Search synthetic/ingested docs with BM25.

Inputs: query (required), limit. Returns: result

search_recipesA

Search previously solved Q&A recipes. ALWAYS call this FIRST before search_apis or call_api. If a matching recipe exists (score < -1.0 is a strong match), return it directly without further API calls.

Inputs: query (required), limit. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 6 tools

    Disambiguation5/5

    Each tool has a clear, distinct purpose: call_api vs get_api_details separate invocation from metadata, search tools target different data types (APIs, docs, recipes), and save_recipe is uniquely for caching solved queries. No ambiguity between tools.

    Naming Consistency5/5

    All tool names follow a consistent verb_noun pattern with snake_case: call_api, get_api_details, save_recipe, search_apis, search_docs, search_recipes. No mixed conventions.

    Tool Count5/5

    6 tools is ideal for a server that provides search, details, and invocation across multiple data sources. Each tool earns its place without being overly narrow or broad.

    Completeness4/5

    The set covers the full workflow: search for APIs, get details, call them, search docs, and reuse saved recipes. Minor gap: no explicit tool to list all endpoints or manage recipes beyond saving, but core functionality is complete.

    Related MCP Connectors

    • Financial data MCP server for Claude, ChatGPT, Cursor and Codex. Real-time stock quotes, financial statements, options flow, SEC filings, insider trades, 13F holdings, macro data and market news from gloom.sh, the open-source Bloomberg Terminal alternative.

      https://api.gloom.sh/mcp
    • Official Intrinio MCP server. US stock prices, options and fundamentals for AI agents.

    • Your agent needs markets — prices and fundamentals for listed companies, the filings behind them, crypto, and what the prediction markets put the odds at. **What you can ask for** • "Pull this company's income statement, cash flow and balance sheet for the last 8 quarters." • "What did insiders buy or sell, and when?" • "Snapshot prices for these 50 tickers, then the OHLC history for the three that moved." • "What are the current odds on this event across Kalshi and Polymarket?" • "Screen for companies matching these financial criteria." **How to use it** Point any MCP client at https://mcp.aisa.one/finance/mcp and sign in with OAuth — there is no key to create or paste. 49 tools: prices and snapshots, income statements, balance sheets and cash flows, metrics and ratios, earnings and analyst estimates, filings and line-item search, insider trades, macro interest rates, news, a screener; CoinGecko spot prices, market tables, OHLC, per-venue tickers and trending; Kalshi and Polymarket markets and trades; plus EDINET filings for Japan. **Why this rather than the source** Equities, crypto and event markets behind one account, so a cross-asset question is one conversation. **It is also a door to the rest** The same login reaches 26 sources and 580+ operations. Read the number here, then ask the same agent what X is saying about the ticker today — without adding a second server. **What it costs** Finding and inspecting an operation is free. Running one is billed per call at API prices, with no seat and no monthly minimum, and every call takes max_price_usd so an agent cannot overspend by accident. **Where else it reaches** https://mcp.aisa.one/marketpulse/mcp · /crypto-market-data/mcp · /prediction-market-data/mcp · /stock-pulse/mcp for one slice each.

    • Your agent needs company financials it can compute on — statements, ratios, earnings, estimates, filings and insider activity as structured data, not a PDF. **What you can ask for** • "Give me 8 quarters of income statement, balance sheet and cash flow for this ticker." • "What do analysts estimate for next quarter, and how did the last four surprise?" • "Find this exact line item across every filing." • "Who bought or sold as an insider in the last 90 days?" • "Screen for profitable companies under this valuation with growing revenue." **How to use it** Point any MCP client at https://mcp.aisa.one/marketpulse/mcp and sign in with OAuth — there is no key to create or paste. 21 tools: prices and snapshots, income statements, balance sheets, cash-flow statements, financial metrics and snapshots, earnings, analyst estimates, company facts, filings and filing items, line-item search, a screener, insider trades, macro interest rates, news, plus EDINET documents and filing digests for Japanese issuers. **Why this rather than the source** Statements as fields you can compute on, and a screener in the same place. **It is also a door to the rest** The same login reaches 26 sources and 580+ operations. Read the fundamentals here, then ask the same agent what social is saying about the ticker — without adding a second server. **What it costs** Finding and inspecting an operation is free. Running one is billed per call at API prices, with no seat and no monthly minimum, and every call takes max_price_usd so an agent cannot overspend by accident. **Where else it reaches** https://mcp.aisa.one/finance/mcp for equities, crypto and prediction markets in one place.

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      An MCP server that exposes 16 free investment-research signals (insider trades, SEC filings, short data, and live quotes) to any MCP-compatible LLM.
      88 npm
      104
      MIT
    • F
      license
      Not graded
      quality
      D
      maintenance
      MCP server that exposes stock research tools (fundamentals, news, technicals, analyst ratings) to AI clients, enabling autonomous generation of structured investment briefs.
      -
    • A
      license
      B
      quality
      B
      maintenance
      A Model Context Protocol (MCP) server for agentic retrieval of financial data from Yahoo Finance, enabling stock information, historical data, analyst data, and more.
      71
      125 PyPI
      6
      AGPL 3.0