India Finance MCP avatar

India Finance MCP

Pricing

Pay per usage

Go to Apify Store
India Finance MCP

India Finance MCP

MCP server for Indian financial data. Get real-time mutual fund NAVs from AMFI (47,000+ schemes), validate GSTIN numbers with checksum verification, and more. Built for AI agents (Claude, ChatGPT, Cursor) via MCP protocol. REST API also available. Stock quotes coming in v1.1.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Tushar

Tushar

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

3 days ago

Last modified

Share

Apify Actor Cloudflare Workers

India Finance MCP

A Model Context Protocol (MCP) server exposing Indian financial data to LLMs and agents, with a parallel REST API for non-MCP consumers.

Single TypeScript codebase, two deployment targets:

  • MCP server (FastMCP, Node) — deployed as an Apify Actor. Plug it into Claude Desktop, Cursor, or any MCP-compatible client.
  • REST mirror (Hono on Cloudflare Workers) — for HTTP clients, monetizable via RapidAPI.

Live as of 2026-05-04.

TargetURLTransports
Apify Actorhttps://apify.com/vamppog/india-finance-mcpMCP (Streamable HTTP) at /mcp via FastMCP
Cloudflare Workershttps://india-finance-mcp.vamp-fa0.workers.devMCP (JSON-RPC) at POST /mcp + REST at /api/*

What it does

ToolPurposeSourceAuth needed
get_mutual_fund_navLook up the latest NAV for any Indian mutual fund by AMFI scheme code or free-text scheme name.AMFI — daily refreshNone
validate_gstinStructural + checksum validation of a 15-character GSTIN. Parses out state, embedded PAN, entity code.Offline (mod-36 checksum)None

Planned for v1.1:

ToolPurposeSource
get_stock_quoteLatest quote for NSE/BSE-listed equities.Yahoo Finance proxy (RELIANCE.NS-style symbols)

Quickstart

As an MCP client (Claude Desktop, Cursor, etc.)

You have three options:

Option A — Cloudflare Workers (always-on, no Apify standby needed):

POST https://india-finance-mcp.vamp-fa0.workers.dev/mcp

Speaks MCP Streamable HTTP / JSON-RPC. Works with any MCP client that supports HTTP transport.

Option B — Apify Actor (FastMCP-backed):

Once the actor's standby mode is enabled in the Apify console, point your MCP client at the actor's MCP endpoint at /mcp.

Option C — local stdio:

git clone <this-repo>
cd "Indian finance MCP"
npm install
npm run dev:mcp # stdio transport for local MCP clients

For an interactive UI, use the FastMCP inspector:

$npm run inspect # opens fastmcp dev UI

As an MCP client over plain HTTP (curl)

# initialize
curl -X POST https://india-finance-mcp.vamp-fa0.workers.dev/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'
# tools/list
curl -X POST https://india-finance-mcp.vamp-fa0.workers.dev/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# tools/call
curl -X POST https://india-finance-mcp.vamp-fa0.workers.dev/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"validate_gstin","arguments":{"gstin":"27AAPFU0939F1ZV"}}}'

As a REST client

# Mutual fund NAV by AMFI scheme code
curl 'https://india-finance-mcp.vamp-fa0.workers.dev/api/mutual-fund/nav?code=122639'
# Free-text scheme name search
curl 'https://india-finance-mcp.vamp-fa0.workers.dev/api/mutual-fund/nav?q=parag+parikh+flexi+cap+direct&limit=5'
# GSTIN validation
curl 'https://india-finance-mcp.vamp-fa0.workers.dev/api/gstin/validate?gstin=27AAPFU0939F1ZV'

Sample response (NAV):

{
"query": "122639",
"matches": [
{
"schemeCode": "122639",
"isinGrowth": "INF879O01027",
"isinReinvestment": null,
"schemeName": "Parag Parikh Flexi Cap Fund - Direct Plan - Growth",
"nav": 91.2902,
"date": "30-Apr-2026",
"category": "Open Ended Schemes(Equity Scheme - Flexi Cap Fund)",
"amc": "PPFAS Mutual Fund"
}
],
"asOf": "30-Apr-2026",
"source": "amfi"
}

Sample response (GSTIN):

{
"gstin": "27AAPFU0939F1ZV",
"valid": true,
"errors": [],
"parts": {
"stateCode": "27",
"stateName": "Maharashtra",
"pan": "AAPFU0939F",
"entityCode": "1",
"defaultLetter": "Z",
"checksum": "V"
}
}

Architecture

src/
├── core/ # Pure logic + I/O. Workers-safe. No fastmcp/hono imports.
│ ├── amfi.ts # Fetch + parse + 1h TTL cache + search for AMFI NAV file
│ ├── gstin.ts # Mod-36 checksum, state-code table, structural checks
│ └── types.ts # Shared record/result types
├── tools/ # MCP-tool contracts: zod schema + execute() + _TOOL const
│ ├── mutual-fund-nav.ts
│ └── validate-gstin.ts
├── mcp/
│ └── index.ts # FastMCP entry — addTool(...) per tool, stdio or http-stream
└── rest/
├── app.ts # Hono app — REST routes + POST /mcp (JSON-RPC)
├── mcp-handler.ts # Workers-safe MCP JSON-RPC dispatcher (no fastmcp)
├── worker.ts # Cloudflare Workers entry: { fetch: app.fetch }
└── node.ts # Local-dev entry via @hono/node-server

How a tool is added

  1. Write the logic in src/core/ — pure functions and any caching. Keep this layer dependency-free; it has to run on both Node (Apify) and the Workers runtime.
  2. Define the contract in src/tools/ — export a zod schema, an execute function, and a *_TOOL const that bundles them with the tool's MCP name + description. This contract is reused by both entries.
  3. Wire it into MCP in src/mcp/index.ts via server.addTool({...}). Tool results must be returned as a JSON string.
  4. Wire it into REST in src/rest/app.ts — add a route, parse query params with <schema>.safeParse, call execute, return c.json(...).

This is the rule the codebase optimizes for: one logic implementation, one contract, two transports.

Transport detection (Apify / FastMCP entry)

src/mcp/index.ts chooses transport at startup:

TriggerTransportUse case
APIFY_CONTAINER_PORT sethttpStream on that portApify Actor runtime
FASTMCP_TRANSPORT=http-streamhttpStream on PORT (default 8080)Self-hosted HTTP
NeitherstdioClaude Desktop, local CLI, FastMCP inspector

MCP on Cloudflare Workers (no FastMCP)

The Workers deploy serves MCP via a hand-rolled JSON-RPC handler in src/rest/mcp-handler.ts because FastMCP pulls in Node-only deps that don't bundle for Workers. The handler implements initialize, notifications/initialized (acked with HTTP 202), ping, tools/list, and tools/call. Tool input schemas are emitted from the same zod schemas used by the FastMCP entry, via zod-to-json-schema. Both entries therefore expose identical tool surface — only the framework underneath differs.

Stateless: no session id, no SSE stream. Each POST is one JSON-RPC request and returns one JSON response (or 202 for notifications).

Caching

getNavRecords() in core/amfi.ts memoizes the parsed AMFI file with a 1-hour in-memory TTL plus an inflight request de-dupe (concurrent calls share a single fetch promise).

  • On Node/Apify the cache lives across requests for the lifetime of the process.
  • On Cloudflare Workers it lives per isolate — cold isolates re-fetch. For cross-isolate caching, bind a KV namespace in wrangler.toml (a commented stub is already there) and short-circuit before the AMFI fetch.

AMFI publishes the daily NAV file once per business day around 9–11 PM IST.

Module-resolution gotcha

tsconfig.json uses moduleResolution: "Bundler" with verbatimModuleSyntax: true. Imports between src/ files must end in .js even though the source is .ts:

import { getNavRecords } from "../core/amfi.js"; // ✅
import { getNavRecords } from "../core/amfi"; // ❌ build will fail

Both tsc and Wrangler/esbuild resolve this correctly.

Workers compatibility constraint

src/rest/worker.ts and its transitive imports must be Workers-safe:

  • ✅ Global fetch, pure logic, Hono.
  • process.env, @hono/node-server, anything from src/mcp/, anything from fastmcp. FastMCP pulls in Node-only deps that won't bundle for Workers.

The current import graph through worker.ts → app.ts → tools/* → core/{amfi,gstin}.ts honors this; keep it that way.


Development

Setup

$npm install # ~225 packages

Common commands

npm test # all vitest tests
npx vitest run tests/gstin.test.ts -t "checksum" # single test by file + name
npx vitest # watch mode
npx tsc --noEmit # typecheck only
npm run dev:mcp # tsx watch — stdio MCP server
npm run inspect # fastmcp dev — interactive MCP inspector UI
npm run dev:rest # tsx watch — Hono on http://localhost:3000
npm run cf:dev # wrangler dev — Workers runtime on http://localhost:8787
npx tsx scripts/smoke.ts # end-to-end smoke test against live AMFI

Building

The dist/ build is only needed for the Apify Docker image. Dockerfile runs tsc in the builder stage. Wrangler bundles src/rest/worker.ts directly — no pre-build required for CF Workers.

$npm run build # tsc → dist/

Testing approach

  • tests/amfi.test.ts parses a fixture string covering category headers, AMC headers, blank ;;;;; rows, and N.A. NAV rows. Extend the fixture rather than mocking the fetch.
  • tests/gstin.test.ts covers valid GSTINs, length/format/state/PAN errors, and bad-checksum cases. Bad-state and bad-PAN tests recompute a valid checksum first to isolate the error under test — important when adding new validation rules.
  • _resetCacheForTesting() is exported from core/amfi.ts if a future test needs to re-exercise the fetch path.

Deployment

Apify (MCP server)

npm install -g apify-cli
apify login
apify push --wait-for-finish 600

Configuration lives in .actor/actor.json. The webServerMcpPath field tells Apify to route MCP traffic to /mcp. The Dockerfile is multi-stage (Alpine, build → runtime) and starts the server with FASTMCP_TRANSPORT=http-stream and FASTMCP_STATELESS=true.

After the build succeeds, enable Standby mode in the Apify console to make the MCP endpoint addressable. That step is console-only — no CLI equivalent.

Cloudflare Workers (REST mirror)

npx wrangler login
npx wrangler deploy

wrangler.toml pins account_id (set per-developer; default in this repo is the Vamp account). To use a different account, override with CLOUDFLARE_ACCOUNT_ID or edit the file.

The build is a single bundle (~190 KiB / ~38 KiB gzipped). No KV bindings yet — adding cross-isolate caching is the obvious next infra change.


Project structure

.
├── .actor/ # Apify actor metadata (actor.json, input_schema.json)
├── src/ # See architecture diagram above
├── tests/ # vitest suites
├── scripts/smoke.ts # End-to-end smoke test
├── Dockerfile # Multi-stage build for Apify
├── wrangler.toml # Cloudflare Workers config
├── tsconfig.json # Bundler-mode + verbatimModuleSyntax
├── vitest.config.ts
└── package.json

  • AMFI NAV file (https://www.amfiindia.com/spages/NAVAll.txt) — public, no auth, attribution recommended. The source: "amfi" field is included in every NAV response.
  • GSTIN validation — entirely offline. The mod-36 checksum is the public algorithm published by GSTN. This tool does not call the GSTN portal and does not confirm whether a GSTIN is currently active or registered to any specific entity. It only confirms that the string is structurally well-formed.
  • Stock quotes (planned) — Yahoo Finance has no official free terms-of-use; use at your own risk and consider swapping to a paid provider before commercializing the stock-quote tool.

Roadmap

  • v0.1 — get_mutual_fund_nav, validate_gstin, deployed to Apify + CF Workers
  • v1.1 — get_stock_quote (Yahoo Finance proxy, NSE + BSE)
  • v1.2 — get_market_summary (indices snapshot)
  • Infra — KV-backed NAV cache for cross-isolate persistence on Workers
  • Listings — Apify Store
  • Listings — Smithery, Glama, mcp.so, PulseMCP, official MCP registry

License

MIT