# Robinhood Mcp

> Model Context Protocol servers for the official Robinhood Crypto Trading API — the credentialed brokerage API at trading.robinhood.com, documented at docs.robinhood.com/crypto/trading.

- **Type:** MCP server
- **Install:** `agentstack add mcp-nirholas-robinhood-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [nirholas](https://agentstack.voostack.com/s/nirholas)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [nirholas](https://github.com/nirholas)
- **Source:** https://github.com/nirholas/robinhood-mcp
- **Website:** https://github.com/nirholas/robinhood-mcp

## Install

```sh
agentstack add mcp-nirholas-robinhood-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# robinhood-mcp

An execution toolkit for the **official Robinhood Crypto Trading API**, delivered over the Model Context Protocol.

Robinhood's crypto API exposes four order types and nothing else: `market`, `limit`, `stop_loss`, and `stop_limit`. There is no bracket, no OCO, no trailing stop, no TWAP, no iceberg, no scale-in ladder, no scheduled DCA, no portfolio rebalance. Those are the order types people actually want, and every one of them has the same requirement: something has to keep working after the request returns. A trailing stop that exists only for the duration of one tool call is not a trailing stop. This package synthesizes the thirteen order types Robinhood lacks and runs them as **durable background jobs** that survive the agent disconnecting, the server restarting, and the machine rebooting. Around that sit ~73 tools across 8 opt-in modules: quotes and holdings, FIFO cost basis and realized P&L, a trade journal, risk limits with an enforced kill switch, and integration diagnostics.

> **This is not Robinhood Chain**, and it is not Robinhood equities. It targets the brokerage Crypto Trading API at `trading.robinhood.com`, documented at [docs.robinhood.com/crypto/trading](https://docs.robinhood.com/crypto/trading/).

---

## The signing bench — [nirholas.github.io/robinhood-mcp](https://nirholas.github.io/robinhood-mcp/)

The project site is an interactive **Ed25519 signing bench**. You assemble a real Robinhood trading request and produce a genuine signature in your own browser — the math runs client-side on Robinhood's published example key, nothing is sent anywhere — then watch it disprove Robinhood's own documentation: their published test vector verifies against a Python `dict` repr, not the JSON body every client actually sends. It is a single self-contained page in [`docs/`](docs/), so it deploys anywhere static.

Deploy your own copy in one click:

[](https://deploy.workers.cloudflare.com/?url=https://github.com/nirholas/robinhood-mcp)
[](https://app.netlify.com/start/deploy?repository=https://github.com/nirholas/robinhood-mcp)
[](https://vercel.com/new/clone?repository-url=https://github.com/nirholas/robinhood-mcp&project-name=robinhood-mcp&output-directory=docs)

| Target | How |
| --- | --- |
| **GitHub Pages** | Settings → Pages → Source: `main` / `/docs`. Serves at `nirholas.github.io/robinhood-mcp/`. No build step. |
| **Cloudflare Pages** | The button above, or `wrangler pages deploy docs`. Config in [`wrangler.toml`](wrangler.toml). |
| **Google Cloud** | `gcloud storage cp -r docs/* gs:///` behind an HTTPS load balancer, or Cloud Run with any static server rooted at `docs/`. |
| **Netlify / Vercel** | The buttons above. Publish directory is `docs/` ([`netlify.toml`](netlify.toml), [`vercel.json`](vercel.json)). |

---

## Safety

**Robinhood publishes no sandbox.** There is no paper account, no test environment, no dry-run host. Every order this package can place is real money in a real brokerage account, and there is no way to rehearse. Read this section before you set `ROBINHOOD_CRYPTO_ENABLE_TRADING=1`.

Every guard below is enforced **in code**, inside the single `Executor` that all orders pass through, never in a tool description. An instruction in a prompt is a suggestion; a thrown error is not.

| Guard | What it does |
| --- | --- |
| **Separate binary** | The `robinhood-mcp` data server registers no tool that can trade. Attaching it to a general-purpose assistant cannot result in an order. |
| **Explicit opt-in** | The trading server and the daemon refuse to start unless `ROBINHOOD_CRYPTO_ENABLE_TRADING=1`. It cannot be launched by accident. |
| **Per-order USD cap** | Every order is priced before submission and rejected above `ROBINHOOD_CRYPTO_MAX_ORDER_USD` (default `$100`). It **fails closed**: if the USD value cannot be determined up front, the order is rejected rather than assumed cheap. |
| **Cumulative USD cap** | `ROBINHOOD_CRYPTO_MAX_DAILY_USD` refuses once the process has committed that much in total. |
| **Symbol allowlist** | With `ROBINHOOD_CRYPTO_SYMBOL_ALLOWLIST` set, only those pairs may trade. Everything else is refused. |
| **Buy-only** | `ROBINHOOD_CRYPTO_BUY_ONLY=1` rejects every sell order. |
| **Guarded vs autonomous** | In the default `guarded` mode an order tool returns the exact request it *would* send plus a priced estimate, and places nothing until a second call carries `confirm: true`. `ROBINHOOD_CRYPTO_AUTONOMOUS=1` skips that gate for unattended strategies. |
| **Kill switch** | `risk_kill_switch_engage` halts all execution and pauses every running job. Persisted to disk, read on every order and never cached, checked inside the `Executor`. |

Two things about those controls are worth stating plainly, because they are the ones people get wrong.

**Autonomous removes the human, not the ceiling.** The per-order cap, the cumulative cap, the allowlist and the buy-only flag all still apply in autonomous mode. An unattended agent is exactly the case where a runaway order is most likely and least observed.

**The kill switch binds the daemon too.** It lives beside the `Executor` rather than inside the risk tool module, because `robinhood-mcp-daemon` builds its own `Executor` and loads no tool modules at all. A halt installed by a module would leave the one unattended process in the system still placing orders. Because the state is read from disk on every order rather than cached, throwing the switch from an MCP session stops a daemon that has been running since before the switch existed. It fails closed: a row that cannot be parsed reads as *engaged*, because resuming trading over a corrupted row is exactly the failure a kill switch exists to prevent.

Two limits are honest about what they are not. The cumulative cap is a **per-process, in-memory** counter that resets on restart: it is a runaway-loop brake, not an accounting system or a hard budget. And **a durable job's total spend is not capped** at all. Per-order caps apply to each order a job places, but a TWAP with 50 slices under a $100 per-order cap can commit $5,000. Size jobs deliberately and check `risk_status` before starting anything unattended.

Finally, scope the API key itself. Robinhood lets you pick permissions per credential: if you only want reads, do not grant order placement, and the key cannot trade no matter what software holds it. IP allowlisting is also available and worth using.

---

## Install

Requires Node.js **22.5 or newer** (the durable job store uses `node:sqlite`).

Nothing to install ahead of time: MCP clients launch the servers with `npx`.

### 1. Create a credential

```bash
npx robinhood-keygen
```

This prints a fresh Ed25519 keypair as JSON on stdout, with instructions on stderr. Then:

1. Register the **public** key at [robinhood.com/account/crypto](https://robinhood.com/account/crypto). This page exists on **web classic only**, not the mobile app and not the new web UI.
2. Robinhood issues an API key in return. That is `ROBINHOOD_CRYPTO_API_KEY`.
3. Keep the private key as `ROBINHOOD_CRYPTO_PRIVATE_KEY`. It is a **base64-encoded 32-byte Ed25519 seed**, not a 64-byte expanded keypair and not PKCS#8. Several Ed25519 libraries export `seed‖publicKey`; pasting that gives 64 bytes and fails every request. Treat the private key like a password: it authorizes trades, and this package never stores or transmits it anywhere except in the signature it computes locally.

If you already have a keypair from elsewhere, `verify_keypair` (in the `dev` module) checks that a private key matches the public key you registered, without sending anything anywhere.

### 2. Add the server to your MCP client

Two binaries ship in the package, and they are separate on purpose.

| Server | Binary | What it can do |
| --- | --- | --- |
| Data | `robinhood-mcp` | Quotes, holdings, account, order history, cost basis, P&L. **Cannot place an order.** |
| Trading | `robinhood-mcp-trading` | Everything above, plus real orders, synthetic order types, and risk controls. |

**Read-only.** This is the one to start with, and the one to attach to a general-purpose assistant. Paste into `claude_desktop_config.json` (Claude Desktop), `.mcp.json` (Claude Code), or your client's equivalent:

```json
{
  "mcpServers": {
    "robinhood-crypto": {
      "command": "npx",
      "args": ["-y", "robinhood-mcp"],
      "env": {
        "ROBINHOOD_CRYPTO_API_KEY": "rh-api-...",
        "ROBINHOOD_CRYPTO_PRIVATE_KEY": "your-base64-seed"
      }
    }
  }
}
```

Ask your assistant: *"What is my Robinhood crypto buying power, and what is BTC trading at?"*

**Trading.** A separate entry, because it places real orders:

```json
{
  "mcpServers": {
    "robinhood-crypto-trading": {
      "command": "npx",
      "args": ["-y", "robinhood-mcp-trading"],
      "env": {
        "ROBINHOOD_CRYPTO_API_KEY": "rh-api-...",
        "ROBINHOOD_CRYPTO_PRIVATE_KEY": "your-base64-seed",
        "ROBINHOOD_CRYPTO_ENABLE_TRADING": "1",
        "ROBINHOOD_CRYPTO_MAX_ORDER_USD": "50",
        "ROBINHOOD_CRYPTO_MAX_DAILY_USD": "500",
        "ROBINHOOD_CRYPTO_SYMBOL_ALLOWLIST": "BTC-USD,ETH-USD"
      }
    }
  }
}
```

Set the caps to numbers you are comfortable losing. They are the only thing standing between a misunderstood instruction and a real fill.

You can run both entries at once. The data server is safe to leave attached permanently; add the trading server when you intend to trade.

### If you have not set credentials yet

The data server still starts. Rather than exiting (which most MCP clients surface only as an opaque "server failed to start"), it comes up with a single `get_setup_status` tool that reports what is missing and how to fix it. If that is the only tool you see, credentials are not configured: set `ROBINHOOD_CRYPTO_API_KEY` and `ROBINHOOD_CRYPTO_PRIVATE_KEY`, then restart the server and the full tool set appears.

The trading server is deliberately stricter and refuses to start without `ROBINHOOD_CRYPTO_ENABLE_TRADING=1`, so it can never be launched by accident.

---

## Modules

The toolkit is larger than any one agent should see at once. Every tool spends context and adds a wrong option to choose between, which measurably degrades tool selection, so capabilities ship as **modules the operator turns on** with `ROBINHOOD_MCP_MODULES`. Only the selected ones are registered.

| Module | What it does | Default | Places orders |
| --- | --- | --- | --- |
| `market` | Quotes, holdings, account details, trading pairs, order history. | on | no |
| `orders` | The four native order types as individual tools, plus the generic `place_order` and `cancel_order`. | on | **yes** |
| `algo` | The thirteen synthetic order types, run as durable background jobs. | on | **yes** |
| `portfolio` | FIFO cost basis, realized P&L and tax lots, allocation, slippage, volatility, risk-based sizing. | on | no |
| `risk` | Exposure, concentration, drawdown, pre-trade checks, and the enforced kill switch. | on | **yes** |
| `journal` | Fills, round-trip trades, win rate and profit factor, daily summaries, stale open orders, CSV export, reconciliation. | off | no |
| `ops` | Health checks, clock skew, key verification, rate-limit state, API version, supervisor and unsettled-intent status. | off | no |
| `dev` | Connection diagnostics, signature explanation, keypair generation and verification, client codegen, environment check. | off | no |

`risk` is classified as order-placing because engaging the kill switch pauses running jobs. It cannot itself submit an order.

**How selection works:**

- **Unset** loads the default set (`market`, `orders`, `algo`, `portfolio`, `risk`), minus anything the server cannot host. That is 52 tools on the trading server and 16 on the data server.
- **A comma-separated list** loads exactly those: `ROBINHOOD_MCP_MODULES=market,orders,risk`.
- **`all`** loads everything: 73 tools on the trading server.

An unknown module name **fails startup** rather than being silently dropped, because a typo that quietly removes tools is worse than a server that refuses to start.

**Loading everything degrades tool choice.** `all` is useful for a builder exploring the surface and a poor choice for a production agent. Pick the modules the task actually needs. If an agent reports a capability as impossible, have it call `list_modules`: the tool names the exact `ROBINHOOD_MCP_MODULES` value that would enable what is missing, so a disabled module is never mistaken for a capability the toolkit lacks.

The data server refuses to load a mutating module (`orders`, `algo`, `risk`) and fails at startup if asked to, so an operator can never believe they enabled execution when they did not.

Full parameter reference for all 73 tools: **[docs/tools.md](docs/tools.md)**.

---

## The thirteen synthetic order types

Each of these is built on top of Robinhood's four primitives by a supervisor that keeps advancing it over time. Every one is started by its own tool with a typed schema, so a missing or misnamed parameter fails at the schema boundary instead of inside the job.

| Order type | Tool | What it does | Key parameters |
| --- | --- | --- | --- |
| **TWAP** | `algo_twap_start` | Splits one large order into evenly spaced slices over a duration, so the entry averages across the window instead of paying a single spread. | `total_quantity`, `slices`, `duration_minutes`, optional `limit_price` guard |
| **Trailing stop** | `algo_trailing_stop_start` | Follows the market with a stop that ratchets in your favour and never retreats, exiting the full size when price retraces past the trail. | `quantity`, exactly one of `trail_percent` / `trail_amount`, optional `activation_price` |
| **Bracket** | `algo_bracket_start` | Enters a position and attaches a take-profit and a stop-loss that cancel one another, so the trade is never left with only one exit. | `entry_type`, `entry_price`, `take_profit_price`, `stop_loss_price` |
| **OCO** | `algo_oco_start` | Rests a take-profit and a stop against an **existing** position and cancels whichever does not fill. | `quantity`, `take_profit_price`, `stop_price`, optional `stop_limit_price` |
| **DCA** | `algo_dca_start` | Buys or sells a fixed amount on a repeating schedule for a set number of occurrences. | `interval_hours`, `occurrences`, one of `quote_amount_per_buy` / `asset_quantity_per_buy`, optional `max_price` |
| **Ladder** | `algo_ladder_start` | Places a series of resting limit orders across a price range, to scale into or out of a position as price moves. | `total_quantity`, `levels`, `start_price`, `end_price`, `distribution` |
| **Iceberg** | `algo_iceberg_start` | Works a large order behind a small visible slice, refilling as each slice fills, so the book never shows the full size. | `total_quantity`, `visible_quantity`, `max_duration_minutes`, optional `limit_price` |
| **Chase** | `algo_chase_start` | Rests a limit order and reposts it as the book moves away, to fill without crossing the spread. | `quantity`, `max_chases`, `offset_bps`, optional `limit_price` bound |
| **Grid** | `algo_grid_start` | Rests buys below and sells above across a price range, replacing each fill with its opposite one level away, banking the spacing on every round trip. | `lower_price`, `upper_price`, `grid_levels`, `quantity_per_grid`, optional `max_cycles` / `max_duration_minutes` / `stop_price` |
| **Momentum** | `algo_momentum_start` | Enters when price breaks out of its recent range by a set margin, then exits when it retraces a set fraction of the move it reached. | `side`, `quantity`, `lookback_ticks`, `breakout_pct`, `exit_pct`, `max_duration_minutes` |
| **Mean reversion** | `algo_mean_reversion_start` | Fades a price that has stretched a set number of standard deviations from its recent mean, and closes the trade when it reverts toward that mean. | `quantity`, `lookback_ticks`, `entry_z`, `exit_z`, `side_mode`, `max_duration_minutes` |
| **Accumulate** | `algo_accumulate_start` | Buys

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [nirholas](https://github.com/nirholas)
- **Source:** [nirholas/robinhood-mcp](https://github.com/nirholas/robinhood-mcp)
- **License:** Apache-2.0
- **Homepage:** https://github.com/nirholas/robinhood-mcp

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-nirholas-robinhood-mcp
- Seller: https://agentstack.voostack.com/s/nirholas
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
