Skip to main content
Glama
AdairBear

traderspost-mcp

by AdairBear
README.md
# TradersPost MCP Server

An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that gives Claude direct access to [TradersPost](https://traderspost.io) webhook trading.

Send trade signals, inspect strategy configs, query trade history, and monitor positions — all without leaving Claude Code or Claude Desktop.

> **Why this exists:** TradersPost doesn't expose a full REST management API. This MCP server wraps their webhook system and, optionally, a local [prop_futures_relay](https://github.com/AdairBear/prop_futures_relay) installation to give Claude a complete trading management interface.

---

## What It Does

17 MCP tools covering the full trading workflow:

| Category | Tools |
|----------|-------|
| Strategy management | `tp_list_strategies`, `tp_get_strategy`, `tp_toggle_strategy` |
| Signal submission | `tp_send_signal` |
| Trade history (SQLite) | `tp_get_recent_trades`, `tp_get_fills`, `tp_get_trade_stats` |
| Position state | `tp_get_positions`, `tp_get_daily_pnl` |
| Health & status | `tp_get_relay_health`, `tp_get_strategy_health`, `tp_system_status`, `tp_eval_status` |
| Control (destructive) | `tp_flatten_all`, `tp_flatten_strategy`, `tp_pause_engine`, `tp_resume_engine` |

### Response envelope

Every tool returns one shape. `ok` reflects **semantic** success, not the HTTP status —
a TradersPost HTTP 200 with `success: false` is a rejection and returns `ok: false`.

```jsonc
// success
{ "ok": true,  "data": { /* result */ }, /* ...extras */ }
// failure
{ "ok": false, "code": "machine_code", "detail": "human readable", /* ... */ }
```

Plus two MCP resources:
- `traderspost://signal-format` — webhook payload reference
- `traderspost://active-accounts` — account config summary

---

## Modes

### Relay mode (recommended)

Point `RELAY_DIR` at a local [prop_futures_relay](https://github.com/AdairBear/prop_futures_relay) installation. The server reads `account_config.yaml`, state JSON files, and `trading_system.db` for full functionality.

### Standalone mode

Set `TP_WEBHOOK_<STRATEGY>` env vars directly. Signal sending works; strategy management and trade history tools return empty results.

---

## Installation

**Requirements:** Python 3.10+

```bash
git clone https://github.com/AdairBear/traderspost-mcp.git
cd traderspost-mcp
pip install -r requirements.txt
```

Or install dependencies directly:

```bash
pip install "mcp[cli]" httpx pyyaml python-dotenv
```

---

## Configuration

### Claude Code (`.claude/settings.json`)

**Relay mode** — with a local prop_futures_relay installation:

```json
{
  "mcpServers": {
    "traderspost": {
      "command": "python",
      "args": ["/path/to/traderspost-mcp/traderspost_mcp.py"],
      "env": {
        "RELAY_DIR": "/path/to/prop_futures_relay"
      }
    }
  }
}
```

**Standalone mode** — webhook URLs only:

```json
{
  "mcpServers": {
    "traderspost": {
      "command": "python",
      "args": ["/path/to/traderspost-mcp/traderspost_mcp.py"],
      "env": {
        "TP_WEBHOOK_MY_STRATEGY": "https://traderspost.io/trading/webhook/...",
        "RELAY_URL": "https://relay.yourdomain.app"
      }
    }
  }
}
```

### Claude Desktop (`~/Library/Application Support/Claude/claude_desktop_config.json`)

```json
{
  "mcpServers": {
    "traderspost": {
      "command": "python",
      "args": ["/path/to/traderspost-mcp/traderspost_mcp.py"],
      "env": {
        "RELAY_DIR": "/path/to/prop_futures_relay"
      }
    }
  }
}
```

### Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `RELAY_DIR` | No | Path to a local `prop_futures_relay` installation. Enables strategy config, state files, and SQLite access. |
| `TP_WEBHOOK_*` | Yes (per strategy) | TradersPost webhook URLs. In relay mode, the strategy's `webhook_ref` field names these. In standalone mode, use `TP_WEBHOOK_<STRATEGY_UPPER>`. |
| `RELAY_URL` | No | Base URL of your running relay (e.g. `https://relay.yourdomain.app`). Required for health check tools. |

Copy `.env.example` to `.env` and fill in your values:

```bash
cp .env.example .env
```

The server auto-loads `.env` from `RELAY_DIR` first, then from its own directory.

---

## Tool Reference

### `tp_list_strategies`

List all configured strategies with their status, ticker, account, and webhook configuration.

```
Returns: JSON with strategy list, account summary, and aliases.
Note: webhook URLs are never exposed — only whether they're configured.
```

### `tp_get_strategy`

Get full configuration for a specific strategy including account rules and session window.

```
Args:
  strategy (str): Strategy key, e.g. "sil_crusher_tradovate_44942793"
```

### `tp_toggle_strategy`

Enable or disable a strategy in `account_config.yaml`.

```
Args:
  strategy (str): Full strategy key
  enabled (bool): True to enable, False to disable

Note: Modifies local config only — restart or redeploy the relay for changes to take effect.
```

### `tp_send_signal` ⚠️

Send a trade signal to TradersPost. **Dry-run by default — pass `live=True` to place a real order.**

```
Args:
  strategy (str): Strategy key (or standalone env var suffix)
  ticker (str):   Instrument — "MNQ", "SIL", "MGC", "ES", etc.
  action (str):   "buy", "sell" (entries), "exit", "cancel" (exits)
  quantity (int): Number of contracts (default: 1)
  sentiment (str, optional): "bullish", "bearish", or "flat"
  order_type (str, optional): "market", "limit", or "stop"
  take_profit (float, optional): Take profit price level
  stop_loss (float, optional): Stop loss price level
  live (bool):  True = REAL order. Default False = dry-run preview only.
  test (bool, optional): Force dry-run. If True, overrides live=True (safety wins).
```

**Replay safety:** every attempt is logged to a JSONL audit file (`TP_ATTEMPT_LOG`)
before the POST. An identical *live entry* (buy/sell) within `TP_DEDUP_WINDOW_SEC`
(default 30s) is refused to prevent a timeout-retry duplicate order.

**Exits are sacred:** `exit`/`cancel` are never deduplicated, fire even on a disabled
strategy, and a rejected exit always fails loud (`ok: false`).

### `tp_get_recent_trades`

Query recent trade signals and TradersPost HTTP responses from SQLite.

```
Args:
  limit (int): Max records 1-100, default 20
  strategy (str, optional): Filter by strategy
  account_id (str, optional): Filter by account
  days (int, optional): Lookback window in days
```

### `tp_get_fills`

Query actual fill data (execution prices, slippage) from the fills table.

```
Args: Same as tp_get_recent_trades
```

### `tp_get_trade_stats`

Aggregate statistics: signal success rates, slippage summary, per-strategy breakdown.

```
Args:
  strategy (str, optional): Filter by strategy
  account_id (str, optional): Filter by account
  days (int): Lookback period, default 30
```

### `tp_get_positions`

Get current position state from relay state JSON files, or falls back to relay API.

```
Returns: Per-strategy state: FLAT / IN_POSITION / PENDING_ENTRY / PENDING_EXIT / HALTED
```

### `tp_get_daily_pnl`

Get today's estimated P&L from the relay's daily loss tracker.

```
Returns: Per-account estimated P&L and remaining loss budget.
Note: Estimated from signals, not confirmed broker fills.
```

### `tp_get_relay_health`

Check relay health via the `/health` endpoint.

```
Requires: RELAY_URL env var
Returns: Relay version, uptime, component status
```

### `tp_get_strategy_health`

Get per-strategy status (signal counts, last signal time, halts) from the running relay.

```
Requires: RELAY_URL env var
Returns: Per-strategy status from /health/strategies
```

---

## Usage Examples

### Check what's configured

```
"Show me all configured strategies and which ones have webhooks set up"
→ Claude calls tp_list_strategies()
```

### Dry-run a signal

```
"Send a test buy signal for SIL, 1 contract, to the sil_crusher_tradovate_44942793 strategy"
→ Claude calls tp_send_signal(strategy="sil_crusher_tradovate_44942793", ticker="SIL",
    action="buy", quantity=1, test=True)
```

### Monitor performance

```
"How many signals has sil_crusher sent this week and what's the success rate?"
→ Claude calls tp_get_trade_stats(strategy="sil_crusher_tradovate_44942793", days=7)
```

### Emergency disable

```
"Disable the MNQ strategy immediately"
→ Claude calls tp_toggle_strategy(strategy="coord_mnq_gmr_tradovate_44942793", enabled=False)
```

### Check positions and P&L

```
"What positions are currently open and what's today's P&L?"
→ Claude calls tp_get_positions() and tp_get_daily_pnl()
```

---

## Security Notes

- Webhook URLs are read from environment variables and **never** appear in tool responses or logs
- `tp_send_signal` is marked `destructiveHint: true` — Claude will confirm before calling it
- `test=True` returns the TradersPost trade plan without executing any orders — use it first
- `tp_toggle_strategy` only modifies local config — the running relay is not affected until redeployed

---

## Architecture

```
Claude (MCP client)
    ↓ stdio
traderspost_mcp.py (MCP server)
    ├── account_config.yaml   (strategy config — RELAY_DIR mode)
    ├── data/state/*.json     (position state — RELAY_DIR mode)
    ├── trading_system.db     (trade history — RELAY_DIR mode)
    ├── TP_WEBHOOK_* env vars (webhook URLs — always)
    └── RELAY_URL/health      (live relay status — optional)
         ↓ httpx POST
    TradersPost webhook
         ↓
    Broker (Tradovate, etc.)
```

---

## Requirements

- Python 3.10+
- `mcp[cli]` >= 1.0 (FastMCP)
- `httpx` >= 0.24
- `pyyaml` >= 6.0
- `python-dotenv` >= 1.0 (optional, for .env auto-loading)

---

## License

MIT — see [LICENSE](LICENSE).