Broker-mcp
Read-only MCP server that connects a Broker trading account to AI clients, providing account data, positions, orders, and market data via 21 tools, with a mock sandbox mode for evaluation.
README
Broker-mcp — Broker MCP Server (Phase 1 · read-only · stdio)
A first-party Model Context Protocol server that connects a customer's Broker (Broker by Parent Company) trading account to any MCP-compatible AI client — Claude Desktop, Cursor, VS Code and others. Built to PRD v1.3 ("Broker MCP — Product Requirements Document"), this is the Phase 1 deliverable: read-only, local (stdio) only.
This server cannot trade. Order placement/modification/cancellation tools are not merely disabled — they do not exist in this codebase (FR-G1, the Zerodha excluded-tools pattern). Nothing here can change account state at Broker, move funds, or sell holdings. Phase 2 (trade tools behind guardrails) is a separate, compliance-gated build.
1. What is implemented (PRD traceability)
Tools (21, all annotated readOnlyHint for account data)
| Tool | What it does | PRD |
|---|---|---|
get_login_url / complete_login / session_status / logout |
Daily login handoff: browser link → Broker's own login page → one-time request token → encrypted local session | FR-A1–A5 |
get_profile |
Account profile | FR-R1 |
get_margins |
Equity + commodity funds/margins (optionally per segment) | FR-R1 |
get_holdings |
Demat holdings with avg cost, LTP, day & overall P&L | FR-R2 |
get_positions |
Net + day positions with P&L | FR-R2 |
get_ltp / get_ohlc / get_quote |
Prices for many instruments; batch limits 1,000 / 1,000 / 500 enforced with transparent chunking | FR-R3, V3 |
resolve_symbol |
"BANKNIFTY next expiry 52000 CE" → exactly one instrument, or candidates to disambiguate (never guesses) | FR-R4, V2 |
get_expiries / get_option_chain |
Option expiries and chain (strikes × LTP/OI/volume/bid/ask around ATM). Greeks/IV honestly reported as unavailable | FR-R5 |
get_historical |
Daily/intraday candles (8 documented intervals) with range guards | FR-R6 |
get_orders / get_order / get_trades |
Order book, order history, trade book — read only | FR-R7 |
calculate_margin |
Pre-trade margin for hypothetical orders; uses Broker's margin API when live, else a clearly-labelled rough estimate | FR-R8 |
server_status / refresh_instruments |
Diagnostics, per-tool metrics, instrument-master refresh | FR-O4, V2 |
Guardrails & controls in this build
- Read-only by construction — no write tool registered anywhere (FR-G1; guardrail stage 3).
- Audit trail — every tool call written to append-only JSONL with UTC timestamp, unique
correlation ID (
mcp-…), user id, redacted arguments, outcome and latency (FR-G7; stage 10). Location:<data dir>/audit/audit-YYYYMMDD.jsonl. - Assistant framing — server instructions and tool descriptions state: knowledgeable assistant, not an autonomous trader; no Broker-authored advice; never fabricate Greeks/IV; credentials only on Broker's own pages (FR-G8, R7 mitigation).
- Readable errors — raw 4xx/5xx bodies never reach the model; failures follow the PRD §4.7 message patterns ("Your Broker session has expired — reconnect to continue", "Insufficient margin…", "I couldn't find that contract — did you mean…") (FR-O1).
- Rate limiting — client-side token bucket (default 3 req/s, far below anything order-loop shaped) plus exponential backoff and a readable message on upstream 429 (FR-O2). Broker publishes no rate limits; the cap is deliberately conservative.
- Timestamps + source labels — every response is wrapped in an envelope with
as_of_utc,as_of_ist, adata_sourcelabel ("point-in-time snapshot, not a live stream" / "MOCK SANDBOX DATA") and a market-session hint (FR-O3). - Token security — the daily access token is stored only on the user's machine, encrypted at rest (Fernet), never transmitted to any Broker-hosted MCP infrastructure (none exists in Phase 1). Corrupt stores are discarded, forcing a clean reconnect (FR-A5). Daily expiry is handled gracefully with a reconnect prompt (FR-A4).
- Input validation — typed schemas on every tool (pydantic), field-level rejection messages (V1); instrument references must resolve to exactly one contract or the tool asks (V2); batch limits chunked transparently (V3); session freshness checked at call time (V14).
Verification status (FR-O6)
- 57 unit tests, all passing (
pytest): schemas, chunking, symbol-resolution grammar, option chain composition, error translation, token-store encryption round-trip, audit redaction, plus end-to-end tool calls through the real FastMCP layer. - stdio protocol smoke test passing: the server was spawned by a real MCP client
(
mcp.client.stdio), initialized (protocol2025-11-25), tools listed with annotations, tools called, error paths exercised — the equivalent of the MCP Inspector check the PRD requires before client wiring. - A multi-agent adversarial code review (PRD-compliance / correctness / security / SDK-usage) was run on this codebase; confirmed findings were fixed.
2. What works right now vs. what is gated
Works today, no dependencies: mock sandbox mode
Broker_MCP_MODE=mock (or Broker-mcp --mock) runs the full server against a deterministic
built-in sandbox — no credentials, no network. Every tool works: a realistic instrument master
(NIFTY/BANKNIFTY option chains, equities, futures), holdings, positions, an order book with
COMPLETE/OPEN/REJECTED orders, historical candles. All responses are loudly labelled
"MOCK SANDBOX DATA — synthetic values… NOT real market data." This is the evaluation,
demo and client-integration surface, and it satisfies the PRD's sandbox-before-live posture.
Live mode — gated on the Broker open-API programme reaching GA
The live client is fully implemented against the verified Broker API surface (checked
19 Jul 2026 against developer.Broker.in and the official PyBrokerAPI SDK source): host
api.Broker.in, Authorization: token api_key:access_token, checksum-based token exchange,
gzipped daily instruments CSV, quote batch limits, historical intervals. To go live you need,
from the Broker Developer Portal: an app (API key + secret) with its redirect URL and
static IPs registered — i.e. Phase 0 of the PRD ("open APIs at GA") must be true for the
account. Until then, live calls fail with readable configuration/session errors.
Known open items (flagged in code, degrade gracefully)
| Item | Status | Behaviour today |
|---|---|---|
POST /optionchain, /optionchain/expirylist |
In the official SDK, not on the docs site — PRD says confirm GA with API team | Tried first; on failure the chain is composed from instrument master + batched quotes (OI/volume live, Greeks/IV honestly absent) |
POST /margins/orders, /margins/basket |
Same "confirm GA" flag | Tried first; falls back to a clearly-labelled rough estimate (authoritative: false) |
| Access-token expiry time | Broker's own docs contradict themselves (12 AM vs 6 AM IST) | Session marked suspect after midnight, expired at 6 AM; the API's own 401 always wins and produces a reconnect prompt |
| API version header | Docs majority X-Version: 3, SDK sends X-Broker-Version: 3 |
Both sent; smoke-test at GA |
| Rate limits | Not documented by Broker anywhere | Conservative client-side cap (3 req/s) |
| Refresh-token / connect-once UX (PRD Q5) | Open decision for API/Security | Not built; daily reconnect flow implemented |
3. Quickstart
Windows (PowerShell):
cd Broker-mcp
python -m venv .venv
.venv\Scripts\python -m pip install -e ".[dev]"
.venv\Scripts\python .venv\Scripts\pywin32_postinstall.py -install # required: places pywin32 DLLs
.venv\Scripts\python -m pytest # 57 tests
.venv\Scripts\Broker-mcp --mock # run the server (stdio) in sandbox mode
The
pywin32_postinstallstep is required on Windows: the officialmcpSDK importspywintypesfor its stdio transport, and pip alone does not always place the loader DLL. Skip it and bothpytestand the server fail withImportError: DLL load failed while importing _win32sysloader. The COM-registration warnings it prints (needs admin) are harmless.
macOS / Linux:
cd Broker-mcp
python -m venv .venv
.venv/bin/python -m pip install -e ".[dev]"
.venv/bin/python -m pytest # 57 tests
.venv/bin/Broker-mcp --mock # run the server (stdio) in sandbox mode
Note: the running server prints nothing and waits silently — that is correct. An MCP stdio server is not a REPL; it waits for a client (Claude Desktop, Inspector) to speak JSON-RPC on stdin. Press
Ctrl+Cto stop it. Clients launch their own copy of the server; you do not run it by hand for them.
Troubleshooting the environment
| Symptom | Cause | Fix |
|---|---|---|
ModuleNotFoundError: No module named 'pydantic_core._pydantic_core' (or a stale *.cp3XX-win_amd64.pyd for the wrong version) |
The .venv mixes wheels built for a different Python (e.g. a 3.12 wheel under a 3.13 interpreter — often from a venv reused after a Python upgrade) |
Recreate the venv with the current Python: delete .venv, then repeat the steps above. Quick check: .venv\Scripts\python --version must match the cp3XX tag on the .pyd files in .venv\Lib\site-packages\pydantic_core\. |
ImportError: DLL load failed while importing _win32sysloader |
The pywin32 post-install step was skipped |
Run .venv\Scripts\python .venv\Scripts\pywin32_postinstall.py -install |
Claude Desktop (mock sandbox — works immediately)
%APPDATA%\Claude\claude_desktop_config.json:
{
"mcpServers": {
"Broker": {
"command": "C:\\path\\to\\Broker-mcp\\.venv\\Scripts\\Broker-mcp.exe",
"args": ["--mock"]
}
}
}
Claude Desktop (live)
{
"mcpServers": {
"Broker": {
"command": "C:\\path\\to\\Broker-mcp\\.venv\\Scripts\\Broker-mcp.exe",
"env": {
"Broker_API_KEY": "your_app_api_key",
"Broker_API_SECRET": "your_app_api_secret"
}
}
}
}
Then in chat: "Connect my Broker account" → the assistant calls get_login_url, you log in on
Broker's own page (mobile + OTP + MPIN — never in the chat), copy the request_token from
the redirect URL, and say "complete login with token …". The session lasts until the daily
regulatory expiry; the server prompts to reconnect after that.
Cursor and VS Code configs, plus sample prompts: docs/client-setup.md and docs/sample-prompts.md.
Test it end-to-end (mock mode — no credentials)
Two ways, quickest first.
MCP Inspector — a browser UI to click each tool and inspect raw responses. Best for methodical tool-by-tool testing; needs Node.js.
npx @modelcontextprotocol/inspector .venv\Scripts\Broker-mcp.exe --mock
It prints a http://localhost:… URL. Open it → Connect → Tools tab → pick a tool (e.g.
get_holdings) → Run Tool. The Inspector launches and talks to the server for you.
Claude Desktop — the real client experience:
- Add the mock config above to
%APPDATA%\Claude\claude_desktop_config.json(merge into any existingmcpServersblock — don't overwrite the file). - Fully quit Claude Desktop from the system-tray icon (right-click → Quit) — closing the window is not enough; it keeps running in the tray and won't reload the config.
- Reopen Claude Desktop, start a new chat, click the tools icon in the input box —
Brokershould appear with 21 tools. - Ask a sample prompt; approve the tool-use prompt the first time it fires:
- "How is my portfolio doing today?" → holdings, labelled MOCK SANDBOX DATA
- "Show the NIFTY option chain for the nearest expiry" → chain with OI/volume; Greeks/IV honestly absent
- "Buy 2 lots of NIFTY futures" → refused (no order tools exist in Phase 1 — proves read-only)
You do not start the server yourself for a client — each client (Claude Desktop, Inspector)
launches its own copy from the command path. If Broker does not appear, check
%APPDATA%\Claude\logs\mcp-server-Broker.log. More prompts: docs/sample-prompts.md.
4. Regulatory position — read before any real-world use
This section is a product-level summary of PRD §8. It is not legal advice. Phase 1 must not be offered to customers until Broker Compliance & Legal have signed off.
Why Phase 1 (this build) is the low-risk posture
Read-only tools never touch order routing, so under SEBI's algo-trading framework (circular of 4 Feb 2025, fully mandatory since 1 Apr 2026) no Algo-ID tagging, no algo registration and no Research-Analyst question arises — there are no orders. Phase 1 rides on the controls the Broker open-API programme itself must already satisfy (client-specific API keys, OAuth + 2FA, static-IP whitelisting, 5-year audit, VAPT). Six brokers (Zerodha, 5paisa, Groww, Dhan, FYERS, Upstox) already operate official MCPs; the read-only posture matches Zerodha/Upstox/FYERS.
Approvals required BEFORE customer launch of this read-only build
| # | Approval / action | Who grants it | Status |
|---|---|---|---|
| 1 | Broker open APIs at GA, SEBI-compliant (static IP, OAuth 2.1, 2FA, audit, VAPT) — the gating dependency the MCP inherits | Exchanges (NSE/BSE/MCX) via the existing API-programme approval; owned by API/infra teams | Gating — outside this repo |
| 2 | Standard API review for the MCP as an API client of that programme | Broker internal (API team + Compliance) | Required |
| 3 | Consent & disclosure language shown at connection (read scopes, risk/non-advice statement, fee disclosure) | Broker Compliance, against SEBI + exchange norms | Required — copy in this repo is engineering draft only |
| 4 | Confirmation of the "confirm with API team" endpoints and the token-expiry time | Broker API team | Required before customer docs |
| 5 | 5-year retention pipeline for the audit logs this server writes | Broker ops/compliance | Required (server writes the records; retention is operational) |
Additionally required before Phase 2 (trade tools — NOT in this build)
- Written confirmation that a human-confirmed, sub-10-orders/sec, user-instructed MCP order is ordinary API trading, not a registrable algo (PRD Q2) — Compliance/Legal, with NSE/BSE if needed.
- Written comfort that an LLM in the order path does not trigger black-box-algo / RA-licence duties (PRD Q3).
- Exchange Algo-ID tagging, static-IP enforcement on the write path, mock/simulation session sign-off, sandbox order-path testing, kill switch, idempotency chaos-tests, 100% confirmation coverage.
- Any material change to an approved order flow requires fresh review.
And before any hosted (Phase 3) endpoint
Security review + external VAPT by a CERT-In-empanelled auditor, plus resolution of how a hosted endpoint satisfies static-IP requirements for writes (may end up read-only-hosted). This build deliberately ships no network listener — stdio only.
Standing non-goals baked into this build
No autonomous trading, no order loops, no Broker-authored advice or strategy, no bespoke LLM. The model analyses the user's own data at the user's explicit request.
5. Architecture
AI client (Claude/Cursor/VS Code)
│ stdio (JSON-RPC, MCP)
▼
Broker-mcp ── server.py FastMCP tools · audit shell · readable errors
session.py login handoff · encrypted token store · daily expiry
backend.py LiveBackend (api.Broker.in) ⇄ MockBackend (sandbox)
instruments.py daily master cache · symbol resolution · chain composition
ratelimit.py token bucket + backoff audit.py JSONL + metrics
routes.py every endpoint path, with confirm-GA flags
│ HTTPS (Authorization: token api_key:access_token)
▼
api.Broker.in (the SEBI-compliant Broker open-API gateway — static IP, 2FA,
Algo-ID machinery all live there; the MCP never bypasses it)
Data locations (per-user, overridable via Broker_MCP_DATA_DIR):
- Encrypted session:
<data dir>/session.enc+ local keytoken.key - Instrument cache:
<cache dir>/instruments-YYYYMMDD.csv - Audit log:
<data dir>/audit/audit-YYYYMMDD.jsonl(ship to WORM storage for the 5-year SEBI retention)
6. Configuration reference
| Env var | Meaning | Default |
|---|---|---|
Broker_API_KEY / Broker_API_SECRET |
App credentials from the Broker Developer Portal | — (required for live) |
Broker_ACCESS_TOKEN |
Directly inject a daily access token (skips login flow) | — |
Broker_MCP_MODE |
live or mock |
live |
Broker_BASE_URL |
Override API host (e.g. UAT) | https://api.Broker.in |
Broker_MCP_DATA_DIR |
Session/audit/cache location | OS per-user data dir |
Broker_MCP_LOG_LEVEL |
Server log level | INFO |
7. Development
.venv\Scripts\python -m pytest -v # test suite
npx @modelcontextprotocol/inspector .venv\Scripts\Broker-mcp.exe --mock # MCP Inspector
Layout: src/Broker_mcp/ (see §5), tests/ (57 tests), docs/ (client setup, sample prompts).
Python ≥3.10. Dependencies: mcp (official SDK), httpx, pydantic, cryptography, platformdirs.
8. FAQ
What does it mean for the server to "run"?
An MCP server is not a web app you open in a browser, and not a program with a menu you type commands into. It is a small process that speaks JSON-RPC over stdio (standard input/output). "Running" means: the process has started and is blocked, waiting for an AI client to send it a message on stdin. It prints nothing and does nothing on its own — a silent, blinking cursor is the correct running state, not a hang.
You will almost never start it yourself. Each AI client (Claude Desktop, Cursor, VS Code, the MCP
Inspector) launches its own copy from the command path in its config, exchanges JSON-RPC
messages with it (initialize → tools/list → tools/call), and shuts it down when you close the
client. When you ran Broker-mcp --mock in a terminal by hand, you started an orphan copy with
nothing connected to it — harmless, but it just sits there until you press Ctrl+C. The only time
you launch it directly is under the MCP Inspector, which then plays the role of the client for you.
So "is the server running?" is rarely the right question — the right question is "has my client launched it and listed its tools?" (check the tools icon in Claude Desktop, or the Tools tab in the Inspector).
Will the live (real) server behave very differently from the mock sandbox?
No — not in shape or behaviour. The server is built around a single Backend interface with two
implementations (LiveBackend → api.Broker.in, MockBackend → synthetic data). Every one of the
21 tools, plus input validation, symbol resolution, option-chain composition, the margin estimate,
the response envelope (timestamps + source labels), the audit log, error translation and batch
chunking, is backend-agnostic — the same code runs in both modes. Switching to live changes
where the numbers come from, not how the server acts on them.
The mock even makes the three "confirm-GA" endpoints (option_chain, option_expiries,
order_margins) fail on purpose, so the sandbox exercises the fallback paths production uses
when those endpoints aren't live: the chain is composed from the instrument master + batched
quotes, and margin falls back to a labelled rough estimate.
Then how close is the sandbox to the real thing — and what is untested?
Structurally it's a high-fidelity stand-in: you are testing the real server, just with synthetic numbers. What the sandbox does not exercise (these paths exist and are written to the verified Broker spec, but have never touched a real server, because none exists pre-GA):
| Area | Mock today | Live reality |
|---|---|---|
| Data values | Toy option pricing, hash-derived OI/volume, sine-wave candles, no Greeks/IV | Real market prices; the confirm-GA endpoints may return richer data (real OI, possibly Greeks/IV, authoritative margins) |
| Auth | Bypassed | Real token-exchange checksum flow + Authorization: token key:token |
| HTTP / rate limiting | Not used | Token bucket + 429 backoff — only instantiated in LiveBackend, never hit in mock |
| Instruments CSV | Generated with Kite-convention columns | Real gzipped CSV — actual column names could differ |
| Error translation | Synthetic errors | Real error envelopes / error_type values map to the readable messages |
| Wire unknowns | N/A | Version header (X-Version vs X-Broker-Version — code sends both), token-expiry time, whether option-chain/margins are GA |
The PRD notes the two source-of-truth documents (Broker docs vs the PyBrokerAPI SDK) do not fully agree; the live code makes defensible choices (sends both version headers, tries endpoint-then- composes) precisely so a smoke-test at GA can confirm the details. Expect a short integration pass then — it is anticipated, not a defect.
What is needed for the live (real) server to work?
- The gating dependency (outside this repo): Broker's open-API programme reaches GA and is SEBI-compliant for the account — PRD Phase 0. No code substitutes for this.
- A registered app in the Broker Developer Portal: API key + secret, a registered redirect URL, and static IPs whitelisted.
- Config: set
Broker_API_KEYandBroker_API_SECRETin the client'senvblock and drop--mock(mode defaults tolive). See §3 "Claude Desktop (live)". - Daily login handoff: connect →
get_login_url→ log in on Broker's own page → copy therequest_tokenfrom the redirect →complete_login. The encrypted access token lands on your machine and expires daily per SEBI rules. - A live smoke-test to confirm the wire unknowns above (CSV columns, error shapes, which endpoints are GA, token-expiry time).
Why does the server print nothing / look frozen when I run it?
That is expected — see "What does it mean for the server to run?" above. It is waiting for stdin.
Press Ctrl+C to stop it. To actually see it do something, use the MCP Inspector or a client.
Why can't it place trades?
By design (PRD FR-G1, Phase 1). Order-placement tools do not exist in this codebase — not disabled, absent. Nothing here can change account state. Trade tools are a separate, compliance- gated Phase 2 build. See §1 and §4.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。