Skip to main content

MCP server for INDmoney — read-only portfolio access via Claude (stocks, MF, US stocks, gold, credit cards, liquid, loans, debt)

Project description

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 tools Status, connect, disconnect, holdings, MF, US stocks, gold, loans, credit cards, liquid, debt, summary, credit score, discover
Persistent sessions AES-256-GCM encrypted session survives server restarts (12-hour TTL)
Two-level cache In-memory (5 min) + disk (60 min) — subsequent queries are instant
Reliable fetching Direct JWT Bearer calls + page-nav interception fallback
Read-only No order placement, no fund transfers — portfolio data only
Type-safe Pydantic 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.

Platform Config 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

Variable Required Default Description
SESSION_ENCRYPTION_KEY Recommended (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_HOURS No 12 How long a logged-in session stays valid before requiring re-login
CACHE_TTL_MINUTES No 60 Disk cache TTL — how long fetched portfolio data is kept on disk
IN_MEMORY_CACHE_TTL_MINUTES No 5 In-memory cache TTL — subsequent queries within this window return instantly
API_REQUEST_TIMEOUT No 10 Per-request timeout in seconds
API_TOTAL_TIMEOUT No 60 Total timeout for a full data fetch in seconds
LOG_LEVEL No INFO Log verbosity: DEBUG, INFO, WARNING, ERROR
BROWSER_HEADLESS No false Set true to hide the browser window (not recommended — you need to see it for OTP login)
BROWSER_DATA_DIR No ./browser-data Path to store the persistent Playwright browser profile (cookies, localStorage)
SESSIONS_DIR No ./sessions Path 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

Tool Description
broker_status Connection status, session age, cache inventory
broker_connect Open browser for OTP login (saves encrypted session)
broker_disconnect Log out, wipe session + cache

Portfolio Data

Tool What it returns
get_holdings Indian stock holdings — symbol, quantity, avg price, current value, P&L
get_mutual_funds MF holdings — scheme name, invested, current value, returns, XIRR
get_us_stocks US stock holdings — ticker, quantity, value in INR
get_gold Gold holdings (digital gold, SGBs, ETFs)
get_liquid Cash / savings — bank balances, FDs, EPF
get_credit_cards Credit card outstanding balances and due dates
get_loans Loan accounts and outstanding amounts
get_debt Debt instruments (bonds, NCDs, debt MFs)
get_credit_score Experian credit score, rating factors, active loans, and credit card limits
get_portfolio_summary Aggregated total invested, current value, P&L, asset allocation

Utilities

Tool Description
discover_endpoints Navigates 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
Variable Default Description
SESSION_ENCRYPTION_KEY (auto-generated) 32-byte hex key for AES-256-GCM
SESSION_TTL_HOURS 12 How long a session stays valid
CACHE_TTL_MINUTES 60 Disk cache TTL
IN_MEMORY_CACHE_TTL_MINUTES 5 In-memory cache TTL
API_REQUEST_TIMEOUT 10 Per-request timeout (seconds)
LOG_LEVEL INFO DEBUG, INFO, WARNING, ERROR
BROWSER_HEADLESS false Set 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:

Symptom Fix
Server not showing in Claude Check absolute path in config; restart Claude fully
"not connected" after OTP Call broker_status — session may have saved after timeout
Tools return stale data Ask Claude to "clear cache and refresh"
Session deleted unexpectedly Never run pytest without the test isolation fixture
Gold returns nothing Your 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

indmoney_mcp-1.0.0.tar.gz (59.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

indmoney_mcp-1.0.0-py3-none-any.whl (54.2 kB view details)

Uploaded Python 3

File details

Details for the file indmoney_mcp-1.0.0.tar.gz.

File metadata

  • Download URL: indmoney_mcp-1.0.0.tar.gz
  • Upload date:
  • Size: 59.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for indmoney_mcp-1.0.0.tar.gz
Algorithm Hash digest
SHA256 f8861e4def763413987a53719b2429bb4dbf66584561fd04fa67b228f736eae5
MD5 dac13c59494639b0066cd3d20153b0c0
BLAKE2b-256 a500630124d16ec75c11da32fd60063c1554c3db40b54ae8539481ce9353ebff

See more details on using hashes here.

File details

Details for the file indmoney_mcp-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: indmoney_mcp-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 54.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for indmoney_mcp-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b4ee3440c13adeb827f9e26c284838c76cf61617bf6d78277de0603654bff3b8
MD5 1102d05aaaa007f170c9d268f297991a
BLAKE2b-256 5bbe2fa341bad272b36079c983ea4fa525a362d5bd3118b5aeb9740c9f443a51

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page