Skip to main content
Glama
Sekharz

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: OpenInsider MCP

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_recipessearch_apisget_api_detailscall_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

  • uvbrew 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
Install Server
F
license - not found
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Sekharz/finanal'

If you have feedback or need assistance with the MCP directory API, please join our Discord server