Webull AU MCP
by nickp27
README.md
# Webull AU OpenAPI MCP
A slim MCP server for the **Webull Australia** OpenAPI. It exposes exactly what
the AU platform supports — **US stock and ETF** market data and trading — and
nothing else. Region is hardcoded to `au`; there is no multi-region, options,
futures, crypto, event-contract, combo, strategy or algo code.
Built on `fastmcp` and the official `webull-openapi-python-sdk` (≥ 2.0.12, which
is the first line to bundle AU production endpoints).
> For reference only; not investment advice. Trading involves risk. Review every
> order before confirming.
## Install
```bash
cd webull-au-mcp
uv sync # or: pip install -e .
```
## Configure
```bash
webull-au-mcp init # writes .env
# edit .env → set WEBULL_APP_KEY / WEBULL_APP_SECRET
webull-au-mcp status # sanity-check config
```
For a zero-setup trial, use a public **UAT** test account from the
[AU SDK docs](https://developer.webull.com.au/apis/docs/sdk) (no application, no 2FA):
```
WEBULL_ENVIRONMENT=uat
WEBULL_APP_KEY=c8d29a52a41c03cb76ebe1f680bada3c
WEBULL_APP_SECRET=40424c891fca1aa68c0aeef862de2ee7
WEBULL_ACCOUNT_ID=1234113618547593216
```
### Configuration
| Variable | Description | Default |
| --- | --- | --- |
| `WEBULL_APP_KEY` | App key (required) | — |
| `WEBULL_APP_SECRET` | App secret (required) | — |
| `WEBULL_ENVIRONMENT` | `uat` (sandbox, no 2FA) or `prod` (live) | `uat` |
| `WEBULL_ACCOUNT_ID` | Default account for tools that need one | — |
| `WEBULL_TOOLSETS` | `account`, `market-data`, `instrument`, `trading` (comma-sep) | `account,market-data,instrument` |
| `WEBULL_MAX_ORDER_NOTIONAL_USD` | Max single-order value (USD) | `10000` |
| `WEBULL_MAX_ORDER_QUANTITY` | Max single-order share quantity | `1000` |
| `WEBULL_SYMBOL_WHITELIST` | Allowed symbols (comma-sep); empty = any | — |
| `WEBULL_TOKEN_DIR` | 2FA token store directory | `./conf/` |
| `WEBULL_AUDIT_LOG_FILE` | Append order audit records here | stderr only |
| `WEBULL_LOG_LEVEL` | SDK log level | `WARNING` |
**Trading is off by default.** The default toolset is read-only. Add `trading`
to `WEBULL_TOOLSETS` to enable order placement, ideally alongside a tight
`WEBULL_SYMBOL_WHITELIST` and notional/quantity caps.
## Authenticate (prod only)
UAT test tokens need no 2FA. For a live account:
```bash
webull-au-mcp auth # approve the request in your Webull app
webull-au-mcp serve
```
## Client configuration
```json
{
"mcpServers": {
"webull-au": {
"command": "uvx",
"args": ["--from", "/path/to/webull-au-mcp", "webull-au-mcp", "serve"],
"env": {
"WEBULL_APP_KEY": "your_app_key",
"WEBULL_APP_SECRET": "your_app_secret",
"WEBULL_ENVIRONMENT": "prod",
"WEBULL_TOOLSETS": "account,market-data,instrument,trading",
"WEBULL_SYMBOL_WHITELIST": "AAPL,MSFT,VOO",
"WEBULL_MAX_ORDER_NOTIONAL_USD": "5000"
}
}
}
}
```
Pass credentials via the client's `env` field rather than a `.env` file in your
workspace, so the model can't read them.
## Docker
The image runs the server over **HTTP transport** (a long-running networked
endpoint at `http://<host>:8000/mcp`), which suits a homelab far better than
stdio.
```bash
cp .env.example .env # fill in credentials
docker compose up -d --build
```
For a **prod** account, cache the 2FA token once (interactive) before starting —
the token persists in the `./conf` volume:
```bash
docker compose run --rm webull-au-mcp auth
docker compose up -d
```
Point an HTTP-capable MCP client at `http://<homelab-ip>:8000/mcp`. For a local
**stdio** client instead of the networked service, run the image directly:
```bash
docker run -i --rm --env-file .env -e WEBULL_MCP_TRANSPORT=stdio webull-au-mcp:latest
```
| Variable | Description | Default (image) |
| --- | --- | --- |
| `WEBULL_MCP_TRANSPORT` | `stdio`, `http`, `sse`, `streamable-http` | `http` |
| `WEBULL_MCP_HOST` | Bind address (http transports) | `0.0.0.0` |
| `WEBULL_MCP_PORT` | Bind port (http transports) | `8000` |
| `WEBULL_MCP_PATH` | MCP endpoint path (http transports) | `/mcp` |
## Tools
**Account** (`account`): `get_account_list`, `get_account_balance`, `get_account_positions`
**Instrument** (`instrument`): `get_instrument`
**Market data** (`market-data`): `get_stock_snapshot`, `get_stock_quotes`,
`get_stock_tick`, `get_stock_bars`
**Trading** (`trading`): `preview_stock_order`, `place_stock_order`,
`replace_stock_order`, `cancel_order`, `get_open_orders`, `get_order_history`,
`get_order_detail`
Order tools hardcode the AU invariants (`market=US`, `instrument_type=EQUITY`,
`entrust_type=QTY`, `combo_type=NORMAL`) and auto-generate the `client_order_id`,
so the model only supplies symbol, side, quantity, order type and price. Every
order passes quantity, notional and whitelist guards before submission; rejected
orders never reach the broker. `place_stock_order` returns the `client_order_id`
you need for `replace`/`cancel`/`get_order_detail`.
Order types: `MARKET`, `LIMIT`, `STOP_LOSS`, `STOP_LOSS_LIMIT`. Time in force:
`DAY`, `GTC`.
## CLI
```
webull-au-mcp init [--env-file PATH] [--force]
webull-au-mcp auth [--env-file PATH]
webull-au-mcp serve [--env-file PATH]
webull-au-mcp status [--env-file PATH]
webull-au-mcp tools [--env-file PATH]
```
## AU-specific notes
- **SDK ≥ 2.0.12 is required.** Earlier releases (including the 2.0.5 the
multi-region upstream pins) only bundle `us`/`hk`/`jp` endpoints, so an `au`
client fails region resolution. UAT hosts are injected explicitly by this
server regardless.
- The upstream server also registers screener/watchlist/fundamental tools. The
AU API reference doThis server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues