Authentication & Access
Authentication & Access
Beta, pre-release. The NinjaTrader MCP server and its trading skills are in beta and aren’t yet generally available. The beta runs on two environments. Demo trades simulated money, and Live trades real money. Start on Demo. Server hostnames, the tool set, the skills, and the onboarding flow may change before launch.
The NinjaTrader MCP server authorizes clients with OAuth 2.1. Your AI client never handles your password. You sign in to NinjaTrader in your browser and approve the connection, and the client receives a token it sends on every request. This is the same delegated-authentication model the Trade API uses for OAuth, adapted to the MCP discovery flow so compatible clients can connect with no manual configuration.
How authorization works
When your client first connects to the MCP server URL, it runs the standard MCP OAuth flow:
- Discovery. The client requests the server’s protected-resource metadata, defined by RFC 9728, and learns which NinjaTrader authorization server to use and which scope to request.
- Authorize. The client opens the NinjaTrader sign-in page in your browser. You log in and approve the connection.
- Token. NinjaTrader returns an access token bound to the MCP server. The client stores it and sends it as a
Bearertoken on every MCP request. - Session. The server establishes a session for the connection and your agent can begin calling tools.
You don’t configure any of these endpoints yourself. A compliant MCP client handles discovery and the token exchange automatically once you provide the server URL. You must complete authorization in a desktop browser.
The MCP server serves discovery at /.well-known/oauth-protected-resource and at the
path-scoped /.well-known/oauth-protected-resource/mcp. The connection scope is
mcp:connect. The server enforces fine-grained authorization per tool against your
account’s permissions, described below.
Permissions and scopes
Connecting establishes that the client is you. What the connection may then do is what you approve on the consent screen: the Actions the agent can take and the Read access it can use. This is the same permission model used across the platform. Each tool declares the access it needs, and the server checks it on every call:
Some tools need two permissions: close_position needs both Trade and View Positions, and my_portfolio needs both View Positions and View Orders. Each manage permission includes its matching view access, so Trade satisfies View Orders, Manage Alerts satisfies View Alerts, and Manage Risk Settings satisfies View Risk Settings.
If your account lacks the access a tool requires, the server denies that tool’s call and hides the tool from your agent’s tool list. The rest of the connection keeps working. A small number of tools, such as describe and the service-status resource, require no special access.
Risk limits
The consent screen’s third group, Risk limits, doesn’t grant access. It caps how much trading the access you granted can do. All four limits are optional and off by default. The server stores them with this connection and checks them on every opening order the agent sends. Closing or flattening a position is always allowed. Limits count in whole contracts, and the server measures them against your entire account, so positions and working orders you create outside the agent consume the same budget.
Per-product and per-contract limits double as an allowlist. As soon as you list any product or contract, the connection can open positions only in what you listed. The server rejects orders for anything else, even when you set no numeric cap.
When an order would exceed a limit, estimate_order reports it as not feasible, and place_order fails with an error that names the limit and the current value, so your agent sees exactly which cap it hit. Risk limits stack with your account-level risk settings: every check must pass, the most restrictive limit wins, and a connection limit can never loosen anything set on the account.
Your agent can’t read these limits ahead of time. The risk_settings tool returns account-level risk settings only, and no tool returns the connection’s risk limits. The rejection message is how the agent learns them. To review or change the configured values, open your authorized-apps settings.
Token lifetime and sessions
Authorization produces two tokens:
- An access token, valid for about 80 minutes, that the client sends on every request.
- A refresh token, valid for about 26 hours, that the client exchanges for a new access token before the old one expires.
A compliant MCP client refreshes the access token in the background, so an agent in active use stays connected with no action from you. Short-lived access tokens are part of the OAuth 2.1 model the MCP specification builds on.
Two events end a connection, and they recover differently:
- The access token expires. This is routine. A compliant client refreshes it and your agent keeps working, and you don’t sign in again.
- The refresh token expires, or you revoke access. The client can no longer refresh, so reconnect through your client to sign in again. The refresh window renews on every refresh, so a client that refreshes at least once a day never reaches it.
The server also holds a session for each connection and ends it after about an hour of inactivity. An idle session and an expired access token both surface the same way. Calls stop succeeding, and reconnecting resolves either one. See Troubleshooting.
A compliant client refreshes for you. If you build a client directly against the HTTP API, you refresh the access token yourself. See Refreshing the access token.
Refreshing the access token
If you build a client directly against the HTTP API instead of using an MCP SDK, implement the OAuth 2.1 refresh flow yourself. Discover the token endpoint from the authorization server metadata, then exchange the refresh token before the access token expires:
Three rules separate a working refresh from a token the server rejects:
- Send the
resourceparameter, set to the MCP server URL you connected to. The MCP specification requires it on every token request, including refresh. Omit it and the server returns a token with no audience, which then fails your next MCP call with401 invalid_token. - Store the rotated refresh token. Each refresh returns a new refresh token and invalidates the previous one. Persist the new value.
- Keep your saved token when a refresh fails. A failed refresh returns an
errorbody, not a token. Overwriting your saved token with it loses the refresh token and forces you to sign in again.
Refresh proactively, before the expires_in window from the token response elapses, rather than waiting for a 401.
Changing or revoking access
You stay in control after you approve the connection. From your authorized-apps settings you can:
- Revoke the connection. Every request fails immediately, including token refresh.
- Edit risk limits. Changes apply on the agent’s next tool call, with no re-approval needed.
- Edit permissions. Changes apply when the client next refreshes its access token.
Security notes
- Your agent authenticates as you. Treat a connected agent like a signed-in session: only connect clients you trust, and disconnect the server when you’re done.
- Start on Demo. Authorize the Demo server first so any mistakes happen against simulated money.
- Keep risk limits in place. Account-level risk settings, such as daily loss limits, auto-liquidation, and trailing drawdown, apply to orders placed through the MCP server just as they do elsewhere.
- Cap the connection. Optional risk limits on the consent screen bound how much this agent can trade, independent of your account-level settings.
- Live and Demo are separate. A token for one environment can’t access the other. See Environments.