Skip to main content
Glama
selvakumarEsra

ibkr-mcp-server

README.md
# ibkr-mcp-server

MCP server that exposes [Interactive Brokers](https://www.interactivebrokers.com/) via the TWS API
as 14 tools: account reads, market data, contract resolution, and order placement.

**Paper-by-default.** Live trading requires explicit opt-in via `IBKR_TRADING_MODE=live`.

## Prerequisites

1. **TWS** or **IB Gateway** running locally. Download from IBKR.
2. **API enabled** in TWS/Gateway: Configure → API → Settings
   - Check "Enable ActiveX and Socket Clients"
   - Uncheck "Read-Only API"
   - Socket port: `7497` (paper) or `7496` (live) — defaults match this server
   - Add `127.0.0.1` to "Trusted IPs"
3. **uv** installed: `curl -LsSf https://astral.sh/uv/install.sh | sh`

## Install

```bash
git clone <this repo>
cd ibkr-mcp-server
uv sync
```

## Configure

Copy `.env.example` and adjust as needed (or export the vars in your shell / MCP client config).

## Register with Claude Code

Add to `~/.claude.json` (or a per-project `.mcp.json`):

```json
{
  "mcpServers": {
    "ibkr": {
      "command": "uv",
      "args": [
        "--directory", "/absolute/path/to/ibkr-mcp-server",
        "run", "ibkr-mcp-server"
      ],
      "env": {
        "IBKR_TRADING_MODE": "paper",
        "IBKR_CLIENT_ID": "17"
      }
    }
  }
}
```

## Tools

| Tool | Purpose |
|---|---|
| `status` | Connection + mode + gateway info |
| `get_account_summary` | Cash, net liq, buying power, margin |
| `get_positions` | Open positions with market price enrichment |
| `get_pnl` | Account-level or per-position P&L |
| `get_executions` | Today's fills (or since ISO timestamp) |
| `search_symbol` | IBKR symbol search |
| `qualify_contract` | Resolve symbol → canonical contract with conid |
| `get_quote` | Snapshot bid/ask/last/volume |
| `get_historical_bars` | OHLCV bars |
| `place_order` | Place MKT/LMT/STP/STP_LMT order |
| `place_bracket_order` | Entry + take-profit + stop-loss |
| `modify_order` | Modify an existing open order |
| `cancel_order` | Cancel an open order |
| `list_open_orders` | List currently open orders |

## Safety

- **Mode gate:** server reads `managedAccounts` on connect and verifies prefixes
  (`DU*` = paper, `U*` = live). On mismatch, all order tools are blocked.
- **Audit log:** every order placement / modification / cancellation is appended
  as a JSON line to `$IBKR_AUDIT_LOG` (default `~/.ibkr-mcp-server/audit.log`).
- **Read-only mode:** set `IBKR_READONLY=1` to disable all order tools.

## Risk rails (v2)

Three additional rails apply to `place_order`, `place_bracket_order`, and `modify_order`. `cancel_order` and `list_open_orders` are intentionally not gated.

- **Notional caps.** Per-order and daily-cumulative ceilings in USD. Mode-aware: paper and live have independent envs. Set to `unlimited` to disable an individual cap.
- **Rate limit.** Each gated tool has its own token bucket (capacity 10, refill 10/min). Hardcoded in v2.
- **Kill switch.** If `IBKR_HALT_FILE` exists, every gated tool returns `{status:"rejected", error_code:"HALT", ...}` immediately. Remove the file to re-enable.

Blocks are returned as data (same shape as IB-side rejections) and appended to the audit log. They do not raise.

`get_quote` now returns a `data_type` field: `"live" | "delayed" | "delayed_frozen" | "frozen"`. The server calls `ib.reqMarketDataType(3)` on connect so weekend/out-of-hours quotes fall back to delayed data instead of returning nulls.

| Env var | Default | Purpose |
|---|---|---|
| `IBKR_MAX_ORDER_NOTIONAL_PAPER` | `100000` | Per-order notional cap in paper (USD); `unlimited` to disable |
| `IBKR_MAX_ORDER_NOTIONAL_LIVE` | `25000` | Per-order notional cap in live (USD); `unlimited` to disable |
| `IBKR_MAX_DAILY_NOTIONAL_PAPER` | `1000000` | Daily cumulative cap in paper; `unlimited` to disable |
| `IBKR_MAX_DAILY_NOTIONAL_LIVE` | `100000` | Daily cumulative cap in live; `unlimited` to disable |
| `IBKR_HALT_FILE` | `~/.ibkr-mcp-server/HALT` | Path probed on every order; presence halts all order-mutating tools |

## Testing

```bash
uv run pytest                          # unit tests (default)
IBKR_INTEGRATION_TESTS=1 uv run pytest -m integration   # against a running paper gateway
uv run python scripts/smoke.py         # manual end-to-end smoke
```

TDQS

C2.9/5.0

Scored across 14 tools

Disambiguation5/5

Each tool targets a distinct operation: order management (place, modify, cancel, list, bracket), data retrieval (account, positions, P&L, quotes, executions, historical bars), contract resolution (qualify, search), and connection status. No significant overlap.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern with snake_case (e.g., get_quote, place_order, list_open_orders). Naming is predictable and readable.

Tool Count5/5

With 14 tools, the server is well-scoped for a trading API, covering orders, account info, market data, and contract resolution without being overloaded or sparse.

Completeness4/5

Core trading workflows are well-covered: full order lifecycle, account and position monitoring, market data, and contract lookup. Minor gaps like advanced order types or market depth are absent, but the essential surface is complete.

Maintenance

ActivityInactive
ResponsivenessNo issues