Skip to main content
Glama
bholzer

tastytrade-mcp

by bholzer
README.md
# 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

A4/5.0

Scored across 18 tools

Disambiguation5/5

All tools target distinct areas: account management, orders, positions, instruments, market data, and health. No overlap; each has a clear and unique purpose.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness5/5

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.

Maintenance

ActivityInactive
ResponsivenessNo issues