tastytrade-mcp
# tastytrade-mcp
MCP server for the [tastytrade](https://tastytrade.com) brokerage API, built in TypeScript on the official [`@tastytrade/api`](https://github.com/tastytrade/tastytrade-api-js) SDK. Runs over stdio.
This is a rebuild of the earlier Python `tastytrade_mcp` server with a deliberately leaner surface: single-tenant, env-var auth, no database, and only tools backed by real API endpoints.
## Setup
No clone, no build — `npx` installs straight from this repo and compiles automatically on first run. You need **Node 20+** and **SSH access to this GitHub repo** (the same `git@github.com` key you use for pushing).
1. Create an OAuth client and a personal-grant refresh token at [my.tastytrade.com → Manage → API Access](https://my.tastytrade.com/app.html#/manage/api-access). You need the **client secret** and the **refresh token** (access tokens are generated and refreshed automatically).
2. Put the secrets in your environment (shell profile, or a gitignored `.env` loaded by direnv — **never** in a file you commit):
```sh
export TASTYTRADE_CLIENT_SECRET="..."
export TASTYTRADE_REFRESH_TOKEN="..."
```
3. Register with your MCP client.
**Project `.mcp.json` (Claude Code) — safe to commit.** `.mcp.json` supports `${VAR}` environment-variable expansion, so the file holds only references; values are read from the environment Claude Code was launched in. If a variable is missing, the config fails to load rather than silently sending an empty secret:
```json
{
"mcpServers": {
"tastytrade": {
"command": "npx",
"args": ["-y", "git+ssh://git@github.com/bholzer/tastytrade-mcp.git"],
"env": {
"TASTYTRADE_CLIENT_SECRET": "${TASTYTRADE_CLIENT_SECRET}",
"TASTYTRADE_REFRESH_TOKEN": "${TASTYTRADE_REFRESH_TOKEN}",
"TASTYTRADE_ENVIRONMENT": "${TASTYTRADE_ENVIRONMENT:-production}"
}
}
}
}
```
> ⚠️ Don't use `claude mcp add --scope project --env TASTYTRADE_CLIENT_SECRET=...` — that writes the **literal secret value** into `.mcp.json`, which is exactly the file that gets committed. Write the `${VAR}` form by hand as above.
**One-liner (Claude Code, user scope).** `claude mcp add` defaults to local/user config (`~/.claude.json`), which never leaves your machine, so passing values directly is acceptable there:
```sh
claude mcp add tastytrade \
--env TASTYTRADE_CLIENT_SECRET="$TASTYTRADE_CLIENT_SECRET" \
--env TASTYTRADE_REFRESH_TOKEN="$TASTYTRADE_REFRESH_TOKEN" \
-- npx -y git+ssh://git@github.com/bholzer/tastytrade-mcp.git
```
**Claude Desktop.** `claude_desktop_config.json` does *not* support `${VAR}` expansion — you have to paste the values in. That file is local-only (not committed), but be aware the secrets sit in plaintext on disk.
The first launch takes ~30s while npm clones and compiles; after that it starts from cache. To pin a specific version, append a tag or commit: `...tastytrade-mcp.git#v1.0.0`.
### Updating
`npx` caches the install. To pick up new commits:
```sh
npx clear-npx-cache # then the next launch re-installs from HEAD
```
(Or pin to tags and bump the tag in your config.)
### Running from a local checkout (development)
```sh
claude mcp add tastytrade \
--env TASTYTRADE_CLIENT_SECRET="$TASTYTRADE_CLIENT_SECRET" \
--env TASTYTRADE_REFRESH_TOKEN="$TASTYTRADE_REFRESH_TOKEN" \
-- node /path/to/tastytrade-mcp/dist/index.js
```
### Environment variables
| Variable | Required | Description |
|---|---|---|
| `TASTYTRADE_CLIENT_SECRET` | yes | OAuth client secret |
| `TASTYTRADE_REFRESH_TOKEN` | yes | OAuth personal-grant refresh token |
| `TASTYTRADE_ENVIRONMENT` | no | `production` (default) or `sandbox` (cert environment) |
| `TASTYTRADE_SCOPES` | no | OAuth scopes, default `read trade` |
## Tools (18)
**System**
- `health_check` — verify credentials, report environment and customer.
**Accounts & portfolio**
- `get_accounts` — list accounts.
- `get_balances` — cash, net liq, buying power, margin usage.
- `get_positions` — open positions, filterable by symbol/underlying, optional marks.
- `get_transactions` — transaction history with date/symbol/type filters and paging.
- `get_net_liq_history` — historical net liquidating value (`1d`–`all`).
- `get_margin_requirements` — margin/buying-power requirements report.
**Market data**
- `search_symbols` — symbol search.
- `get_instrument` — full instrument definition (tick size, streamer symbol, …) for equities, options, futures, future options, crypto.
- `get_market_metrics` — IV rank/percentile, liquidity, beta, earnings/dividend dates.
- `get_option_chain` — nested option chain with expiration/DTE/strike/type filters; returns an expiration summary when unfiltered to keep responses small.
- `get_quotes` — live bid/ask, last trade, OHLC summary, and Greeks (for options) via the dxLink websocket streamer. Accepts equity, OCC option, futures, and future-option symbols.
**Trading**
- `create_order` — 1–4 leg orders for any instrument type. **Dry-run by default**: returns the preview (buying-power effect, fees, warnings) without placing anything; requires explicit `dry_run: false` to submit.
- `list_orders` — order history or live working orders.
- `get_order` — single order status.
- `cancel_order` — cancel one order.
- `replace_order` — modify price/type/TIF of a working order.
- `cancel_all_orders` — cancel every working order in an account (optionally one underlying).
## Differences from the Python server
- OAuth only (the v7 JS SDK no longer supports session login as a client config). Sandbox use requires a cert-environment OAuth client instead of sandbox username/password.
- Dropped: multi-user database mode, encrypted token storage, shortcuts, and tools that had stub/fake implementations (fake streaming endpoints, correlation analysis, opportunity scanning). The persistent "emergency state" machinery is replaced by the real `cancel_all_orders` action.
- `set_stop_loss` / `set_take_profit` are expressible through `create_order` (`order_type: "Stop"` / `"Limit"` with closing legs).
## Development
```sh
npm run watch # incremental compile
npm start # run the built server
```
TDQS
Scored across 18 tools
All tools target distinct areas: account management, orders, positions, instruments, market data, and health. No overlap; each has a clear and unique purpose.
All tool names follow a consistent verb_noun pattern in lowercase snake_case (e.g., get_accounts, create_order, cancel_all_orders). Only health_check is slightly different but still follows a common pattern.
18 tools is well-scoped for a trading platform, covering account info, order lifecycle, positions, instruments, market data, and health. Each tool earns its place without excess.
Provides full lifecycle for orders (create, cancel, replace, list, get) plus account balances, positions, instruments, market metrics, and transactions. No obvious gaps for typical trading workflows.