| Decision | Choice | Why |
|---|---|---|
| Language | TypeScript end-to-end | The official MCP TypeScript SDK has a first-class Streamable HTTP client; one language lets the UI and backend share types, the tool catalog, argument validation and analytics. |
| Backend | Node.js + Express 5 (one small process) | NSE’s CORS policy blocks browsers, so a backend must be the MCP client. Express is the most familiar choice for readers of an educational repo. |
| Frontend | React 19 + Vite, no UI/chart libraries | Small, readable components. Charts are ~200 lines of SVG — enough for line/volume/bar/range views without a dependency. |
| Analytics | Pure TypeScript functions (shared/analytics.ts) |
NSE already aggregates server-side (SMA, volume stats, 52W range, comparisons). What’s missing — corporate-action adjustment, EMA/RSI/volatility/drawdown series, relative volume — is small and runs in both browser and server. Python/Pandas was evaluated and rejected: responses are ≤ ~40 KB and the computations are simple, so a second runtime would add setup cost with no benefit. |
| Python | Example only (examples/python) |
Shows the official mcp Python SDK for developers who prefer it; tested against the mock. |
| Offline/testing | Mock MCP server built with the same SDK, replaying recorded NSE responses | NSE availability is intermittent; tests must not depend on it, and new users should be able to explore offline. |
| AI agent | Optional, Anthropic SDK manual tool-use loop | Demonstrates MCP’s core value (model chooses tools from tools/list) without becoming a separate product. Disabled unless ANTHROPIC_API_KEY is set. |
| Storage | None | Nothing to persist. A 60-second in-memory cache avoids re-hitting NSE. |
┌──────────────────────── Browser ────────────────────────┐
│ React UI (web/src) │
│ Learn · Dashboard · Explorer · Examples · Insights · │
│ Integrate · Agent · Protocol log │
└───────────────┬─────────────────────────────────────────┘
│ JSON over HTTP (/api/*)
┌───────────────▼──────────── Node backend (server/src) ─────────────────────┐
│ app.ts Express routes, error mapping │
│ analytics/recipes multi-tool compositions (deep dive, unusual volume, …) │
│ agent/agent.ts optional Claude tool-use loop over discovered tools │
│ mcp/hub.ts NseMcpHub: routing, validation, limiter, cache, stats │
│ mcp/connection.ts one MCP Client + StreamableHTTPClientTransport per server│
│ mcp/wiretap.ts fetch wrapper that records every JSON-RPC exchange │
└───────────────┬───────────────────────────────┬────────────────────────────┘
│ MCP (JSON-RPC over Streamable HTTP)
┌────────────▼────────────┐ ┌──────────▼──────────────┐
│ cm-market-mcp │ │ nse-bhavcopy-redis-mcp │
│ mcp.nseindia.in/cmmkt │ │ …/bhavcopy/cm/mcp │
└─────────────────────────┘ └─────────────────────────┘
(or mock/server.ts replaying mock/fixtures/nse-fixtures.json)
shared/ ← imported by both sides
types.ts API contracts
catalog.ts server list, tool metadata (category, example args, view), param options
mcpResult.ts parse CallToolResult (JSON / number / soft error), validate arguments
analytics.ts candles, CA adjustment, SMA/EMA/RSI, volatility, drawdown, gaps, RVOL
inputSchema, validates with validateArguments and POSTs /api/tools/:name/execute.NseMcpHub.execute finds the tool (from tools/list), re-validates/coerces arguments, checks the 60 s cache.McpConnection.callTool.initialize → notifications/initialized → tools/list on first use; reconnects and retries (max 2) on session loss (HTTP 404) or connection reset. Timeouts are not retried.parseToolResult turns the text block into JSON / number / text and detects soft errors.CallToolResult, and the wire exchange. The UI renders a tailored view (ResultViews.tsx) chosen by the catalog’s view.tools/list. The catalog only adds metadata; unknown tools fall back to a generic renderer and the dashboard warns when NSE adds or removes tools.shared/ and are used by UI, server, scripts and tests.shared/catalog.ts (category, example, view) for a tailored experience; run npm run record-fixtures.ViewKind in shared/types.ts and a renderer in web/src/components/ResultViews.tsx.shared/analytics.ts + unit test.server/src/analytics/recipes.ts, route in app.ts, tab in web/src/pages/Insights.tsx.ANTHROPIC_API_KEY, read from the environment/.env (git-ignored) and used server-side only.127.0.0.1 by default.