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 justpython.
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
envblock, you can copy.env.exampleto.envin the project root and set values there. Both approaches work — the Claude configenvblock takes precedence over.envif 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:
- Open a Chromium browser window
- Navigate to INDmoney login
- Wait while you enter your phone number + OTP
- 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_statusafterward 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:
- Playwright launches a persistent Chromium context (keeps cookies/localStorage between runs)
- User completes OTP login manually in the browser window
- Server extracts the JWT from
document.cookie(tokencookie onwww.indmoney.com) - 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_KEYis empty, one is auto-generated and printed on first run. Copy it to.envto 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
- Fork the repo
- Create a feature branch:
git checkout -b feature/my-thing - Write tests for your changes
- Make sure
pytest tests/passes - Open a pull request
All contributions welcome — new broker adapters, parser fixes, documentation improvements.
License
MIT — free to use, modify, and distribute.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8861e4def763413987a53719b2429bb4dbf66584561fd04fa67b228f736eae5
|
|
| MD5 |
dac13c59494639b0066cd3d20153b0c0
|
|
| BLAKE2b-256 |
a500630124d16ec75c11da32fd60063c1554c3db40b54ae8539481ce9353ebff
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4ee3440c13adeb827f9e26c284838c76cf61617bf6d78277de0603654bff3b8
|
|
| MD5 |
1102d05aaaa007f170c9d268f297991a
|
|
| BLAKE2b-256 |
5bbe2fa341bad272b36079c983ea4fa525a362d5bd3118b5aeb9740c9f443a51
|