Skip to main content
Glama
LogeshR15

Indian Mutual Fund Intelligence MCP

by LogeshR15
README.md
# Indian Mutual Fund Intelligence MCP

Research-and-evidence MCP server for Indian mutual funds. See `spec.md` for the full
architecture proposal. Retrieves, normalizes and computes NAV, portfolio, and document
evidence with provenance — it does not score, rate, or recommend funds, and does not attempt
true performance attribution (not computable from Indian public disclosure).

Not investment advice.

## Status

- **Phase 1 (evidence spine):** AMFI NAVAll.txt ingest + `resolve_fund` + `get_fund_performance`.
- **Phase 2 (portfolio spine):** live AMC portfolio XLSX parsing with 100%-reconciliation
  gating, ISIN-keyed change engine (corporate-action flagging, price/flow drift detection),
  holding persistence, concentration, and `get_fund_portfolio`.
  - **AMC coverage today (12): PPFAS, SBI, UTI, Mirae Asset, Motilal Oswal, Tata, Nippon
    India, DSP, Franklin Templeton, Baroda BNP Paribas, Sundaram, and Union** (see
    `ingest/amc_adapters/registry.py`), each verified live end-to-end with its own golden
    fixture test. Adding an AMC means (1) a real, live-verified way to discover its monthly
    portfolio files — a static link, or a documented backing endpoint found via a one-time
    offline Playwright network capture (never a headless browser at runtime, per the spec) —
    and (2) a golden fixture test proving the parser's column/header/percentage-scale
    auto-detection handles that AMC's layout. These twelve AMCs exercise real layout
    diversity: PPFAS/Mirae/DSP/Union share one shape (one file per scheme); SBI, Motilal
    Oswal, Tata, Nippon India, Baroda BNP Paribas, and Sundaram each publish one combined
    workbook per month (multiple sheets, one per scheme, most with a differently-laid-out
    "Index" sheet — SBI/Motilal Oswal/Tata call the code column "fund/scheme/short code",
    Baroda BNP Paribas calls it "Short Name", Sundaram calls it "ACRONYM", Nippon has no
    header row at all — all handled by one shared, column-detecting resolver rather than a
    hardcoded mapping per AMC); Franklin Templeton has no Index sheet at all (the sheet name
    itself is the code, resolved by scanning each sheet's own title row); UTI puts the ISIN
    column non-adjacent to the rest entirely and never states a %-to-NAV grand total
    (self-summing fallback); Tata labels its true 100% total row "NET ASSETS" and suffixes
    sub-totals; Franklin puts the ISIN column *before* the name column (the reverse of every
    other AMC). Mirae, Motilal Oswal, DSP, Baroda BNP Paribas, and Union's holdings parsing
    needed **zero** new parser code, confirming the generalization holds as new AMCs are
    added rather than just accumulating special cases. Note: DSP and Baroda BNP Paribas's
    discovered endpoints only ever serve the *latest* month, not full history — a real
    capability limit, not a bug.
  - **Fifteen AMCs were attempted and are genuinely blocked, not just unstarted** — each
    investigated live with real effort, spanning distinct failure modes: **HDFC** and
    **Kotak Mahindra** (Radware Bot Manager CAPTCHA) are bot-protected outright. **ICICI
    Prudential** (F5 BIG-IP WAF, TLS-fingerprint-based), **Invesco** and **WhiteOak Capital**
    (CloudFront/AWS-WAF on the whole domain — Invesco's India business may also have been
    rebranded, making this one possibly moot), and **Edelweiss** (Akamai edge WAF blocking
    its portfolio API specifically) are each blocked by a commercial WAF vendor. **Axis** and
    **PGIM India** are both cases where the real API is same-origin but only reachable after
    client-side JS execution the site fingerprints and blocks in Playwright specifically — a
    different failure mode from a WAF blocking the API itself. **HSBC** has no discoverable
    disclosure page at all. **Three AMCs — Bandhan, JM Financial, and Mahindra Manulife —
    share a distinct and notable failure mode**: their APIs return a real `200 OK` with a
    `{"data"/"payload": "<base64>"}` body that decodes to high-entropy ciphertext, not JSON —
    application-layer payload encryption, not access control. Replaying even a captured real
    request fails; decrypting it would mean reverse-engineering each site's client-side
    crypto scheme, a fundamentally different and more invasive problem than a WAF bypass, and
    explicitly out of scope. The repetition across three unrelated AMCs suggests a shared
    fintech backend vendor for investor-portal APIs — worth checking before investing more
    time on any AMC that returns this same opaque-payload shape. **Quant**'s self-service
    disclosure page appears to be simply broken (empty ASP.NET WebForms viewstate, zero
    backing requests fire) rather than protected. **Canara Robeco**'s file discovery actually
    *works* cleanly (static links, exact 100% reconciliation, zero parser changes) — but its
    WAF blocks the project's honest User-Agent while accepting a spoofed browser UA; asked
    the user explicitly rather than deciding unilaterally, and **the decision was to skip
    it** and keep the honest-User-Agent policy from spec.md intact. **Aditya Birla**'s
    discovery endpoint is already found and documented but its file lives behind a CDN host
    this *sandbox's* network policy blocks (not a real-world blocker).
  - The remaining ~21 AMCs haven't been attempted yet. This is real, per-AMC engineering
    effort — exactly what the spec calls "the real moat" of the project — but the pattern
    (Playwright discovery → adapter → golden test) is proven across twelve materially
    different AMC layouts, and the failure modes for the rest are now well-characterized
    (multiple WAF vendors, headless-JS fingerprinting, SPA-with-no-API, payload encryption, a
    broken page, or UA policy) rather than unknowns.

- **Phase 3 (document intelligence, partial):** PDF section extraction (SEBI-standard headings +
  keyword search) ground-truthed against a real AMFI-hosted SID, `get_document`, and
  `get_fund_profile` (identity, benchmark, verbatim mandate excerpts, realised Direct-vs-Regular
  cost spread computed from NAV alone). TER capture and fund-manager extraction from factsheets
  are not yet implemented and are reported as explicitly unavailable, never fabricated.

Remaining AMC adapters, TER/manager extraction, and change monitoring (Phase 4) are not yet built.

## Usage

```
uv sync
uv run mf-mcp ingest-navall   # populate the local store with AMFI's daily NAV universe
uv run mf-mcp backfill-portfolio --amc ppfas \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "Parag Parikh Flexi Cap Fund" \
    --from 2019-01-01
uv run mf-mcp backfill-portfolio --amc sbi \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "SBI Flexicap Fund" \
    --from 2024-01-01
uv run mf-mcp backfill-portfolio --amc uti \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "UTI Flexi Cap Fund" \
    --from 2024-01-01
uv run mf-mcp backfill-portfolio --amc mirae \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "Mirae Asset Large Cap Fund" \
    --from 2024-01-01
uv run mf-mcp backfill-portfolio --amc motilal-oswal \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "Motilal Oswal Flexi Cap Fund" \
    --from 2024-01-01
uv run mf-mcp backfill-portfolio --amc tata \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "Tata Large & Mid Cap Fund" \
    --from 2024-01-01
uv run mf-mcp backfill-portfolio --amc nippon \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "Nippon India Large Cap Fund" \
    --from 2024-01-01
uv run mf-mcp backfill-portfolio --amc dsp \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "DSP Flexi Cap Fund" \
    --from 2024-01-01   # DSP's endpoint only ever serves the latest month, not full history
uv run mf-mcp backfill-portfolio --amc franklin-templeton \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "Franklin India Bluechip Fund" \
    --from 2024-01-01
uv run mf-mcp backfill-portfolio --amc baroda-bnp-paribas \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "Baroda BNP Paribas Large Cap Fund" \
    --from 2024-01-01   # only the latest month is available
uv run mf-mcp backfill-portfolio --amc sundaram \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "Sundaram Large and Mid Cap Fund" \
    --from 2013-01-01   # full archive available back to 2012-2013
uv run mf-mcp backfill-portfolio --amc union \
    --scheme-id <scheme_id from resolve_fund> \
    --scheme-hint "Union Flexi Cap Fund" \
    --from 2021-01-01
uv run mf-mcp serve           # run the MCP server (stdio)
```

Data lives in `~/.indian-mf-mcp/` (SQLite store + raw archive; never evicted).

Run tests with `uv run pytest -q`. One test (`test_ppfas_live_smoke.py`) hits the real PPFAS
site and is skipped automatically if the network is unavailable.

TDQS

A4/5.0

Scored across 5 tools

Disambiguation5/5

Each tool targets a distinct facet: resolve_fund handles identity, get_fund_performance covers returns/risk, get_fund_portfolio covers holdings, get_fund_profile covers static metadata, and get_document retrieves verbatim source evidence. The descriptions explicitly delineate boundaries (e.g. profile returns mandate excerpts vs. document retrieves raw pages), so there is minimal risk of misselection.

Naming Consistency5/5

Four tools follow a clean get_fund_<noun>/get_document verb_noun pattern, and resolve_fund is a semantically apt deviation for the identity-resolution step. The convention is predictable throughout with no mixed casing or stylistic drift.

Tool Count5/5

Five tools is well-scoped for a fund-intelligence server, and each one earns its place by covering a genuinely separate dimension (identity, performance, portfolio, profile, documents). No tool feels redundant or trivial.

Completeness4/5

The surface covers the full read-only lifecycle from identity resolution through evidence retrieval, which is coherent for an intelligence (non-mutating) server. Minor gaps exist — benchmark comparators, managers, and TER are explicitly deferred — but they are transparently flagged rather than silently missing.

Maintenance

ActivityMaintained
ResponsivenessNo issues