Remote MCP
Lets hosted AI clients (ChatGPT, Claude.ai, Claude mobile) talk to your Tradeboard install over the internet so you can ask them to fetch quotes, summarise positions, or place orders in plain English.
Local stdio MCP (Claude Desktop / Cursor / Windsurf on the same machine as your install) keeps working unchanged. Remote MCP is a parallel, opt-in transport that shares the same tool registry but reaches it over HTTPS.
| You want to... | Use |
|---|---|
| Trade from your laptop using Claude Desktop, Cursor, or Windsurf | Local stdio (MCP setup guide) |
| Trade from ChatGPT.com, Claude.ai, or the Claude mobile app | Remote MCP (this guide) |
| Both | Enable both, they don't interfere |
What you need
- Tradeboard on your own domain with HTTPS. Dashboard reachable at
https://yourdomain.com, login + broker auth + orders all working through the web UI. If you're not there yet, start with one of the install scripts:install/install.sh,install/install-multi.sh,install/install-docker.sh, orinstall/install-docker-multi-custom-ssl.sh. - Tradeboard 2.0.1.0 or later. The dashboard footer shows the version;
GET https://yourdomain.com/auth/app-inforeturns it as JSON. On older builds runinstall/update.shfirst. - An Tradeboard API key. Generate one at Profile → API Keys. The MCP server uses it server-side; hosted clients never see it, they get OAuth tokens instead.
- A hosted client account that supports custom MCP connectors. Check the client's current plan and workspace requirements; these are controlled by the client vendor.
Turn it on
Native install (install.sh)
The installer asks at run time whether to enable Remote MCP. If you said yes, it's already on at https://yourdomain.com/mcp, skip to Connecting.
If you said no and want to flip it now, edit /var/python/tradeboard/.env:
MCP_HTTP_ENABLED = 'True'
MCP_PUBLIC_URL = 'https://yourdomain.com'Then sudo systemctl restart tradeboard.
Multi-domain native (install-multi.sh)
Edit the per-deploy .env (typically /var/python/tradeboard-flask/<deploy-name>/.env) with the same two keys, then sudo systemctl restart tradeboard-<deploy-name>.
Docker (install-docker.sh / install-docker-multi-custom-ssl.sh)
cd /path/to/tradeboard
sudo ./install/enable-remote-mcp-docker.shThe helper picks the stack (or asks if you have several), backs up the bind-mounted .env, sets the keys, restarts the container, and probes the OAuth + healthz endpoints. Re-run for each instance.
Defaults after enabling
Native installers only turn on MCP_HTTP_ENABLED and set MCP_PUBLIC_URL. They inherit the current .sample.env values: approval is off and write scope is enabled. Review these settings before exposing the service:
MCP_OAUTH_REQUIRE_APPROVAL = 'True'
MCP_OAUTH_WRITE_SCOPE_ENABLED = 'False'The enable-remote-mcp-docker.sh helper applies that stricter posture automatically: new clients require approval and Remote MCP starts read-only. It also preserves the default browser allowlist of https://claude.ai,https://chatgpt.com.
Enable MCP_OAUTH_WRITE_SCOPE_ENABLED=True only after validating read-only sessions and deciding that hosted clients may place or modify orders.
Connecting & using ChatGPT and Claude
Once it's enabled, your MCP URL is:
https://yourdomain.com/mcpWith MCP_OAUTH_REQUIRE_APPROVAL=True, the first connection pauses until you approve the client at /admin/remote-mcp. With approval disabled, registration proceeds immediately; use that setting only on a deliberately restricted deployment.
Adding Tradeboard to ChatGPT
Heads up: ChatGPT recently renamed Connectors → Apps. Same feature, new menu name. The in-chat menu still says Connectors, so don't be confused.
Step 1: Open Apps settings
- Avatar (bottom left) → Settings
- Sidebar → Apps
- Top right → Add more → opens New App BETA
Step 2: Fill in the form
| Field | Value |
|---|---|
| Name | Tradeboard |
| Description | Tradeboard trading server (optional) |
| MCP Server URL | https://yourdomain.com/mcp |
| Authentication | OAuth |
Step 3: Advanced OAuth settings
Expand Advanced OAuth settings → Registration method → Dynamic Client Registration (DCR).
The notice "CIMD is unavailable…" is expected, Tradeboard advertises DCR. DCR is the right pick.
Default scopes ChatGPT requests are read:market read:account. Add write:orders only if you've turned MCP_OAUTH_WRITE_SCOPE_ENABLED=True on the server and you want this connector to place orders.
Step 4: Acknowledge and create
Tick "I understand and want to continue" under the orange warning, then Create.
Step 5: Pending approval (when enabled)
ChatGPT will show:
OAuth authorization failed: unauthorized_client
This is expected only when MCP_OAUTH_REQUIRE_APPROVAL=True. Your server saw the registration but is holding it until you approve. Don't dismiss the modal.
Step 6: Approve in Tradeboard
- New tab →
https://yourdomain.com/admin/remote-mcp - Sign in (TOTP if MCP 2FA is on)
- Pending approvals → verify name + timestamp match → Approve
Step 7: Complete OAuth
- Back in ChatGPT → Reconnect
- A tab pops to
https://yourdomain.com/oauth/authorize?... - Sign in if needed → consent screen lists scopes (verify the redirect URI is a
chatgpt.comURL) → Authorize - App moves from Drafts to Enabled
Step 8: Use it
In any new chat, click + below the message box → Connectors → toggle Tradeboard ON.
Try:
"Using Tradeboard, give me the LTP of RELIANCE on NSE."
ChatGPT calls get_quote and shows the price. With read:account granted, also try:
"What's my account balance and current open positions?"
Client policy and tool availability
Tradeboard exposes tools allowed by the granted OAuth scopes. ChatGPT can apply additional product policy, confirmation, plan, and connector restrictions, so the tools visible or executable in a client can differ from the server's tools/list response. Verify sensitive operations in Analyzer Mode and do not treat a granted write:orders scope as a guarantee that a hosted client will execute every write tool.
Useful ChatGPT prompts
- "Get me the bid-ask spread for INFY and HDFCBANK"
- "Summarise my holdings and tell me which are in profit"
- "Pull 1-day candles for SBIN for the last 30 days and tell me the trend"
- "List my orders from today and show fills vs rejects"
Adding Tradeboard to Claude.ai
Step 1: Connectors page
claude.ai → name (bottom left) → Settings → Connectors.
Step 2: Add custom
Top right + → Add custom connector.
Step 3: Fill in
| Field | Value |
|---|---|
| Name | Tradeboard |
| Remote MCP server URL | https://yourdomain.com/mcp |
Leave Advanced settings alone, OAuth is detected automatically. Click Add.
Step 4: Pending approval (when enabled)
When MCP_OAUTH_REQUIRE_APPROVAL=True, the first attempt fails with a pending-approval error. Keep the page open. With approval disabled, continue directly to OAuth consent.
Step 5: Approve in Tradeboard
https://yourdomain.com/admin/remote-mcp → Pending approvals → Approve.
Step 6: Complete OAuth
Back in claude.ai → Connect on the connector card → sign in to Tradeboard (+ TOTP if on) → consent screen (verify redirect URI is claude.ai) → Authorize. Card switches to Disconnect when you're live.
Step 7: Tool permissions
Click your Tradeboard connector to expand permissions:
| Group | Recommendation |
|---|---|
Interactive tools (place_order, modify_order, cancel_order, ...) | Ask me at first; Always allow once you trust the prompts |
| Read-only tools | Always allow |
| App-only tools | Always allow |
You can override individual tools, e.g. Always allow most things but force Ask me for cancel_all_orders.
Step 8: Use it
In any chat, click the Tools icon below the message box → toggle Tradeboard on.
"Show me the current LTP of NIFTY 50 and a quick view of my open positions."
Claude shows expandable tool-call cards. Ask me tools surface a permission prompt with Allow once / Always allow / Deny.
Client policy and tool availability
Tradeboard exposes the same scoped registry to Claude.ai, but Claude can apply client-side permissions, plan limits, confirmations, or policy restrictions. Check the connector's current tool list and require confirmation for destructive operations.
Recommended posture for write tools
- Start in Sandbox / Analyzer mode (
/analyzer) and dry-run prompts before turning live trading on - Keep MCP 2FA on, fresh authorization for
write:ordersthen requires TOTP - Set a tight
MCP_RATE_LIMIT_WRITE(e.g.5 per minute) so a runaway model can't fire a flurry of orders before you intervene - Tail
log/mcp.jsonlwhile testing, every call recorded with timestamp, scope, outcome, latency - Keep the Kill switch at
/admin/remote-mcpone click away
Useful Claude prompts
- "Place a limit BUY for 1 share of TCS at ₹3500 in CNC product on NSE"
- "Modify my last open INFY order, change the quantity to 5"
- "Cancel all my open orders"
- "What was my P&L today?"
For more example prompts per tool, see the Tool References, the same prompts work on Remote MCP.
Switching scopes after connecting
Already connected with read:market read:account and want to add write:orders?
- Set
MCP_OAUTH_WRITE_SCOPE_ENABLED=Truein.envand restart - Disconnect the connector / app in ChatGPT or Claude
- Re-add it with the broader scope set
- Re-approve at
/admin/remote-mcp
OAuth doesn't let an existing token widen its scope, re-consent is required. By design.
Daily operations
/admin/remote-mcp
| Section | What it's for |
|---|---|
| Pending approvals | New clients land here. Approve only ones you recognise, the name is set by the hosted client itself |
| Approved clients | Currently authorised. Each row shows last-used time |
| Revoked clients | Permanent. There is no un-revoke. The client must register again through DCR for a new client_id |
| MCP tool call audit | Every tool call: timestamp, client, tool, scope, outcome, latency. Filter by tool or outcome |
| Kill switch | Revokes every live refresh token in the system, not only those of approved clients. Existing access JWTs remain valid until their short expiry |
Audit log
Same data as the admin page, written to log/mcp.jsonl as JSON Lines. Tail with:
tail -f log/mcp.jsonlTool arguments are hashed, not stored verbatim, so the log itself is not a data leak.
2FA enforcement
Profile → TOTP → 2FA Enforcement lets you gate three independent purposes:
| Purpose | What it gates |
|---|---|
| Dashboard sign-in | TOTP after password on every login |
| Remote MCP authorization | Fresh TOTP at /oauth/authorize for every write:orders grant |
| Password reset | Forces TOTP path (no email fallback) |
All three default off so existing installs see no change. Saving requires a fresh TOTP code in the same request, proves you have authenticator access for both enabling and disabling.
Configuration reference
All keys live in .env (native) or the bind-mounted .env (Docker). Native installers set the master switch and public URL; the dedicated Docker helper also applies the stricter approval and write-scope settings described above.
| Key | Sample default | Purpose |
|---|---|---|
MCP_HTTP_ENABLED | False | Master switch |
MCP_PUBLIC_URL | empty; required when enabled | Public HTTPS origin advertised in OAuth metadata |
MCP_OAUTH_REQUIRE_APPROVAL | False | New clients require admin approval when enabled |
MCP_OAUTH_WRITE_SCOPE_ENABLED | True | Whether write:orders is grantable at all |
MCP_HTTP_CORS_ORIGINS | https://claude.ai,https://chatgpt.com | Browser allowlist |
MCP_HTTP_IP_ALLOWLIST | empty | Present in .sample.env but not implemented. Setting it has no effect; use the reverse proxy or firewall for IP filtering |
MCP_OAUTH_ACCESS_TTL | 900 | Access-token TTL in seconds (max 3600) |
MCP_OAUTH_REFRESH_TTL | 2592000 | Refresh-token TTL in seconds (30 days; min 3600, max 31 days) |
MCP_OAUTH_CODE_TTL | 60 | Authorization-code TTL (max 300) |
MCP_RATE_LIMIT_READ | 60 per minute | Per-token cap for read scopes |
MCP_RATE_LIMIT_WRITE | 50 per minute | Per-token cap for write:orders |
MCP_LOOPBACK_URL | inherits HOST_SERVER | Override only for unusual topologies |
MCP_OAUTH_KEYS_DIR | keys | Directory for RS256 signing keys |
TRADEBOARD_MCP_READ_ONLY | off | Drops all 11 order tools from the registry, leaving 37. Survives an already-granted write:orders scope |
TRADEBOARD_MCP_TOOLSETS | all | Comma-separated subset of orders, account, marketdata, research, utility |
TRADEBOARD_MCP_TRUST_ENVELOPE | 1 | Set to 0 to return bare payloads instead of the trust envelope |
The last three apply to both the stdio and HTTP transports.
Security model
The defenses, in plain order:
- Optional approval gate: with
MCP_OAUTH_REQUIRE_APPROVAL=True, clients cannot complete OAuth until you approve them at/admin/remote-mcp - Scope gate:
write:ordersis invisible in OAuth discovery whenMCP_OAUTH_WRITE_SCOPE_ENABLED=False - Short access tokens: 15-minute TTL caps the damage window if a token is stolen
- Rate limits: per-token, separately for reads and writes
- PKCE + JWT: S256-only PKCE, exact redirect_uri matching, signed access JWTs, and rotating refresh tokens
- Refresh-token family protection: reuse of an already-rotated refresh token revokes its entire token family
- Kill switch: one click revokes all refresh tokens; already-issued access JWTs remain valid until expiry
- Read-only mode:
TRADEBOARD_MCP_READ_ONLYremoves every order tool from the registry, so even a client already holdingwrite:orderscannot place an order
send_telegram_alert is the one exception to "read scopes cannot cause an effect outside Tradeboard". It is annotated as a write tool but gated on read:account, so a read-only hosted session can still send outbound Telegram messages.
The blast radius is real. A stolen access token can place orders the broker accepts; they originate from your registered server IP. The 15-minute default TTL limits the window, but the kill switch does not immediately invalidate an access JWT. Never combine
MCP_OAUTH_WRITE_SCOPE_ENABLED=TruewithMCP_OAUTH_REQUIRE_APPROVAL=Falseon a public deployment: that lets any internet client register, auto-approve, and request order scope.
For the implementation boundaries behind these controls, see MCP Architecture.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
unauthorized_client after Create / Add | DCR client not approved yet | Approve at /admin/remote-mcp |
invalid_client on retry | Client revoked or DB reset; old client_id cached | Disconnect + re-add to force fresh DCR |
| "Server doesn't implement OAuth" | Old build | Update to 2.0.1.0+ |
| "CIMD is unavailable" in ChatGPT | Tradeboard advertises DCR, not CIMD | Expected: pick DCR |
| Tools missing from chat | Connector not toggled on for that chat | + menu (ChatGPT) or Tools menu (Claude) |
bad_arguments on a tool call | Hosted client guessed parameter names | Update Tradeboard (newer builds expose strict tool schemas) |
| Sudden 401 on every call | Refresh token expired or kill switch fired | Reconnect on the connector |
place_order blocked on ChatGPT | OpenAI's safety policy | Use Claude.ai for order placement |
| "Failed to connect to the server" on tool calls | Loopback misconfigured | Confirm HOST_SERVER in .env matches your dashboard URL; restart |
Tokens issued but /mcp returns 401 | MCP_PUBLIC_URL changed after the tokens were minted, or the tokens came from a different instance | Tokens carry iss/aud derived from MCP_PUBLIC_URL at issue time and are checked against the server's current value. Keep the value stable, or reconnect the client after changing it |
| Form submit blocked by CSP | Old build | Update to 2.0.1.0+ |
| Container won't restart after enabler | Bad .env change | Run the rollback one-liner the enabler printed; restart; check log/errors.jsonl |
Subdomain mode (advanced)
If you want MCP on a separate hostname (e.g. mcp.yourdomain.com) so its cookies, CORS, and TLS lifecycle are isolated from the dashboard, the manual recipe is in install/Remote-MCP-readme.md. Same nginx + certbot pattern as install-docker-multi-custom-ssl.sh. Most users don't need this; same-domain is what the installer automates.
Disabling
Native:
sudo sed -i "s|MCP_HTTP_ENABLED.*|MCP_HTTP_ENABLED = 'False'|" /var/python/tradeboard/.env
sudo systemctl restart tradeboard(install-multi.sh users: substitute the per-deploy .env and service name.)
Docker:
sudo sed -i "s|MCP_HTTP_ENABLED.*|MCP_HTTP_ENABLED = 'False'|" /opt/tradeboard/<domain>/.env
cd /opt/tradeboard/<domain> && sudo docker compose restartOAuth + MCP routes immediately stop responding. Existing tokens hit 404. Local stdio MCP is unaffected: it runs over stdin/stdout and doesn't touch the HTTP transport.
For a softer takedown that keeps Remote MCP enabled, visit /admin/remote-mcp → Kill switch. It revokes refresh tokens, so hosted clients must complete OAuth again after their current access JWT expires. To stop access immediately, disable Remote MCP and restart the application.
Related
- MCP Server Setup Guide: local stdio integration with Claude Desktop / Cursor / Windsurf
- Tool References: every tool with parameters and example prompts (shared across both transports)
- Tradeboard Symbol Format: how equity / future / option symbols are constructed
install/Remote-MCP-readme.md: operator-focused install + threat model in the source tree- MCP Architecture: transport and OAuth implementation boundaries
