Submit

INDmoney MCP

@VIckys-AI-Stuffs

Give Claude AI read-only access to your entire INDmoney portfolio. Fetch Indian stocks, mutual funds, US stocks, gold, credit cards, loans, savings, and Experian credit score — all from Claude Desktop. Uses Playwright browser automation with OTP login and AES-256-GCM encrypted persistent sessions.
Overview

INDmoney MCP Server

A Model Context Protocol (MCP) server that gives Claude read-only access to your INDmoney portfolio — stocks, mutual funds, US stocks, gold, credit cards, liquid savings, loans, and debt.

Built with Python + Playwright. Uses browser automation for OTP login and network interception to capture live API data. Sessions are encrypted and persist across restarts.


What you can ask Claude

Once connected, you can ask things like:

  • "Show me my stock holdings and P&L"
  • "How are my mutual funds performing?"
  • "What's my US stocks portfolio in INR?"
  • "What's my outstanding credit card balance?"
  • "Give me a full portfolio summary with asset allocation"
  • "How much cash do I have in my savings accounts?"

Features

14 MCP toolsStatus, connect, disconnect, holdings, MF, US stocks, gold, loans, credit cards, liquid, debt, summary, credit score, discover
Persistent sessionsAES-256-GCM encrypted session survives server restarts (12-hour TTL)
Two-level cacheIn-memory (5 min) + disk (60 min) — subsequent queries are instant
Reliable fetchingDirect JWT Bearer calls + page-nav interception fallback
Read-onlyNo order placement, no fund transfers — portfolio data only
Type-safePydantic models throughout; all responses are structured JSON

Requirements

  • Python 3.11+
  • macOS / Linux / Windows (WSL2)
  • Claude Desktop (or any MCP-compatible client)
  • An INDmoney account

Installation

1. Clone and install

git clone https://github.com/VIckys-AI-Stuffs/indmoney-mcp-python.git
cd indmoney-mcp-python

python3.11 -m venv venv
source venv/bin/activate        # Windows: venv\Scripts\activate

pip install -e .
python -m playwright install chromium

2. Generate an encryption key

The server encrypts your session on disk with AES-256-GCM. Generate a persistent key once and keep it — losing it means losing your saved session (you'll just need to log in again):

python3 -c "import secrets; print(secrets.token_hex(32))"
# example output: a3f1c8e2b4d7...  ← copy this value

3. Configure Claude Desktop

Open your Claude Desktop config file and add the indmoney server block. All configuration is passed directly via the env key — no .env file needed.

PlatformConfig file location
macOS~/Library/Application Support/Claude/claude_desktop_config.json
Linux~/.config/Claude/claude_desktop_config.json
Windows%APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "indmoney": {
      "command": "/absolute/path/to/indmoney-mcp-python/venv/bin/python",
      "args": ["/absolute/path/to/indmoney-mcp-python/main.py"],
      "env": {
        "PYTHONUNBUFFERED": "1",
        "SESSION_ENCRYPTION_KEY": "paste-your-32-byte-hex-key-here"
      }
    }
  }
}

Important: Use the full absolute path to venv/bin/python, not just python.

All supported env variables

VariableRequiredDefaultDescription
SESSION_ENCRYPTION_KEYRecommended(auto-generated)32-byte hex key for AES-256-GCM session encryption. If omitted, a new key is generated on every restart and your saved session will be lost each time.
SESSION_TTL_HOURSNo12How long a logged-in session stays valid before requiring re-login
CACHE_TTL_MINUTESNo60Disk cache TTL — how long fetched portfolio data is kept on disk
IN_MEMORY_CACHE_TTL_MINUTESNo5In-memory cache TTL — subsequent queries within this window return instantly
API_REQUEST_TIMEOUTNo10Per-request timeout in seconds
API_TOTAL_TIMEOUTNo60Total timeout for a full data fetch in seconds
LOG_LEVELNoINFOLog verbosity: DEBUG, INFO, WARNING, ERROR
BROWSER_HEADLESSNofalseSet true to hide the browser window (not recommended — you need to see it for OTP login)
BROWSER_DATA_DIRNo./browser-dataPath to store the persistent Playwright browser profile (cookies, localStorage)
SESSIONS_DIRNo./sessionsPath to store encrypted session + cache files

Advanced: full config example with all options

{
  "mcpServers": {
    "indmoney": {
      "command": "/absolute/path/to/indmoney-mcp-python/venv/bin/python",
      "args": ["/absolute/path/to/indmoney-mcp-python/main.py"],
      "env": {
        "PYTHONUNBUFFERED": "1",
        "SESSION_ENCRYPTION_KEY": "paste-your-32-byte-hex-key-here",
        "SESSION_TTL_HOURS": "12",
        "CACHE_TTL_MINUTES": "60",
        "IN_MEMORY_CACHE_TTL_MINUTES": "5",
        "LOG_LEVEL": "INFO",
        "BROWSER_HEADLESS": "false"
      }
    }
  }
}

Alternative: Instead of the env block, you can copy .env.example to .env in the project root and set values there. Both approaches work — the Claude config env block takes precedence over .env if the same key appears in both.

3. Restart Claude Desktop

Quit completely and reopen. The indmoney server should appear in Settings → MCP Servers.


Connecting for the first time

In Claude, say:

Connect me to INDmoney

Claude will:

  1. Open a Chromium browser window
  2. Navigate to INDmoney login
  3. Wait while you enter your phone number + OTP
  4. Detect successful login, save the encrypted session, and close the browser

The OTP login window may timeout after ~30 seconds on Claude's side — that's okay. The browser stays open and the session is saved when you complete the OTP. Call broker_status afterward to confirm.


MCP Tools Reference

Session Management

ToolDescription
broker_statusConnection status, session age, cache inventory
broker_connectOpen browser for OTP login (saves encrypted session)
broker_disconnectLog out, wipe session + cache

Portfolio Data

ToolWhat it returns
get_holdingsIndian stock holdings — symbol, quantity, avg price, current value, P&L
get_mutual_fundsMF holdings — scheme name, invested, current value, returns, XIRR
get_us_stocksUS stock holdings — ticker, quantity, value in INR
get_goldGold holdings (digital gold, SGBs, ETFs)
get_liquidCash / savings — bank balances, FDs, EPF
get_credit_cardsCredit card outstanding balances and due dates
get_loansLoan accounts and outstanding amounts
get_debtDebt instruments (bonds, NCDs, debt MFs)
get_credit_scoreExperian credit score, rating factors, active loans, and credit card limits
get_portfolio_summaryAggregated total invested, current value, P&L, asset allocation

Utilities

ToolDescription
discover_endpointsNavigates dashboard pages and logs all live API URLs — useful if endpoints change

How it works

Claude ──STDIO JSON-RPC──► MCP Server (Python)
                    ┌───────────┴───────────┐
                    │                       │
              Session Manager         INDmoney Scraper
              (disk + AES-256-GCM)    (Playwright)
                    │                       │
              sessions/indmoney/       browser-data/indmoney/
              ├── session.json         (persistent browser profile
              └── cache/               with cookies + localStorage)
                  ├── holdings.json
                  └── ...

Authentication flow:

  1. Playwright launches a persistent Chromium context (keeps cookies/localStorage between runs)
  2. User completes OTP login manually in the browser window
  3. Server extracts the JWT from document.cookie (token cookie on www.indmoney.com)
  4. JWT is stored encrypted on disk; browser context preserves cookies for the lifetime of the session

Data fetching:

  • Most endpoints: page.evaluate(fetch(url, {Authorization: Bearer <jwt>})) — direct API call from the browser context (avoids CORS)
  • Some endpoints (gold, fallbacks): page.expect_response(predicate) while navigating to the relevant SPA page — captures the first matching network response

Configuration

Copy .env.example to .env and edit as needed:

cp .env.example .env
VariableDefaultDescription
SESSION_ENCRYPTION_KEY(auto-generated)32-byte hex key for AES-256-GCM
SESSION_TTL_HOURS12How long a session stays valid
CACHE_TTL_MINUTES60Disk cache TTL
IN_MEMORY_CACHE_TTL_MINUTES5In-memory cache TTL
API_REQUEST_TIMEOUT10Per-request timeout (seconds)
LOG_LEVELINFODEBUG, INFO, WARNING, ERROR
BROWSER_HEADLESSfalseSet true to hide the browser window

If SESSION_ENCRYPTION_KEY is empty, one is auto-generated and printed on first run. Copy it to .env to keep sessions valid across restarts.


Project structure

indmoney-mcp-python/
├── main.py                          # Entry point — STDIO MCP transport
├── pyproject.toml
├── .env.example
├── mcp_server/
│   ├── server.py                    # All 14 MCP tool handlers
│   ├── config.py                    # Config (env vars + paths)
│   ├── logger.py                    # stderr-only logger
│   │
│   ├── types/                       # Pydantic models
│   │   └── portfolio.py             # Holding, MutualFundHolding, CreditCardAccount, …
│   │
│   ├── adapters/indmoney/
│   │   ├── scraper.py               # Playwright fetch + page-nav interception
│   │   ├── endpoints.py             # All API URLs (Octopus, apixt-*, etc.)
│   │   ├── auth.py                  # OTP login flow
│   │   └── parser.py                # Raw API → Pydantic models
│   │
│   ├── session/
│   │   ├── manager.py               # SessionManager singleton
│   │   ├── store.py                 # Disk read/write
│   │   ├── crypto.py                # AES-256-GCM encrypt/decrypt
│   │   └── cache.py                 # Multi-level cache
│   │
│   ├── browser/
│   │   ├── manager.py               # Playwright context lifecycle
│   │   └── interceptor.py           # Network response interception
│   │
│   └── utils/
│       └── retry.py                 # Exponential backoff retry decorator
├── tests/
│   ├── conftest.py                  # Autouse fixture — isolates session dir per test
│   ├── test_integration_basic.py
│   ├── test_phase2_session_management.py
│   ├── test_phase3_browser_automation.py
│   └── test_phase4_scraper_and_parser.py
├── sessions/                        # GITIGNORED — encrypted session data
├── browser-data/                    # GITIGNORED — Playwright persistent profile
└── logs/                            # GITIGNORED — runtime logs

Development

# Activate venv
source venv/bin/activate

# Run tests
pytest tests/ -v

# Run with coverage
pytest --cov=mcp_server tests/

# Code quality
black mcp_server/
isort mcp_server/
flake8 mcp_server/

# Test server directly (no Claude needed)
python -c "
import asyncio
from mcp_server.server import INDmoneyMCPServer

async def main():
    s = INDmoneyMCPServer()
    r = await s._handle_broker_status({})
    print(r[0].text)

asyncio.run(main())
"

# Interactive tool testing
mcp dev main.py

Security

  • Encrypted at rest: Session tokens are encrypted with AES-256-GCM before being written to disk. The key lives only in .env (gitignored).
  • OTP stays in your browser: The OTP you type never passes through the MCP server — it goes directly from your keyboard to the INDmoney website.
  • Read-only: The server has no tools for placing orders, transferring funds, or modifying your account.
  • Local only: All data stays on your machine — nothing is sent to any third-party server.

ToS notice: Browser-based scraping may be against INDmoney's Terms of Service. Use responsibly and at your own risk.


Troubleshooting

See TROUBLESHOOTING.md for detailed solutions to common issues.

Quick fixes:

SymptomFix
Server not showing in ClaudeCheck absolute path in config; restart Claude fully
"not connected" after OTPCall broker_status — session may have saved after timeout
Tools return stale dataAsk Claude to "clear cache and refresh"
Session deleted unexpectedlyNever run pytest without the test isolation fixture
Gold returns nothingYour gold holding may already be in get_holdings (e.g., GOLDBEES ETF)

Contributing

  1. Fork the repo
  2. Create a feature branch: git checkout -b feature/my-thing
  3. Write tests for your changes
  4. Make sure pytest tests/ passes
  5. Open a pull request

All contributions welcome — new broker adapters, parser fixes, documentation improvements.


License

MIT — free to use, modify, and distribute.

Server Config

{
  "mcpServers": {
    "indmoney": {
      "command": "python",
      "args": [
        "-m",
        "mcp_server.main"
      ],
      "env": {
        "PYTHONUNBUFFERED": "1",
        "SESSION_ENCRYPTION_KEY": "<your-32-byte-hex-key>"
      }
    }
  }
}
© 2025 MCP.so. All rights reserved.

Build with ShipAny.

INDmoney MCP MCP Server