stonex-mcp
Typed TypeScript client for the StoneX Client (torchapi) REST API, plus an MCP server that exposes those endpoints as tools.
Auth is not automated (no Okta/MFA in this project). You log into StoneX Client in a browser, export a cookies.txt file, and pass the path to that file on the CLI.
Requirements
- Bun 1.1+ (for local development /
preparebuild) - Node.js 18+ (to run the published
binbundle)
Install
bun install
Auth: cookies.txt
- Install a browser extension that exports Netscape
cookies.txt(e.g. Get cookies.txt LOCALLY). - Log into https://client.stonex.com/client/.
- Export cookies for
client.stonex.comto a file (e.g.client.stonex.com_cookies.txt). - Pass that path to the server:
stonex-mcp --cookies /path/to/client.stonex.com_cookies.txt
The server reads session cookies from that file and calls GET https://client.stonex.com/client/token only when it needs a Bearer JWT.
Token cache
Derived access tokens are cached on disk so repeated MCP tool calls do not mint a new token every time:
| OS | Path |
|---|---|
| Windows | %LOCALAPPDATA%\stonex-mcp\access-token.json |
| macOS | ~/Library/Caches/stonex-mcp/access-token.json |
| Linux | ${XDG_CACHE_HOME:-~/.cache}/stonex-mcp/access-token.json |
When the cached JWT is missing or near expiry, a new token is requested using the cookies file and written back to the cache. If refresh starts failing with 401, re-export cookies after logging into StoneX Client again.
Treat the cookies file and cached token like passwords. Do not commit them.
Run the MCP server
bun start -- --cookies /path/to/client.stonex.com_cookies.txt
# or after build:
node dist/stonex-mcp.js --cookies /path/to/client.stonex.com_cookies.txt
Cursor / Claude Desktop config
{
"mcpServers": {
"stonex": {
"command": "npx",
"args": [
"-y",
"stonex-mcp",
"--cookies",
"C:/Users/YOU/Downloads/client.stonex.com_cookies.txt"
]
}
}
}
npx runs the built Node bundle (dist/stonex-mcp.js, produced by bun run build / prepare). Local equivalent: "command": "bun", "args": ["run", "/path/to/stonex-mcp/src/cli.ts", "--cookies", "/path/to/cookies.txt"].
Typed client
import { StoneXClient } from "./src/client/index.ts";
import { sessionCookieFromCookiesTxtFile } from "./src/auth/cookiesTxt.ts";
import { resolveAuth } from "./src/auth/resolveAuth.ts";
import { writeTokenCache } from "./src/auth/tokenCache.ts";
const { accessToken, sessionCookie } = await resolveAuth(
"/path/to/client.stonex.com_cookies.txt",
);
const client = new StoneXClient({
accessToken,
sessionCookie,
onAccessToken: (token) => writeTokenCache(token),
});
const accounts = await client.getAccounts();
const summary = await client.getAccountSummary({
accountNumber: accounts[0]!.acctNo,
});
Or build a cookie header yourself with sessionCookieFromCookiesTxtFile(...).
Endpoints mirror the StoneX Client SPA (https://vulcan.stonex.com/torchapi): accounts, balances, summary, positions, activity, performance, projected income, documents, and related user/account metadata.
Security note
Local capture files (stonex-fetch.js, stonex-har.json, stonex-urls.txt) and fixtures/ can contain live secrets and account data. They are gitignored. Rotate credentials if those files were shared.