MCP
MCP server
Connect Claude Code, Codex, Cursor or any host; the seven tools; protocol details.
The MCP server is the API for agents: the same key, the same limits and the same nightly data, as seven tools a host calls on the user's behalf. It speaks Streamable HTTP at https://api.tradingpal.io/mcp, is stateless, and signs the user in through the browser, so there is no key to copy. A keyless demo server at https://api.tradingpal.io/mcp/demo lets an agent show the data before anyone signs up.
Connect
Add the server with no key. Its first answer is a 401 with a pointer your host follows: the browser opens on TradingPal, you sign in and approve, and the host keeps a token it refreshes by itself. The approval shows up on Keys as a key named after the host, where you can revoke it.
claude mcp add --transport http tradingpal https://api.tradingpal.io/mcp
# then, inside Claude Code: /mcp → tradingpal → sign inAdd to CursorOpens Cursor with the server filled in; click Needs login next to it to sign in.
Claude.ai and ChatGPT take the same address as a custom connector and run the same sign-in. Then ask the host, in plain words, what is setting up on your tickers.
Install as a plugin
The plugin bundles the server above with the skill, so the agent also knows the presentation rules. Source: github.com/rendude/tradingpal-plugins.
claude plugin marketplace add rendude/tradingpal-plugins
claude plugin install tradingpal@tradingpalWith a key instead
A host on a machine with no browser sends a key in the same header the REST API takes: --header "Authorization: Bearer $TRADINGPAL_API_KEY" on claude mcp add, bearer_token_env_var = "TRADINGPAL_API_KEY" under [mcp_servers.tradingpal] in Codex's config.toml, or a headers block in Cursor's JSON. A key skips the sign-in; it never triggers one.
Tools
| Tool | Key | Arguments | Returns |
|---|---|---|---|
get_ticker_patterns | yes | symbol | Current setups on one tracked ticker, the same payload as GET /tickers/{symbol}/patterns. |
get_pattern_history | yes | symbol, limit?, outcome? | Past occurrences with outcomes, newest first, as GET /tickers/{symbol}/history. |
get_pattern_chart | yes | symbol, setup_id | The chart PNG as an image content block, so the model can look at it. |
list_tracked_tickers | yes | none | The tracked list with covered flags. |
set_tracked_tickers | yes | symbols | Replaces the tracked list, all-or-nothing. Read first, then send the full list. |
get_family_track_record | no | family? | One family's track record, or all five. |
demo | no | symbol | Current setups on a demo symbol, with the chart as an image, for anyone. |
Tool results carry the JSON payload as text and as structuredContent, so a host can show it or reason over it. Tool errors come back as tool errors (not protocol errors) whose text starts with the error code and ends with the fix, so the model can act on them.
Without an account
https://api.tradingpal.io/mcp/demo initializes and lists the tools for anyone, with no sign-in and no key. demo and get_family_track_record answer; the other five return a tool error that says how to connect for real. This is deliberate: an agent can show a person what the data looks like on a large cap, then send them to the sign-in.
Sign-in flow
What a host does under the hood, for anyone writing one:
| Step | Where |
|---|---|
| Discover | POST https://api.tradingpal.io/mcp without credentials answers 401 with WWW-Authenticate: Bearer resource_metadata="https://api.tradingpal.io/.well-known/oauth-protected-resource/mcp". That document names the authorization server, https://api.tradingpal.io, whose metadata is at https://api.tradingpal.io/.well-known/oauth-authorization-server. |
| Register | POST https://api.tradingpal.io/oauth/register (RFC 7591) with client_name and redirect_uris. Public clients (token_endpoint_auth_method: "none") are the norm; loopback http://127.0.0.1:<any port>/…, https:// and native app schemes are accepted as redirects. |
| Authorize | GET https://api.tradingpal.io/oauth/authorize with response_type=code, the client_id, the redirect_uri, a PKCE code_challenge (S256 only) and state. The user signs in and approves; the code comes back on the redirect with state and iss. |
| Token | POST https://api.tradingpal.io/oauth/token with grant_type=authorization_code, the code, the code_verifier and the client_id. Returns a Bearer access token (7 days) and a refresh token (90 days). grant_type=refresh_token rotates both; a replayed refresh token or code revokes everything it issued. |
| Revoke | POST https://api.tradingpal.io/oauth/revoke with the token, or the user revokes the app on Keys. |
One scope, patterns: everything the account's key can do. Tokens go in the same Authorization: Bearer header as a key, on the MCP server and on the REST API alike; an expired or revoked token answers 401 with error="invalid_token" so the host refreshes or signs in again.
Protocol details
- Transport. Streamable HTTP, JSON-RPC 2.0 over
POST https://api.tradingpal.io/mcp. The server is stateless: no session id, andGETorDELETEreturn405. - Methods.
initialize,ping,tools/list,tools/call;prompts/listandresources/listreturn empty lists. - Auth. A Bearer token from the sign-in flow above, or an API key (
tp_live_…), in theAuthorizationheader on every request.https://api.tradingpal.io/mcp/demotakes neither. - Limits. Keyed tool calls count against the key's 60 a minute and 10,000 a day; keyless calls are limited per IP. A limited call returns a tool error naming the wait.
- Client name.
initializerecords the host'sclientInfo, so usage by host is visible on our side.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
The host lists the server but every tool errors with missing_api_key | The header is not being sent | Check the host's header configuration; for Codex, that TRADINGPAL_API_KEY is exported in the shell that runs it. |
invalid_api_key | Revoked or mistyped key | Create a new key on Keys. |
forbidden | The account is not on a plan with API access | Upgrade the account; the key stays valid. |
ticker_not_tracked | The ticker is not on the tracked list | The agent should call set_tracked_tickers with the full list plus the ticker, then retry. |
| The host reports a 405 | It opened a GET stream | The server is stateless Streamable HTTP; POST only. Most hosts fall back on their own. |