MCP Authentication
The TradeStaq MCP server requires authentication before you can access portfolio data, deploy bots, or execute trades. This page covers both audiences:
- End users running an MCP client like Claude Desktop, Cursor, or Claude Code — authenticate via in-chat tools or browser OAuth. OAuth sessions pick a scope at consent that caps what the agent can do.
- Third-party MCP client developers connecting to
mcp.tradestaq.comdirectly — use the standards-compliant OAuth 2.1 authorization server with Dynamic Client Registration.
Quick Reference
| Audience | Method | How |
|---|---|---|
| End user (npx client) | login tool | Email + password in chat |
| End user (any client) | authenticate tool | Browser OAuth, pick a scope, credentials never in chat |
| End user (scripts) | set_token tool | Paste existing JWT |
| Any user | check_auth tool | Verify auth, tier capabilities, wallet balance, and token scope |
| Third-party MCP client | OAuth 2.1 + DCR | Self-register, then Authorization Code + PKCE with scope |
| Any user | Connected Apps | Revoke active access tokens |
For End Users — In-Chat Authentication
The MCP server exposes four authentication tools. Your AI client calls them based on plain-English requests.
Method 1: Email and Password (login)
"Log me in to TradeStaq with email user@example.com"
The AI calls the login tool, which returns a JWT on success. The token is stored in the MCP server process for subsequent tool calls.
When to use: Local npx setups where you trust the AI client with credentials.
Method 2: Browser OAuth (authenticate)
"Authenticate me with TradeStaq"
The authenticate tool opens your default browser to a TradeStaq authorization page. After you log in and approve, the token is passed back to the MCP server automatically. Credentials never transit the MCP transport.
When to use: When you use SSO / social login, when you have 2FA enabled, or when you prefer not to type credentials in the AI chat.
Method 3: Manual Token (set_token)
"Set my TradeStaq token to eyJhbGciOiJI..."
You can generate a long-lived JWT from the dashboard and paste it in. Useful for CI pipelines or sharing a session across tools.
Checking Authentication Status (check_auth)
"Am I logged in to TradeStaq?"
The AI calls check_auth which returns your authentication state plus the context an agent needs to decide what it can safely do next. The response includes:
id,name,email,telegramLinked— basic user infotier— subscription tier name/slug plus acapabilitiesblock (allowLiveTrading,allowAIBuilder,allowNewsTrading,allowMcpServer)strategyLabBalanceUsd— current wallet balance for wallet-charging tools (e.g.generate_strategy)token— present only for MCP Bearer (OAuth) authentication. CarriesclientId,clientName,scope, andexpiresAt
Agents are expected to preflight check_auth before invoking gated tools so they can surface scope or balance issues to the user instead of hitting a 403 mid-flow. The response is cached per-token for 30 seconds, so frequent checks don't hit the database.
OAuth Scopes
Remote OAuth tokens carry a scope that caps what the token can do. Scopes are hierarchical — higher scopes imply lower ones.
| Scope | Can read | Can paper-trade | Can live-trade / charge wallet |
|---|---|---|---|
mcp:read | Yes | No | No |
mcp:paper | Yes | Yes | No |
mcp:live | Yes | Yes | Yes |
When a tool requires a higher scope than the token holds, the server returns a structured 403 insufficient_scope response with the required scope echoed back. The agent should relay this to the user and ask them to re-authorize with the right scope — it should not automatically call logout + authenticate without explicit user approval, since broader scopes expand what the agent can do on your account.
Session-cookie authentication (dashboard users) has no scope — dashboard sessions can do whatever the user's subscription tier allows.
Wallet-Charging Tools: acknowledgeCost
Tools that charge your Strategy Lab wallet (currently generate_strategy, $0.50 per experiment, up to 30 experiments per call) require the agent to pass acknowledgeCost: true in the request. Without it, the endpoint returns a cost-estimate envelope (no job queued) so the agent can show you the charge and get explicit approval before committing. Dashboard users are exempt — consent happens in the UI.
For Third-Party MCP Clients — OAuth 2.1 + Dynamic Client Registration
Third-party MCP clients (Claude.ai, ChatGPT, custom MCP hosts) that want to connect to mcp.tradestaq.com/mcp on behalf of their users should use the standards-compliant OAuth 2.1 authorization server. No contact with TradeStaq needed to get started — clients self-register.
Discovery
TradeStaq publishes standard metadata files under the production origin (https://www.tradestaq.com):
| Endpoint | Spec | Purpose |
|---|---|---|
/.well-known/oauth-authorization-server | RFC 8414 | Advertises issuer, endpoints, response_types, grant_types, PKCE support, token-endpoint auth methods |
/.well-known/oauth-protected-resource | RFC 9728 | Advertises the API resource (https://www.tradestaq.com/api) and its authorization server. Also carries mcp_resource for strict MCP 2025-06-18 clients |
/.well-known/mcp/server-card.json | SEP-1649 | Advertises both the hosted streamable-http endpoint and the stdio npm package |
See Discovery & .well-known endpoints for the full catalog.
Dynamic Client Registration (RFC 7591)
POST https://www.tradestaq.com/api/oauth/register
Content-Type: application/json
{
"client_name": "My MCP Client",
"redirect_uris": ["https://mcp-client.example.com/oauth/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code"],
"response_types": ["code"],
"scope": "mcp"
}
Response returns a client_id. Supports public (PKCE-only) and confidential clients. Register once per client, then reuse the client_id across all end-user authorizations.
Authorization Code Flow with PKCE
-
Redirect the user to:
https://www.tradestaq.com/api/oauth/authorize ?response_type=code &client_id=<client_id> &redirect_uri=<redirect_uri> &code_challenge=<code_challenge> &code_challenge_method=S256 &state=<random-nonce> &scope=mcpThe user logs in (if not already), lands on
/oauth/consent, and approves. PKCE is mandatory —plainis banned. -
User is redirected back to your
redirect_uriwith?code=<single-use-code>&state=<nonce>. Codes expire after 60 seconds and are single-use (atomic GETDEL). -
Exchange the code for a JWT:
POST https://www.tradestaq.com/api/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code=<code> &redirect_uri=<redirect_uri> &client_id=<client_id> &code_verifier=<code_verifier>Response:
{ "access_token": "eyJ...", "token_type": "Bearer", "expires_in": 3600, "scope": "mcp", "refresh_token": "tsr_..." }— a 60-minute access JWT plus a rotating 30-day refresh token. -
Send the token on MCP requests as
Authorization: Bearer <access_token>. -
Refresh before the access token expires (or on a
401) with the rotating refresh token — no browser re-consent:POST https://www.tradestaq.com/api/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=refresh_token &refresh_token=<refresh_token> &client_id=<client_id>The response returns a fresh
access_tokenand a newrefresh_token(rotation) — persist the new one and discard the old. Presenting an already-used refresh token is treated as theft and revokes the whole session (RFC 9700 reuse detection).
Errors follow RFC 6749 §5.2 (JSON bodies with error + error_description).
Loopback Redirect URIs (RFC 8252 §7.3)
For native or CLI MCP clients that listen on http://127.0.0.1:<random_port>/callback, the authorization server accepts any port on the loopback interface at authorization time, not just the exact port registered. This lets a desktop MCP client register once with a placeholder port and bind to a random available port per session.
Confidential Clients
Clients that can keep a secret (server-side MCP hosts) can request token_endpoint_auth_method: "client_secret_basic" or "client_secret_post" at registration. The server issues a client_secret in the registration response. Confidential flows still require PKCE.
Managing Access (Revoke)
Visit Dashboard → Settings → Connected Apps to see every MCP client that has an active token for your account. Each row shows:
- Client name (from the
client_nameat registration) - Client ID
- Scope
- Issued time, expiry time, last used time
Click Revoke to immediately invalidate the token. Revocation is enforced on the hot path (Redis denylist with TTL matching the JWT's remaining lifetime) — subsequent API calls with that token fail with 401. The token's Mongo record is stamped with revokedAt for audit.
Revoking a token ends its entire session — the access token, its rotating refresh-token chain, and any access tokens issued under the same authorization are invalidated together. Other independent sessions (separate authorizations) are unaffected; revoke each to sign out everywhere.
How Tokens Are Stored
| Detail | Value |
|---|---|
| Format | JWT (JSON Web Token) |
| Storage (npx) | In-memory during the MCP server process |
| Storage (remote) | Stateless — the client re-sends its bearer per request; nothing is held server-side |
| Storage (third-party client) | Your client's responsibility — treat like any OAuth access token |
| Expiry | Access token 60 min; rotating refresh token 30 days (sliding) — silent renewal, no periodic re-consent |
| Scope | mcp:read, mcp:paper, or mcp:live — whichever you granted at the OAuth consent screen (or the legacy mcp for pre-0.3.13.0 tokens, treated server-side as mcp:live) |
| Revocable | Yes, at /dashboard/settings/connected-apps (hot-path Redis denylist enforcement) |
The npm MCP server does not persist tokens to disk. Close the client and you re-authenticate on next use.
Authentication Flows
In-chat flow (login / authenticate / set_token):
┌──────────┐ login/authenticate ┌──────────────┐ JWT ┌──────────┐
│ AI Client│────────────────────────▶│ MCP Server │────────▶│ TradeStaq│
│ │◀────────────────────────│ │◀────────│ API │
└──────────┘ token stored in └──────────────┘ verify └──────────┘
MCP process memory
Third-party OAuth 2.1 + DCR flow:
┌────────────────┐ 1. POST /api/oauth/register ┌──────────────┐
│ Third-party │────────────────────────────────────▶│ TradeStaq │
│ MCP Client │◀──── client_id ────────────────────│ Auth Server │
│ │ │ │
│ │ 2. redirect user → /authorize │ │
│ │────────────────────────────────────▶│ │
│ │ │ │
│ │ 3. user consents, get code │ │
│ │◀───────────────────────────────────│ │
│ │ │ │
│ │ 4. POST /api/oauth/token (PKCE) │ │
│ │────────────────────────────────────▶│ │
│ │◀─ access JWT (60m) + refresh (30d) ─│ │
│ │ │ │
│ │ 5. Bearer JWT on MCP requests │ ┌──────────┐│
│ │────────────────────────────────────▶│ │TradeStaq ││
│ │ │ │ API ││
│ │◀───────────────────────────────────│ └──────────┘│
└────────────────┘ └──────────────┘
Security Considerations
- Email/password login sends credentials through the MCP transport. On local npx, they stay on your machine. On remote, TLS protects them. Prefer OAuth when your 2FA or SSO requires it.
- Browser OAuth (
authenticatetool or standards-compliant flow) never exposes your password to the AI client. - Grant the narrowest scope that works. Research/summary agents only need
mcp:read. Paper-trading agents should ask formcp:paper. Reservemcp:livefor agents you trust with real money. - PKCE is mandatory for the OAuth 2.1 server. Clients cannot opt out.
code_challenge_method=plainis banned per OAuth 2.1 §7.5. - Short authorization code lifetime. Codes expire after 60 seconds and are single-use (atomic GETDEL). A stolen code is useless after one exchange.
- Tokens are revocable. A compromised token can be invalidated immediately from the dashboard. Revocation hits the hot path — no lag.
- Refresh tokens with rotation. Access tokens are short-lived (60 min); a rotating 30-day refresh token renews them silently — no periodic browser re-consent. Each refresh returns a new refresh token and invalidates the old one; presenting a used token is treated as theft and revokes the whole session (RFC 9700 reuse detection).
- Tokens from the deprecated
/api/oauth/mcp/tokenendpoint are rejected as of v0.3.13.0 because they were minted without a JWT identifier and silently bypassed scope enforcement. Clients on@the-staq/tradestaq-mcpv0.2.0+ already use the RFC-compliant/api/oauth/tokenflow; older configs must re-authenticate.
Next Steps
- Discovery & .well-known endpoints — What a programmatic MCP client finds at first contact
- Setup Guide — Configure Claude Desktop, Cursor, or Claude Code
- Tools Reference — All 31 tools
- HTTP Transport — Remote server and self-hosting
- Troubleshooting — Auth error solutions