Content
# thinkorswim MCP
A Python MCP server for options-trading research, built on the **Charles Schwab Trader API** (the successor to thinkorswim/TD Ameritrade). Designed to plug into Claude Code and AI agents, with an optional FastAPI sidecar for backend integration.
## Features
- **Real-time quotes & price history** via the Schwab REST API
- **Option chains with full Greeks** — delta, gamma, theta, vega, IV, OI, volume
- **IV analytics** — IV rank, IV percentile, expected move
- **Multi-leg strategy builder** — verticals, iron condors, calendars; net Greeks, breakevens, max profit/loss
- **Declarative screener** — filter a universe by IV rank, price, and more; built-in templates included
- **Rate-limit-aware client** — token bucket at 110 req/min with 429 backoff
- **FastAPI sidecar** (Phase 4) for NestJS/backend integration
- **ToS desktop automation stub** (Phase 3) for thinkscript scans via pyautogui + CSV export
## Prerequisites
- Python 3.11+
- [`uv`](https://docs.astral.sh/uv/) (recommended) or pip
- A [Charles Schwab brokerage account](https://www.schwab.com/) (required for API access)
- A registered app at [developer.schwab.com](https://developer.schwab.com) → **Trader API (Individual)**
> **Note:** API approval takes 1–3 business days. Apply before you start.
## Setup
```bash
# 1. Install dependencies
uv sync --all-extras
# 2. Configure credentials
cp .env.example .env
# Edit .env with your SCHWAB_API_KEY and SCHWAB_APP_SECRET
# 3. Run the OAuth flow (one-time, opens a browser)
make auth
# 4. Verify the token works
make smoke
```
## Usage
### Run the MCP server (stdio — for Claude Code / IDE agents)
```bash
make serve-mcp
```
Add to your Claude Code config (`~/.claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"thinkorswim": {
"command": "uv",
"args": ["run", "python", "-m", "tos_mcp.server"],
"cwd": "/path/to/thinkorswim_mcp"
}
}
}
```
### Run the FastAPI sidecar (for backend integration)
```bash
make serve-api # http://localhost:8181
```
### Run tests
```bash
make test
```
## MCP Tools
| Tool | Description |
|------|-------------|
| `get_quote` | Real-time quotes for one or more symbols |
| `get_price_history` | OHLCV bars (daily/weekly/minute) |
| `get_option_chain` | Full chain with Greeks, IV, OI, volume |
| `get_iv_rank` | IV rank (0–100) vs past year |
| `get_iv_percentile` | % of past-year days with lower IV |
| `get_expected_move` | ±1σ range to a given expiration |
| `build_options_strategy` | Net Greeks + breakevens for multi-leg strategies |
| `screen_list_scans` | List available scan templates |
| `screen_run_scan` | Execute a scan across a universe |
| `screen_save_scan` | Save a custom scan spec |
| `request_tos_scan` | Trigger a thinkscript scan via ToS desktop (Phase 3) |
## Project Structure
```
thinkorswim_mcp/
├── tos_core/ # Importable business logic (no MCP/HTTP here)
│ ├── auth.py # OAuth + token store (schwab-py)
│ ├── client.py # Rate-limited Schwab REST wrapper
│ ├── chains.py # Option chain fetch + Greeks normalization
│ ├── analytics.py # IV rank, expected move, strategy builder
│ └── screener/ # Declarative scan engine + spec schema
├── tos_mcp/ # FastMCP server (thin handlers → tos_core)
├── tos_api/ # FastAPI sidecar for backend integration
├── tos_export_worker/ # pyautogui ToS desktop worker (Phase 3 stub)
└── tests/
```
`tos_core` is independently importable — the MCP server and FastAPI sidecar both delegate to it. This keeps business logic testable and reusable outside of any transport layer.
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `SCHWAB_API_KEY` | — | App key from developer.schwab.com |
| `SCHWAB_APP_SECRET` | — | App secret from developer.schwab.com |
| `SCHWAB_CALLBACK_URL` | `https://127.0.0.1` | OAuth callback (must match registered URL) |
| `SCHWAB_TOKEN_PATH` | `~/.tos/schwab_token.json` | Where the OAuth token is stored |
| `TOS_EXPORT_DIR` | `~/.tos/exports` | Drop folder for ToS CSV exports (Phase 3) |
## Limitations
- **Live trading only** — Schwab has no sandbox or paper trading environment for the API
- **Rate limit** — 120 requests/min; the client enforces 110/min with automatic backoff
- **thinkscript** — cannot run via any API; the ToS automation module (Phase 3) is a best-effort workaround using desktop GUI automation
- **Read-only** — no order placement is exposed
## License
MIT