loading…
Search for a command to run...
loading…
An MCP server that connects to the Charles Schwab brokerage API to enable account management, market data retrieval, and secure order execution. It includes a C
An MCP server that connects to the Charles Schwab brokerage API to enable account management, market data retrieval, and secure order execution. It includes a Claude Code plugin with specialized skills for optimized tool selection and safety-focused confirmation patterns for trading.
An MCP server that connects to the Charles Schwab brokerage API, plus a Claude Code plugin with skills that save LLM roundtrips when calling the MCP tools.
MCP Server — Wraps the Schwab API via schwabdev and exposes 18 tools over Streamable HTTP:
| Category | Tools |
|---|---|
| Session | list_accounts, set_active_account, get_active_account |
| Market Data | get_quotes, get_option_chain, get_option_expirations, get_price_history, get_movers, get_market_hours |
| Accounts | get_account, get_transactions, get_transaction, get_preferences |
| Orders | list_orders, list_all_orders, get_order, place_order, cancel_order, replace_order, preview_order |
| Instruments | search_instruments, get_instrument |
Claude Code Plugin — Ships six skills (schwab:account, schwab:orders, schwab:quotes, schwab:market, schwab:instruments, schwab:chart-orders) that give Claude the tool-selection rules, parameter formats, and safety patterns upfront. This eliminates the back-and-forth the LLM would otherwise need to figure out which tool to call and how to call it.
# Clone and install
git clone <repo-url> && cd schwab-mcp
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
# Add credentials
cp .env.example ~/.schwab-mcp/.env
# Edit ~/.schwab-mcp/.env with your Schwab app key and secret
# Authenticate (opens browser for OAuth)
schwab-mcp auth
# Start the server
schwab-mcp serve
The server listens on http://127.0.0.1:8099/mcp by default. Override with env vars SCHWAB_MCP_HOST and SCHWAB_MCP_PORT.
Install the plugin directory so Claude Code picks up the MCP connection and skills:
claude plugin add ./plugin
This registers:
plugin/.mcp.json)Once installed, ask Claude things like:
You: Buy 100 shares of SPY with limit order at current median bid-ask spread.
This order should be canceled if it weren't filled before 3/30 12PM ET.
Claude: I need to get SPY's current bid-ask spread first, then build the order.
Let me fetch the quote.
[calls get_quotes for SPY]
Got the quote. Here's the current SPY pricing:
- Bid: $632.70
- Ask: $633.00
- Midpoint: $632.85
Regarding cancellation by 3/30 12PM ET — Schwab doesn't support
"cancel at a specific time." I'll use DAY duration (valid through
market close on 3/30). You'd need to manually cancel at noon if
unfilled.
[calls place_order with confirmed=False — dry run]
| Field | Value |
|------------|----------------------------|
| Action | BUY |
| Symbol | SPY |
| Quantity | 100 shares |
| Order Type | LIMIT |
| Price | $632.85 (bid-ask midpoint) |
| Duration | DAY |
| Session | NORMAL |
Shall I submit this order?
You: yes
Claude: [calls place_order with confirmed=True]
Order submitted successfully.
The skill guided Claude to:
confirmed=False) and show the summaryconfirmed=True) after explicit user approvalYou: Plot my last week's credit spread trades
Claude: [fetches filled orders for Mar 22-28]
39 credit spread orders on SPXW last week — 30 vertical spreads
and 9 iron condors across 5 trading days.
[fetches 15-minute SPX candles for the same range]
[runs chart_orders.py with candles + orders data]
Candles: 130, Orders: 62 (12 buy, 11 sell, 39 spread)
Interactive chart saved to plugin/skills/chart-orders/chart.html

The skill guided Claude to:
Mutating operations (place_order, cancel_order, replace_order) use a two-step confirmation pattern. The first call is a dry run that shows what would happen; you must explicitly confirm to execute.
src/schwab_mcp/
server.py # CLI entry point (serve / auth commands)
client.py # Schwab client init, OAuth tokens, state persistence
_mcp.py # FastMCP server instance
logging_config.py # Rotating log handler with credential redaction
tools/ # MCP tool implementations
session.py # Account listing and selection
market_data.py # Quotes, options, price history, movers
accounts.py # Account details, transactions, preferences
orders.py # Order CRUD with dry-run safety
instruments.py # Symbol/CUSIP lookup
plugin/
.mcp.json # MCP server connection config
.claude-plugin/plugin.json # Plugin metadata
hooks/hooks.json # Session cleanup hook
skills/ # Claude Code skill definitions
All runtime state lives in ~/.schwab-mcp/:
| File | Purpose |
|---|---|
.env |
API credentials |
tokens.db |
OAuth tokens (auto-refreshed by schwabdev) |
state.json |
Active account selection |
schwab-mcp.log |
Rotating log (5 MB, 3 backups, credentials redacted) |
Large tool responses (option chains, long transaction lists) are written to /tmp/schwab-mcp/ and cleaned up automatically when the Claude Code session ends.
# Run tests
pytest
# Run with debug logging
LOG_LEVEL=DEBUG schwab-mcp serve
Добавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"schwab-mcp": {
"command": "npx",
"args": []
}
}
}