ibkr-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ibkr-mcp fetch my account history and analyze my P&L for the last 30 days"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ibkr-mcp-server
MCP server for Interactive Brokers — Flex Web Service account historical analysis.
Overview
This server exposes IBKR's Flex Web Service as MCP tools so that Claude (or any MCP-compatible client) can retrieve and analyse your account history without manual report downloads.
Related MCP server: IBKR MCP Server
Prerequisites
An Interactive Brokers account.
A Flex Query configured in Account Management with the desired sections (Trades, OpenPositions, CashTransactions, EquitySummaryInBase, FIFOPerformanceSummaryInBase).
A Flex Web Service token generated in Account Management → Reports → Flex Queries → Manage → Generate Token.
Setup
# Install with uv (recommended)
uv sync
# Or with pip
pip install -e .Copy .env.example to .env and fill in your credentials:
cp .env.example .env
# edit .env with your IBKR_FLEX_TOKEN and IBKR_FLEX_QUERY_IDRunning the server
# stdio transport (for Claude Desktop / mcp CLI)
ibkr-mcp
# Or via uv
uv run ibkr-mcpClaude Desktop config (local stdio)
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"ibkr": {
"command": "uv",
"args": ["run", "--project", "/path/to/ibkr-mcp", "ibkr-mcp"],
"env": {
"IBKR_FLEX_TOKEN": "your_token",
"IBKR_FLEX_QUERY_ID": "your_query_id"
}
}
}
}claude.ai MCP connector (remote SSE)
claude.ai (Teams / Enterprise) supports custom MCP connectors over HTTPS. The server must be publicly reachable; use the steps below.
1. Deploy the server
# Option A — Docker (recommended)
docker build -t ibkr-mcp .
docker run -d \
-e IBKR_FLEX_TOKEN=your_token \
-e IBKR_FLEX_QUERY_ID=your_query_id \
-e MCP_TRANSPORT=sse \
-e MCP_AUTH_TOKEN=your_secret_token \
-p 8000:8000 \
ibkr-mcp
# Option B — uv directly (on a VPS / cloud VM)
MCP_TRANSPORT=sse \
MCP_AUTH_TOKEN=your_secret_token \
IBKR_FLEX_TOKEN=your_token \
IBKR_FLEX_QUERY_ID=your_query_id \
uv run ibkr-mcp2. Put HTTPS in front (required by claude.ai)
Use any reverse proxy that terminates TLS. A minimal Caddy example:
your-domain.com {
reverse_proxy localhost:8000
}Or use a managed tunnel for quick testing:
ngrok http 8000 # gives you https://xxxx.ngrok.io3. Add to claude.ai
Open claude.ai → Settings → Integrations → Add custom integration
Fill in:
Name: IBKR
URL:
https://your-domain.com/sse(note the/ssepath)
Under Authorization, select Bearer token and paste the value of
MCP_AUTH_TOKENClick Save — the tools appear automatically
Health check:
GET https://your-domain.com/healthreturns{"status":"ok"}and bypasses bearer auth, so you can verify connectivity without credentials.
Available Tools
Flex Web Service protocol
Tool | Description |
| Initiate a Flex query; returns a |
| Download a completed report by reference code (polls until ready) |
| Convenience: send + poll + download in one call |
XML parsing
Tool | Description |
| Account metadata (account ID, type, currency, date range) |
| Trade records — filterable by symbol, asset category, date |
| Open position records |
| Cash transactions (dividends, interest, fees, etc.) |
| Daily NAV / equity summary time series |
| FIFO realized and unrealized P&L by symbol |
Analysis
Tool | Description |
| Aggregate realized P&L from trades; group by symbol, month, year, asset category |
| Summarize gross dividends and withholding taxes by symbol |
| Portfolio value over time with total-return calculation |
Typical workflow
1. flex_run_query() → xml_content
2. flex_account_info(xml_content) → account metadata
3. flex_analyze_pnl(xml_content) → realized P&L by symbol
4. flex_analyze_dividends(xml_content) → dividend income summary
5. flex_analyze_portfolio_history(xml_content) → NAV time seriesFlex Query setup guide
Your query must include these Sections for full tool coverage:
Account Information
Trades (select Executions)
Open Positions
Cash Transactions
Equity Summary in Base Currency
FIFO Performance Summary in Base Currency
Recommended date period: Last N days or Custom Date Range covering your analysis window.
Development
uv sync --dev
pytest tests/Available Tools
13 toolsflex_account_infoA
Extract account metadata from a Flex XML report.
Args: xml_content: Raw Flex XML string (from flex_run_query or flex_get_statement).
Returns JSON array of account info objects, one per FlexStatement in the report.
Inputs: xml_content (required). Returns: result
flex_analyze_cash_utilizationA
Calculate free cash as a percentage of Net Liquidation Value (Net Liq), after deducting cash reserved for short (sold) put obligations.
When a put is sold, the seller must be able to purchase the underlying if assigned. The worst-case cash reservation per contract is:
strike × multiplier × |quantity|This tool answers: "Of my total Net Liq, how much of my cash is actually free — not spoken for by open short-put assignments?"
Uses the most recent equity-summary row for Net Liq and cash, and the current open-positions snapshot for short puts.
Returns JSON: net_liq — total portfolio value in base currency gross_cash — cash balance from equity summary reserved_for_puts — worst-case assignment obligation of all short puts free_cash — gross_cash − reserved_for_puts free_cash_pct_net_liq — free_cash / net_liq × 100 (the headline %) cash_pct_net_liq — gross_cash / net_liq × 100 (for reference) currency — base currency of the account as_of_date — equity summary report date used short_puts — per-position breakdown of the reservation
Inputs: xml_content (required). Returns: result
flex_analyze_dividendsA
Summarize dividend income and withholding taxes from cash transactions.
Args: xml_content: Raw Flex XML string.
Returns JSON with total gross dividends, total withholding tax, net dividends, and a per-symbol breakdown.
Inputs: xml_content (required). Returns: result
flex_analyze_pnlA
Aggregate realized P&L from trade records in a Flex XML report.
Only closing trades (open_close contains 'C') contribute to realized P&L.
Args: xml_content: Raw Flex XML string. group_by: Dimension to aggregate by — "symbol", "month", "year", "asset_category", or "buy_sell" (default "symbol"). asset_category: Filter by asset category e.g. STK, OPT, FUT (optional). from_date: Earliest trade date, YYYY-MM-DD (optional). to_date: Latest trade date, YYYY-MM-DD (optional).
Returns JSON with totals and a breakdown list sorted by realized_pnl descending.
Inputs: xml_content (required), to_date, group_by, from_date, +1 more. Returns: result
flex_analyze_portfolio_historyA
Show how the portfolio NAV changed over time and compute a return figure.
Return methods
twr (default) — Time-Weighted Return via daily chain-linking. Eliminates the timing/size effect of external cash flows. Use this to evaluate the strategy independent of cash-flow decisions.
mwr — Money-Weighted Return via Modified Dietz. Reflects the investor's actual experience: large deposits before a rally boost the return; large withdrawals before a rally reduce it. Use this to evaluate overall portfolio performance.
Args: xml_content: Raw Flex XML string. metric: Which equity component to track — "total", "cash", "stock", "options", "futures", "bonds" (default "total"). return_method: "twr" (default) or "mwr".
Returns JSON with a time-series, annualised and period returns, and the total net external cash flow over the period.
Inputs: xml_content (required), metric, return_method. Returns: result
flex_get_statementA
Download a completed Flex report using its reference code.
Polls automatically until the report is ready or the timeout is reached.
Args: reference_code: Reference code returned by flex_send_request. token: Flex API token (overrides IBKR_FLEX_TOKEN env var). poll_interval_seconds: Seconds between polling attempts (default 5). max_wait_seconds: Maximum seconds to wait for the report (default 120).
Returns JSON: {"xml_content": "<FlexQueryResponse...>..."}
Inputs: reference_code (required), token, max_wait_seconds, poll_interval_seconds. Returns: result
flex_parse_cash_txnsA
Extract cash transaction records from a Flex XML report.
Common transaction_type values: Dividends, "Withholding Tax", "Broker Interest Paid", "Broker Interest Received", "Other Fees".
Args: xml_content: Raw Flex XML string. transaction_type: Filter by transaction type substring (case-insensitive, optional). symbol: Filter by symbol (optional). from_date: Earliest date, YYYY-MM-DD (optional). to_date: Latest date, YYYY-MM-DD (optional).
Returns JSON: {"count": N, "total_amount": "...", "transactions": [...]}
Inputs: xml_content (required), symbol, to_date, from_date, +1 more. Returns: result
flex_parse_equityA
Extract daily NAV / equity summary rows from a Flex XML report.
Args: xml_content: Raw Flex XML string. from_date: Earliest report date, YYYY-MM-DD (optional). to_date: Latest report date, YYYY-MM-DD (optional).
Returns JSON: {"count": N, "equity_summary": [...]}
Inputs: xml_content (required), to_date, from_date. Returns: result
flex_parse_fifo_pnlA
Extract FIFO realized/unrealized P&L summary from a Flex XML report.
Args: xml_content: Raw Flex XML string. symbol: Filter by ticker symbol (case-insensitive, optional). asset_category: Filter by asset category e.g. STK, OPT, FUT (optional).
Returns JSON: {"count": N, "total_realized": "...", "total_unrealized": "...", "rows": [...]}
Inputs: xml_content (required), symbol, asset_category. Returns: result
flex_parse_positionsA
Extract open position records from a Flex XML report.
Args: xml_content: Raw Flex XML string. symbol: Filter by ticker symbol (case-insensitive, optional). asset_category: Filter by asset category e.g. STK, OPT, FUT (optional).
Returns JSON: {"count": N, "positions": [...]}
Inputs: xml_content (required), symbol, asset_category. Returns: result
flex_parse_tradesA
Extract trade records from a Flex XML report.
Args: xml_content: Raw Flex XML string. symbol: Filter by ticker symbol (case-insensitive, optional). asset_category: Filter by asset category e.g. STK, OPT, FUT (optional). from_date: Earliest trade date to include, YYYY-MM-DD (optional). to_date: Latest trade date to include, YYYY-MM-DD (optional).
Returns JSON: {"count": N, "trades": [...]}
Inputs: xml_content (required), symbol, to_date, from_date, +1 more. Returns: result
flex_run_queryA
Send a Flex query and wait for the complete XML report.
Combines flex_send_request + flex_get_statement in one call.
Args: query_id: Flex Query ID (overrides IBKR_FLEX_QUERY_ID env var). token: Flex API token (overrides IBKR_FLEX_TOKEN env var). poll_interval_seconds: Seconds between polling attempts (default 5). max_wait_seconds: Maximum seconds to wait for the report (default 120).
Returns JSON: {"xml_content": "<FlexQueryResponse...>..."}
Inputs: token, query_id, max_wait_seconds, poll_interval_seconds. Returns: result
flex_send_requestA
Initiate a Flex query. Returns a reference_code to use with flex_get_statement.
Args: query_id: Flex Query ID (overrides IBKR_FLEX_QUERY_ID env var). token: Flex API token (overrides IBKR_FLEX_TOKEN env var).
Returns JSON: {"reference_code": "...", "status": "..."}
Inputs: token, query_id. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 13 tools
Each tool targets a distinct action or report section. The only potentially overlapping pair is flex_parse_fifo_pnl and flex_analyze_pnl, but their descriptions clearly differentiate raw extraction vs. aggregated analysis. Similarly, flex_run_query explicitly wraps the two-step send/get process.
All tools share the flex_ prefix and almost all follow a verb_noun pattern (send_request, parse_trades, analyze_pnl). The sole exception is flex_account_info, which uses a noun-only suffix. This is a minor inconsistency that does not hinder readability.
13 tools is within the ideal 3-15 range for a domain-specific MCP. Each tool covers a distinct stage of the Flex report lifecycle or a different report section, so none feel redundant.
The server covers the full workflow: initiate query (flex_send_request), retrieve XML (flex_get_statement, flex_run_query), parse core sections (trades, positions, cash, equity, FIFO P&L), and analyze (PnL, dividends, cash utilization, portfolio history). No obvious missing operations for the stated purpose.
Related MCP Connectors
Read-only access to your own crypto portfolio across 11+ exchanges and 20+ chains: holdings, full history, FIFO cost basis and P&L, fees and income. Ask Claude or ChatGPT about your portfolio; the connector can never trade, move funds or act as a login.
Ask Claude about your income and spending, and import bank statements. No bank login.
Personal finance, bank account, and shared memory connector for Claude, ChatGPT, Gemini Spark & more
Agentic brokerage access to a US brokerage account: quotes, orders, positions, cash and documents.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables LLM clients to interact with Interactive Brokers Trader Workstation for automated trading workflows. Supports market data retrieval, portfolio management, and order execution through the TWS API.5-
- AlicenseNot gradedqualityDmaintenanceProvides AI models with secure access to Interactive Brokers trading data and functionality, enabling account management, market data retrieval, and trading operations through natural language interactions.18MIT
- FlicenseNot gradedqualityCmaintenanceConnects Claude AI to Interactive Brokers accounts to enable real-time portfolio tracking, position management, and historical market data retrieval. It also integrates financial news and sentiment analysis from multiple sources, including Finnhub and IB native feeds.-
- AlicenseBqualityBmaintenanceProvides 32 trading analysis tools for AI-powered market analysis, including real-time data, technical indicators, options Greeks, scanners, and Interactive Brokers portfolio management, all accessible via natural language in Claude Desktop.36406MIT