gexbot-mcp
README.md
# gexbot-mcp
A thin [MCP](https://modelcontextprotocol.io) server that wraps the [GEXBot API](https://gex.bot)
so it can be added as a **custom connector** in claude.ai.
Built with the official MCP Python SDK (`FastMCP`), served over **Streamable HTTP** so it can be
hosted remotely (e.g. on Render).
Spec reference: [nfa-llc/gexbot-openapi](https://github.com/nfa-llc/gexbot-openapi) — base URL
`https://api.gex.bot/v2`, Bearer-token auth.
## Tools exposed
| Tool | Description |
|---|---|
| `get_gex_levels(ticker, dte=0)` | Zero-gamma/flip level, top 3 call walls, top 3 put walls, net GEX sign + value, spot price, timestamp. |
| `get_gex_profile(ticker, dte=0)` | Per-strike net GEX for strikes within ±3% of spot, trimmed. |
| `list_tickers()` | Supported tickers (stocks/indexes/futures) from GEXBot. |
Plus a plain HTTP `GET /health` endpoint (not an MCP tool) for uptime checks / Render health checks.
### About `dte`
GEXBot doesn't take an arbitrary DTE integer — it buckets data into fixed categories. This server
maps the `dte` argument onto those buckets:
- `dte=0` → `zero` (next expiry / 0DTE)
- `dte=1` → `one` (next expiry + 1)
- any other value → `full` (full aggregation across all published expiries, up to ~90 days out)
### Tickers you care about
No hardcoded restriction — any ticker GEXBot supports works (see `list_tickers()`). The ones you'll
likely use most: `QQQ`, `SPY`, `NDX`, `SPX`, `SPXW`.
## Auth
The server reads `GEXBOT_API_KEY` from the environment at request time and sends it as
`Authorization: Bearer <key>` to GEXBot. **The key is never hardcoded** — it must be set as an
environment variable wherever you run this (locally, in Docker, or on Render).
## Run locally
```bash
python -m venv .venv
.venv\Scripts\activate # Windows
pip install -r requirements.txt
set GEXBOT_API_KEY=gexbot_custom_your_key_here # cmd.exe
# or: $env:GEXBOT_API_KEY = "gexbot_custom_your_key_here" # PowerShell
python server.py
```
The server listens on `http://0.0.0.0:8000` by default (override with `PORT`). The MCP endpoint is
at `/mcp`; health check is at `/health`.
Quick sanity check:
```bash
curl http://localhost:8000/health
```
## Run with Docker
```bash
docker build -t gexbot-mcp .
docker run -p 8000:8000 -e GEXBOT_API_KEY=gexbot_custom_your_key_here gexbot-mcp
```
## Deploy to Render (free tier)
1. Push this folder to a GitHub (or GitLab) repo.
2. In the Render dashboard: **New +** → **Web Service** → connect your repo.
- Render will auto-detect the `Dockerfile`. Leave build/start commands blank (Docker handles it).
- Or, if you prefer a one-click config, this repo includes `render.yaml` — use **New +** →
**Blueprint** and point it at the repo instead.
3. Set the **Instance Type** to **Free**.
4. Under **Environment**, add:
- `GEXBOT_API_KEY` = *your key* (mark it as a **Secret**). Paste this yourself in the Render
dashboard — don't put it in the repo or in `render.yaml`.
5. **Health Check Path**: `/health`.
6. Deploy. Render will build the Docker image and give you a URL like:
`https://gexbot-mcp.onrender.com`
Note: Render's free web services spin down after 15 minutes of inactivity and take ~30-60s to wake
back up on the next request — the first tool call after idle time may be slow.
## Add to claude.ai as a custom connector
1. In claude.ai: **Settings → Connectors → Add custom connector**.
2. URL: `https://<your-app>.onrender.com/mcp`
3. Save. Claude will discover the three tools (`get_gex_levels`, `get_gex_profile`, `list_tickers`).
## Error handling
All tools return a compact JSON dict. On failure they return `{"error": "<message>", ...}` instead
of raising, so the model can see and relay the problem. Handled cases:
- **Bad/missing API key** → 401 from GEXBot → clear "check GEXBOT_API_KEY" message.
- **Key lacks access to a resource** → 403 → clear message.
- **Unsupported ticker** → 404 → clear message.
- **Bad request** (e.g. malformed ticker/category) → 400 → GEXBot's error message surfaced.
- **GEXBot outage / market-closed edge cases** → 5xx handled with a clear message; additionally,
`get_gex_levels` / `get_gex_profile` include a `"stale": true` flag when the returned data's
timestamp is more than 24h old, since GEXBot itself doesn't have an explicit "market closed" error.
- **Network/timeout errors** → clear message, no stack trace leaked to the client.
## Project layout
```
server.py # the MCP server (FastMCP, Streamable HTTP)
requirements.txt
Dockerfile
render.yaml # optional Render Blueprint config
.env.example
```
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues