Skip to main content
Glama
Sparker0i

Indian Broker MCP Server

by Sparker0i
README.md
# Indian Broker MCP Server

A Model Context Protocol (MCP) server that connects to Indian broker platforms — **Groww**, **Zerodha Kite**, and **INDmoney** — to provide a unified, read-only view of your financial portfolio through Claude Code, Claude Desktop, or any MCP-compatible client.

No paid broker API subscriptions required. The server uses **Playwright browser automation** to capture data from the broker web apps after you log in via a visible Chrome window.

---

## Features

- **Unified portfolio view** across multiple brokers
- **Stocks, F&O, Mutual Funds, US Stocks, Gold** — all asset classes
- **Network interception** captures structured JSON from broker SPAs (more reliable than DOM scraping)
- **Persistent browser sessions** — log in once per session expiry
- **Encrypted session storage** (AES-256-GCM) in memory
- **Read-only** — no order placement, no fund transfers
- **Graceful degradation** — partial data returned if one broker fails

### Broker Support Matrix

| Feature | Groww | Zerodha Kite | INDmoney |
|---|:---:|:---:|:---:|
| Stock Holdings | Yes | Yes | Yes |
| F&O Positions | Yes | Yes | — |
| Mutual Funds | Yes | Yes (Coin) | Yes |
| US Stocks | Yes | — | Yes |
| Gold / SGB | Yes | — | Yes |
| Orders | Yes | Yes | Yes |
| Login Method | Email + OTP | User ID + Password + TOTP | Phone + OTP |

---

## Prerequisites

- **Node.js** 18+
- **Google Chrome** installed (Playwright uses your system Chrome via `channel: 'chrome'`)
- **Claude Code** or **Claude Desktop** (or any MCP client)

---

## Installation

```bash
git clone <repo-url> indian-broker-mcp
cd indian-broker-mcp
npm install
npx playwright install chromium
npm run build
```

## Configuration

Copy the example env file and edit as needed:

```bash
cp .env.example .env
```

### Environment Variables

| Variable | Default | Description |
|---|---|---|
| `SESSION_ENCRYPTION_KEY` | Auto-generated | 32-byte hex key for AES-256-GCM session encryption |
| `SESSION_TTL_HOURS` | `6` | Session expiry time in hours |
| `BROWSER_HEADLESS` | `false` | Set `true` to run browsers headless (login still needs headed mode) |
| `BROWSER_SLOW_MO` | `100` | Delay in ms between Playwright actions (helps avoid detection) |
| `BROWSER_DATA_DIR` | `./browser-data` | Persistent browser profile storage |
| `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error` |
| `RECORDINGS_DIR` | `./recordings` | Output directory for `learn_broker_navigation` |

---

## Connecting to an MCP Client

### Claude Code

```bash
claude mcp add indian-broker -- node /path/to/indian-broker-mcp/build/index.js
```

### Claude Desktop

Add to your Claude Desktop config (`~/.config/claude/claude_desktop_config.json` on Linux, `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):

```json
{
  "mcpServers": {
    "indian-broker": {
      "command": "node",
      "args": ["/path/to/indian-broker-mcp/build/index.js"]
    }
  }
}
```

Restart Claude Desktop after adding the configuration.

### MCP Inspector (for testing)

```bash
npx @modelcontextprotocol/inspector node ./build/index.js
```

Opens a web UI at `http://localhost:5173` where you can call tools interactively.

---

## Usage

### Step 1: Connect to a broker

Ask Claude:

> "Connect me to Zerodha"

This calls the `broker_connect` tool, which:
1. Opens a visible Chrome window to the broker's login page
2. You log in manually (including OTP / 2FA)
3. The server detects login success automatically and captures the session

You can also connect using cookies from your browser's DevTools:

> "Connect to Groww using these cookies: `<paste from document.cookie>`"

### Step 2: Query your portfolio

Once connected, ask naturally:

- "What are my stock holdings?"
- "Show my mutual fund portfolio across all brokers"
- "What's my total portfolio value?"
- "Show my F&O positions on Zerodha"
- "What US stocks do I hold?"
- "Show today's orders"
- "Search for Reliance stock"

### Step 3: Disconnect

> "Disconnect from Zerodha"

This wipes the session data and deletes the browser profile for that broker.

---

## Tools Reference

### Authentication

| Tool | Parameters | Description |
|---|---|---|
| `broker_connect` | `broker` (groww/zerodha/indmoney), `method` (browser_login/cookies), `cookies?` | Connect to a broker |
| `broker_disconnect` | `broker` | Disconnect and wipe session |
| `broker_status` | — | Show connection status for all brokers |

### Portfolio (Read-Only)

| Tool | Parameters | Description |
|---|---|---|
| `get_holdings` | `broker` (default: all) | Stock holdings |
| `get_positions` | `broker` (default: all) | Open positions (intraday/delivery) |
| `get_fno_positions` | `broker` (default: all) | F&O positions specifically |
| `get_mutual_funds` | `broker` (default: all) | Mutual fund portfolio |
| `get_us_stocks` | `broker` (default: all) | US stock holdings |
| `get_gold` | `broker` (default: all) | Gold / SGB / Gold ETF holdings |
| `get_orders` | `broker` (default: all) | Today's order history |
| `get_portfolio_summary` | — | Aggregated summary across all brokers |

### Market Data

| Tool | Parameters | Description |
|---|---|---|
| `search_stock` | `query`, `broker?` | Search for stocks/MFs by name or symbol |
| `get_quote` | `symbol`, `broker?` | Current price quote for a stock |

### Development

| Tool | Parameters | Description |
|---|---|---|
| `learn_broker_navigation` | `broker`, `url?` | Record browser navigation, XHR requests, and DOM snapshots for building/updating scrapers |

---

## Resources

MCP Resources provide cached data accessible by URI:

| URI | Description |
|---|---|
| `broker://status` | Connection status for all brokers |
| `broker://{name}/holdings` | Holdings for a specific broker (e.g., `broker://zerodha/holdings`) |
| `broker://{name}/mutual-funds` | Mutual funds for a specific broker |
| `portfolio://summary` | Aggregated portfolio summary |

---

## Architecture

```
MCP Client (Claude Code / Desktop)
        │
        │ STDIO (JSON-RPC)
        ▼
┌─────────────────────────────────┐
│       MCP Server (Node.js)      │
│                                 │
│  ┌─────────┐ ┌───────┐ ┌─────┐ │
│  │  Groww   │ │Zerodha│ │ IND │ │
│  │ Adapter  │ │Adapter│ │money│ │
│  └────┬─────┘ └───┬───┘ └──┬──┘ │
│       │           │        │    │
│  ┌────▼───────────▼────────▼──┐ │
│  │   Playwright (Chrome)      │ │
│  │   • Network interception   │ │
│  │   • Page navigation        │ │
│  │   • Persistent contexts    │ │
│  └────────────────────────────┘ │
│                                 │
│  ┌────────────────────────────┐ │
│  │  Session Store (encrypted) │ │
│  └────────────────────────────┘ │
└─────────────────────────────────┘
```

### How data extraction works

1. **Navigate** to the relevant broker page (e.g., holdings dashboard)
2. **Intercept** the XHR/fetch responses the SPA makes to its internal APIs
3. **Parse** the structured JSON from those responses
4. **Normalize** broker-specific fields into unified types
5. **Return** to the MCP client in a consistent format

Network interception is the primary strategy because it captures clean, structured data directly from the broker's internal APIs — far more reliable than parsing the DOM.

---

## Project Structure

```
src/
├── index.ts                    # Entry point (STDIO transport)
├── server.ts                   # MCP server, tool/resource registration
├── types/
│   ├── portfolio.ts            # Holding, Position, MutualFundHolding, etc.
│   ├── broker.ts               # BrokerAdapter interface
│   └── auth.ts                 # Session types
├── adapters/
│   ├── base.ts                 # Abstract base adapter
│   ├── groww/
│   │   ├── index.ts            # Adapter + normalizers
│   │   ├── scraper.ts          # Network interception logic
│   │   ├── endpoints.ts        # URL patterns
│   │   ├── selectors.ts        # DOM selectors (fallback)
│   │   └── types.ts            # Raw API response types
│   ├── zerodha/                # Same structure
│   └── indmoney/               # Same structure
├── browser/
│   ├── manager.ts              # Browser lifecycle, persistent contexts
│   ├── auth-flow.ts            # Login detection + session capture
│   ├── interceptor.ts          # XHR/fetch response capture engine
│   ├── recorder.ts             # Navigation recorder for development
│   └── helpers.ts              # Utilities (delays, screenshots)
├── auth/
│   ├── crypto.ts               # AES-256-GCM encrypt/decrypt
│   └── session-store.ts        # In-memory encrypted session store
├── normalizer/
│   └── index.ts                # Portfolio summary aggregation
└── utils/
    ├── logger.ts               # stderr-only logger
    ├── config.ts               # .env config loader
    └── retry.ts                # Exponential backoff retry
```

---

## Session Management

- Sessions are stored **encrypted in memory** using AES-256-GCM
- Browser profiles are persisted to disk under `browser-data/{broker}/` so cookies survive server restarts
- Sessions auto-expire after the configured TTL (default: 6 hours)
- When a session expires, the next data request will return an error prompting you to reconnect
- `broker_disconnect` securely wipes both the in-memory session and the on-disk browser profile
- Each broker is fully isolated in its own browser context

### Typical session lifetimes

| Broker | Approximate Session Duration |
|---|---|
| Zerodha Kite | 6–8 hours |
| Groww | Varies |
| INDmoney | Days to weeks |

---

## Development

### Adding or updating broker scrapers

The `learn_broker_navigation` tool helps you discover and update internal API endpoints:

1. Call the tool: `learn_broker_navigation` with `broker: "groww"`
2. A Chrome window opens — log in and navigate to the pages you care about
3. The recorder captures every URL, XHR request/response, and DOM state
4. Recordings are saved to `recordings/{broker}/{timestamp}/`
5. Use the captured data to update `endpoints.ts` and `types.ts` for that broker

### Watch mode

```bash
npm run dev    # tsc --watch
```

### Key design decisions

- **Network interception over DOM scraping**: Broker SPAs fetch data via internal REST APIs. Intercepting those JSON responses is more reliable and structured than parsing rendered HTML.
- **Persistent browser contexts**: Using Playwright's `launchPersistentContext` so cookies/localStorage survive restarts. The user only needs to log in when the session expires.
- **Anti-detection**: Uses real Chrome (not Chromium), removes `webdriver` flag, adds random delays between actions.
- **Flexible response parsing**: Each adapter's normalizer handles multiple possible response shapes (brokers may change their API structure). Fields are accessed with fallback chains (`raw.field1 ?? raw.field2 ?? default`).

---

## Security

- **No credentials stored** — you log in manually; only session cookies are captured
- **AES-256-GCM encryption** for all in-memory session data
- **Cookies and tokens are never logged** — the logger redacts sensitive data
- **All output goes to stderr** — stdout is reserved for MCP JSON-RPC (writing to stdout would break the protocol)
- **Browser profiles are gitignored** and deleted on disconnect
- **Strictly read-only** — there are no tools for placing orders, modifying positions, or transferring funds

---

## Limitations

- **Browser scraping is fragile** — broker UIs and internal APIs change without notice. Use `learn_broker_navigation` to recalibrate when something breaks.
- **OTP login requires user presence** — Groww and INDmoney require manual OTP entry. Zerodha requires TOTP/PIN.
- **No real-time streaming** — data is fetched on demand by navigating to pages. There is no WebSocket or live price feed.
- **Rate limiting** — avoid calling portfolio tools in rapid succession. The server adds delays between page navigations but aggressive use may trigger broker anti-bot measures.
- **Terms of Service** — automated access to broker web apps may violate their terms. This tool is intended for personal use only.
- **Single user** — the server manages one session per broker. It is not designed for multi-user or shared access.

---

## License

MIT

TDQS

B3.2/5.0

Scored across 14 tools

Disambiguation4/5

Most tools have clearly distinct purposes, but get_positions and get_fno_positions could be confused since F&O positions are a subset of positions. Similarly, get_holdings, get_mutual_funds, get_us_stocks, and get_gold are differentiated by asset type, which is clear. Overall, the tools are separable by their descriptions.

Naming Consistency3/5

The naming convention is mixed: some tools follow a verb_noun pattern (e.g., get_holdings, search_stock), while others use a noun_verb pattern (e.g., broker_connect, broker_disconnect). This inconsistency is not chaotic but could be more uniform. Both patterns use lowercase with underscores, so it's readable.

Tool Count5/5

14 tools is appropriate for a broker aggregation server. The count is well within the typical 3-15 range, and each tool addresses a specific aspect of broker connectivity, data retrieval, or usability. None feel redundant.

Completeness3/5

The tool set covers connection management, holdings, positions, and orders, but misses obvious financial data like cash balances and trade history. It also lacks any trading or order placement capabilities, which could be expected for a broker MCP, though it may be intentionally read-only. The core read-only aggregation surface is present, but notable gaps exist.

Maintenance

ActivityInactive
ResponsivenessNo issues