ibkr-mcp
# ibkr-mcp-server
MCP server for Interactive Brokers — Flex Web Service account historical analysis.
## Overview
This server exposes IBKR's [Flex Web Service](https://www.interactivebrokers.com/en/software/am/am/reports/flexwebservice.htm) as MCP tools so that Claude (or any MCP-compatible client) can retrieve and analyse your account history without manual report downloads.
## Prerequisites
1. An Interactive Brokers account.
2. A **Flex Query** configured in Account Management with the desired sections (Trades, OpenPositions, CashTransactions, EquitySummaryInBase, FIFOPerformanceSummaryInBase).
3. A **Flex Web Service token** generated in Account Management → Reports → Flex Queries → Manage → *Generate Token*.
## Setup
```bash
# Install with uv (recommended)
uv sync
# Or with pip
pip install -e .
```
Copy `.env.example` to `.env` and fill in your credentials:
```bash
cp .env.example .env
# edit .env with your IBKR_FLEX_TOKEN and IBKR_FLEX_QUERY_ID
```
## Running the server
```bash
# stdio transport (for Claude Desktop / mcp CLI)
ibkr-mcp
# Or via uv
uv run ibkr-mcp
```
### Claude Desktop config (local stdio)
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
```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**
```bash
# 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-mcp
```
**2. 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:
```bash
ngrok http 8000 # gives you https://xxxx.ngrok.io
```
**3. Add to claude.ai**
1. Open claude.ai → **Settings** → **Integrations** → **Add custom integration**
2. Fill in:
- **Name**: IBKR
- **URL**: `https://your-domain.com/sse` *(note the `/sse` path)*
3. Under **Authorization**, select **Bearer token** and paste the value of `MCP_AUTH_TOKEN`
4. Click **Save** — the tools appear automatically
> **Health check**: `GET https://your-domain.com/health` returns `{"status":"ok"}` and
> bypasses bearer auth, so you can verify connectivity without credentials.
## Available Tools
### Flex Web Service protocol
| Tool | Description |
|------|-------------|
| `flex_send_request` | Initiate a Flex query; returns a `reference_code` |
| `flex_get_statement` | Download a completed report by reference code (polls until ready) |
| `flex_run_query` | Convenience: send + poll + download in one call |
### XML parsing
| Tool | Description |
|------|-------------|
| `flex_account_info` | Account metadata (account ID, type, currency, date range) |
| `flex_parse_trades` | Trade records — filterable by symbol, asset category, date |
| `flex_parse_positions` | Open position records |
| `flex_parse_cash_txns` | Cash transactions (dividends, interest, fees, etc.) |
| `flex_parse_equity` | Daily NAV / equity summary time series |
| `flex_parse_fifo_pnl` | FIFO realized and unrealized P&L by symbol |
### Analysis
| Tool | Description |
|------|-------------|
| `flex_analyze_pnl` | Aggregate realized P&L from trades; group by symbol, month, year, asset category |
| `flex_analyze_dividends` | Summarize gross dividends and withholding taxes by symbol |
| `flex_analyze_portfolio_history` | 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 series
```
## Flex 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
```bash
uv sync --dev
pytest tests/
```
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.