Webull MCP Server
README.md
# Webull MCP Server
An [MCP](https://modelcontextprotocol.io) server that exposes the **official
Webull OpenAPI** ([`webull-openapi-python-sdk`](https://pypi.org/project/webull-openapi-python-sdk/))
as tools an MCP client — Claude Code, Claude Desktop, or any other — can call.
Read account balances, positions, orders, stock quotes, historical bars, and
US option market data; optionally place and cancel live equity orders.
---
## ⚠️ Read this before you install
**Unofficial.** This project is not affiliated with, endorsed by, or supported
by Webull. It calls Webull's OpenAPI as a third-party client, at your own risk.
The API can change or break without notice, and nothing here is guaranteed to
keep working.
**Not financial advice.** This is plumbing, not a strategy. It has no opinion
about what you should buy or sell. You are solely responsible for every order
that leaves your account and every dollar it costs you.
**Trading is disabled by default — and there is no paper mode.** The order
tools are not even *registered* with the MCP client unless you explicitly set
`WEBULL_ENABLE_TRADING=true`. Webull publishes **no paper-trading endpoint**,
so once enabled, every order this server places is **live, with real money, on
a real account**. See [Enabling live trading](#enabling-live-trading-optional).
**Your credentials stay on your machine.** Your App Key and Secret live only in
a local `.env` file, which is gitignored. They are sent only to Webull's API —
never to the model, never to any third party.
---
## Tools
### Read-only (always available)
| Tool | What it does |
|------|--------------|
| `list_accounts` | List accounts available to your credentials |
| `get_account_balance` | Cash, net liquidation, buying power |
| `get_positions` | Current holdings |
| `get_open_orders` | Working orders |
| `get_order_history` | Filled, cancelled, and past orders |
| `get_instrument` | Resolve a ticker to instrument metadata |
| `get_quote` | Real-time price snapshot (last, OHLC, volume) |
| `get_history_bars` | Historical OHLCV candles |
| `get_option_quote` | Snapshots for US option contracts — bid/ask, volume, open interest, IV, and all five Greeks |
| `get_option_history_bars` | Historical OHLCV bars for option contracts |
| `get_option_tick` | Tick-by-tick trades for a single option contract |
| `trading_status` | Reports whether live trading is enabled |
Option tools take OCC-format symbols (`AAPL260619C00285000` —
`<ROOT><YYMMDD><C|P><strike × 1000, 8 digits>`). Webull has no chain-listing
endpoint, so build candidate symbols from known strikes and expirations and
quote them directly. Up to 20 per call.
### Live trading (gated, off by default)
Registered **only** when `WEBULL_ENABLE_TRADING=true`:
| Tool | What it does |
|------|--------------|
| `preview_order` | Validate an order without submitting — fees, buying-power impact, validation errors |
| `place_order` | Submit a **live** equity order. Additionally requires `confirm=True` |
| `cancel_order` | Cancel a working order by `client_order_id` |
Supported order types: `MARKET`, `LIMIT`, `STOP_LOSS`, `STOP_LOSS_LIMIT`;
`DAY` or `GTC`; optional extended-hours routing.
---
## Example session
What using it actually looks like from an MCP client. Values below are
illustrative — substitute your own account.
```
> How's my account doing, and what's the SMCI Jan 250 call worth?
● get_account_balance()
⎿ {
"account_id": "XXXXXXXXXXXXXXXXXXXXXXXXXX",
"net_liquidation": "18432.55",
"cash_balance": "6120.18",
"buying_power": "12240.36"
}
● get_positions()
⎿ [
{ "symbol": "INTC", "quantity": "40", "cost_price": "127.54",
"last_price": "131.02", "unrealized_pnl": "139.20" },
{ "symbol": "IWM", "quantity": "15", "cost_price": "241.88",
"last_price": "238.15", "unrealized_pnl": "-55.95" }
]
● get_option_quote(symbols: "SMCI260116C00250000")
⎿ [
{ "symbol": "SMCI260116C00250000",
"bid": "12.40", "ask": "12.85", "volume": "1843",
"open_interest": "9021", "imp_vol": "0.5412",
"delta": "0.4187", "gamma": "0.0092", "theta": "-0.1734",
"vega": "0.2815", "rho": "0.0946" }
]
Net liq is $18,432.55 with $12,240 buying power. INTC is up $139 and IWM
is down $56. The SMCI 250 call is $12.40 × $12.85 — 0.42 delta, 54% IV,
and theta is costing you $17/day per contract.
```
> Only read-only tools appear above. `place_order` is not available at all
> unless you explicitly enable trading — see
> [Enabling live trading](#enabling-live-trading-optional).
---
## Setup
### 1. Get Webull API credentials
1. Go to the [Webull Developer portal](https://developer.webull.com/) and sign
in with the Webull account you want the server to access.
2. Apply for OpenAPI access and create an app. Approval is not instant — Webull
reviews requests.
3. Copy the **App Key** and **App Secret** it issues.
Your account must have OpenAPI enabled for your region. Real-time market data
may additionally require a market-data entitlement on your account; without one,
quotes may be delayed.
### 2. Install
```bash
git clone https://github.com/<your-username>/webull-mcp.git
cd webull-mcp
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
```
Requires Python 3.10 or newer.
### 3. Configure
```bash
cp .env.example .env
```
Edit `.env` and fill in your credentials:
```ini
WEBULL_APP_KEY=your_app_key_here
WEBULL_APP_SECRET=your_app_secret_here
# One of: us, hk, jp, sg, th, au, my, uk
WEBULL_REGION=us
# Optional. If set, account tools use this account when you omit account_id.
# Leave blank to auto-resolve the first account from list_accounts.
WEBULL_DEFAULT_ACCOUNT_ID=
# Leave this false unless you have read the trading section below.
WEBULL_ENABLE_TRADING=false
```
`.env` is gitignored. Never commit it, and never paste its contents anywhere.
### 4. Register with your MCP client
Edit `.mcp.json` and replace the placeholder paths with the absolute path to
your clone:
```json
{
"mcpServers": {
"webull": {
"command": "/absolute/path/to/webull-mcp/.venv/bin/python",
"args": ["/absolute/path/to/webull-mcp/src/server.py"]
}
}
}
```
For Claude Code, either drop `.mcp.json` into a project directory where it will
be auto-detected, or register it explicitly:
```bash
claude mcp add webull -- /absolute/path/to/webull-mcp/.venv/bin/python /absolute/path/to/webull-mcp/src/server.py
```
Restart your client. Verify the server starts:
```bash
.venv/bin/python src/server.py
```
It should start and wait on stdio — no output is correct. Ctrl-C to exit.
On the first call that touches your account, the SDK performs a 2FA handshake
and caches a token under `conf/`. That directory is gitignored.
---
## Enabling live trading (optional)
**Only do this if you accept that every order is real.** There is no sandbox,
no paper account, and no undo.
1. Set `WEBULL_ENABLE_TRADING=true` in `.env` — the string must be exactly
`true`.
2. Restart your MCP client. The trading tools are registered at import time, so
a restart is required.
3. Confirm with the `trading_status` tool.
Two independent safety layers remain in place:
- **Registration gate** — with the flag unset or `false`, `place_order`,
`preview_order`, and `cancel_order` are never exposed to the model at all. It
cannot call a tool it cannot see.
- **Confirmation gate** — even when enabled, `place_order` raises unless it is
called with `confirm=True`. Run `preview_order` first.
To disable again, set the flag back to `false` and restart.
---
## Notes and limitations
- Region defaults to `us`. Set `WEBULL_REGION` for other markets.
- Order tools cover **equities only** — options trading is not implemented.
Option support here is market data only.
- Webull exposes no option-chain listing endpoint. Build OCC symbols yourself.
Expired contracts return `INVALID_SYMBOL`, and Friday expirations shift to
Thursday when Friday is a market holiday.
- Built on the unified, symbol-based `webull-openapi-python-sdk`. The older
split `webull-python-sdk-*` packages use a different, instrument-id-based
API — **do not install both.**
- The SDK writes logs under `logs/`. **These logs contain your App Key, your
2FA token, and your account IDs.** They are gitignored; never attach one to a
bug report without redacting it first.
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports and PRs are welcome.
## License
[MIT](LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues