DEV Community

Cover image for I built an open-source MCP server that gives any AI assistant live NSE + BSE stock data
Govind Sisara
Govind Sisara

Posted on

I built an open-source MCP server that gives any AI assistant live NSE + BSE stock data

The itch

Ask ChatGPT or Claude "what was Reliance's operating margin last quarter?" and you get one of two answers: a polite "I don't have live data," or a confident, wrong number. The reasoning is great. The data access is nonexistent — these models are blind to anything past their training cut-off, and they have zero native window into NSE/BSE.

So I built an MCP server to fix it, and open-sourced it. This is the build story + a quick-start if you want to plug it into your own setup.

30-second MCP refresher

The Model Context Protocol is an open standard that lets AI assistants call external tools through a consistent interface. Instead of guessing, the model issues a structured request — get_stock_quote for RELIANCE — gets real data back, and reasons over it. One protocol, and Claude, ChatGPT, Cursor, Gemini, and Grok can all hit the same data source.

It's basically USB-C for AI tools.

What I exposed: 34 tools

search_stocks            screen_stocks (326 fundamental filters)
screen_stocks_technical  get_company_profile   get_financials
get_stock_quote          get_price_history     get_shareholding
get_fii_dii_detail       market_ipo            market_fno_ban
get_user_portfolio       add_to_watchlist      ...and 21 more
Enter fullscreen mode Exit fullscreen mode

Coverage: all ~8,200 NSE + BSE stocks, fundamentals, technicals, institutional flows, market data, and portfolio tracking. (It's a research tool, not a broker — it doesn't place trades.)

Architecture decisions

The big one: remote-first, on the edge.

┌─────────────────┐   JSON-RPC / HTTPS   ┌──────────────────────┐
│  AI Assistant   │ ───────────────────► │  Cloudflare Worker   │
│ (Claude, etc.)  │ ◄─────────────────── │  (stateless MCP)     │
└─────────────────┘                       └──────────────────────┘
                                              │
                                   D1 (users, tokens, usage)
                                   KV (rate limits, auth codes)
Enter fullscreen mode Exit fullscreen mode

Most MCP servers ship as local stdio processes you have to install and run. That's a friction wall for non-developers. I wanted someone to paste one URL into claude.ai and be done — so the server runs as a Cloudflare Worker. Globally distributed, no servers to babysit.

Stateless transport

The MCP SDK's WebStandardStreamableHTTPServerTransport in stateless mode maps perfectly onto Workers — any request hits any edge location and is served identically:

const server = createServer(env, ph, userId);
const transport = new WebStandardStreamableHTTPServerTransport({
  sessionIdGenerator: undefined,  // stateless
  enableJsonResponse: true,
});
await server.connect(transport);
Enter fullscreen mode Exit fullscreen mode

Auth was the hard part

MCP clients vary wildly. Chat apps (Claude.ai, ChatGPT) expect a full OAuth flow with Dynamic Client Registration (RFC 7591) plus discovery endpoints (RFC 8414, RFC 9728). Code editors often just want a bearer token.

The trick that makes the OAuth handshake "just work": return a 401 with a WWW-Authenticate header on the first initialize. That's the signal that kicks off the client's built-in OAuth flow.

if (!authHeader?.startsWith("Bearer ") && !isPublicMethod) {
  return Response.json(
    { error: "authentication_required" },
    { status: 401, headers: {
        "WWW-Authenticate":
          `Bearer resource_metadata="${metadataUrl}", scope="openid email"`,
    }},
  );
}
Enter fullscreen mode Exit fullscreen mode

So the server accepts both short-lived HMAC access tokens and long-lived personal tokens, distinguished by prefix (tpt_rt_…). One auth surface, two credential types. tools/list and ping stay public so registries can discover the catalog without auth.

Rate limiting that doesn't punish honest users

Two independent layers:

  1. Per-minute burst smoother (KV, fails open) — stops one token from dumping its whole daily allowance in seconds. If KV hiccups, allow the request; the daily cap is the real ceiling.
  2. Daily/monthly quota (D1, fails closed) — an atomic UPSERT reserves a unit before the tool runs. Limiter unreachable → deny, never hand out unmetered access.

The part I'm happiest with: failed calls get refunded. The MCP SDK throws InvalidParams whenever a tool argument fails schema validation — and LLMs hallucinate bad arguments constantly. Charging a user's quota because their model fumbled an argument would be infuriating.

if (quotaConsumed && userId) {
  quotaConsumed = false;            // guard against double-refund
  if (hasError) {
    ctx.waitUntil(refundRateLimitV2(env.DB, userId, date, month));
  } else {
    ctx.waitUntil(trackToolCall(env.DB, userId, src));
  }
}
Enter fullscreen mode Exit fullscreen mode

The npm package is just a bridge

For stdio-only clients there's a tiny npm package — ~300 lines, zero runtime deps. No business logic: it reads JSON-RPC from stdin, forwards to the Worker over HTTPS, writes responses to stdout. It auto-detects message framing (Content-Length vs newline-delimited JSON, which differ across clients) and refreshes the access token before expiry. All tool logic lives on the server, so new tools ship instantly without anyone running npm update.

Quick start

No install (claude.ai, ChatGPT, Gemini, Grok) — paste the URL, sign in with Google:

https://mcp.tapetide.com/mcp
Enter fullscreen mode Exit fullscreen mode

Local via npm (Cursor, Windsurf, Claude Desktop):

{
  "mcpServers": {
    "tapetide": {
      "command": "npx",
      "args": ["-y", "tapetide-mcp"],
      "env": { "TAPETIDE_TOKEN": "your_token_here" }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Then just ask:

"Find mid-caps where FII holding rose last quarter, ROE above 15%, and RSI under 40."

Lessons if you're building your own MCP server

  • Go remote if your audience isn't all devs. A pasteable URL beats a npx command for reach.
  • Stateless + edge is a natural fit for MCP's request/response shape.
  • Budget real time for OAuth + DCR. It's the least glamorous, most fragile part — implement the .well-known discovery endpoints precisely.
  • Support more than one credential type. Chat apps and editors want different things.
  • Refund quota on errors. LLMs make bad tool calls all the time; don't bill users for it.

Free and open source under MIT. Source, all 34 tools, and setup guides:

🔗 https://github.com/Tapetide-hq/nse-bse-indian-stock-market-data-mcp

If you build something on top of it or have ideas for tools you'd want, I'd love to hear it in the comments.

Top comments (0)