trading-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@trading-mcpBuy 15 shares of Nvidia."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Trading MCP Server (JWT-authenticated)
A small but production-shaped Model Context Protocol server that Claude can connect to and drive in natural language. It exposes a five-tool paper-trading domain, and every tool call is gated behind JWT authentication that is verified on each invocation — not once at connection time.
The trading domain was chosen deliberately: because holdings, cash, and orders are strictly per-user, the auth layer is doing real work on every call, which makes it a more meaningful demonstration of authentication than a shared or read-only dataset would be.
Tools
Tool | Auth required | Purpose |
| no | Validate credentials, return a signed JWT. |
| yes | Current simulated price + day change for a symbol. |
| yes | Execute a simulated market buy/sell against the user's own portfolio. |
| yes | Cash, positions, and live unrealized P&L. |
| yes | The user's past executed orders. |
Market prices are simulated from a seeded local table — no external API key, fully reproducible. See Assumptions & trade-offs.
Demo accounts
Username | Password |
|
|
|
|
Each user has their own cash, holdings, and history — useful for confirming that one user's token can never see another's data.
Related MCP server: Alpaca MCP Server
Setup
Requires Python 3.10+. A recent-but-not-bleeding-edge version (3.11–3.13) is recommended; see the note under Connecting to Claude Desktop if you are on 3.14.
git clone <your-repo-url>
cd trading-mcp
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install --upgrade pip
pip install -r requirements.txtSet the signing secret
The JWT signing secret is read from the environment and is never committed. The server refuses to start without it.
cp .env.example .env
# then edit .env, or generate a strong secret in one line:
echo "JWT_SECRET=$(python -c 'import secrets;print(secrets.token_hex(32))')" > .envVerify it works (before touching Claude)
Two independent checks:
# 1. Unit tests: auth core + tool behavior
python -m pytest -q
# 2. End-to-end: launches the server over the real stdio MCP protocol,
# lists tools, and exercises login + a protected call.
export JWT_SECRET="$(python -c 'import secrets;print(secrets.token_hex(32))')"
python smoke_test.pysmoke_test.py printing ALL SMOKE CHECKS PASSED means the server is wired
correctly and will connect to any MCP client.
Connecting to Claude Desktop
Find the absolute path to your virtualenv's Python and to
server.py:echo "$(pwd)/.venv/bin/python" echo "$(pwd)/server.py"In Claude Desktop: Settings → Developer → Edit Config, and add:
{ "mcpServers": { "trading-mcp": { "command": "/ABSOLUTE/PATH/TO/trading-mcp/.venv/bin/python", "args": ["/ABSOLUTE/PATH/TO/trading-mcp/server.py"], "env": { "JWT_SECRET": "paste-a-long-random-secret-here" } } } }Fully quit Claude Desktop (Cmd+Q / quit, not just close the window) and reopen it. The server should show as running under Settings → Developer.
Important: use the venv's Python by absolute path
command must point at the virtualenv's Python (.venv/bin/python), not a
bare python / python3. The client resolves a bare command against your system
PATH and pins the result — on a machine whose default is a Python without the
mcp package installed, the server starts and immediately exits with
ModuleNotFoundError: No module named 'mcp'. An absolute venv path has nothing
to resolve, so it is used as-is.
Python 3.14 note: some dependencies may not yet ship prebuilt wheels for 3.14, so
pip installcan fail while building them. If so, create the venv withpython3.12 -m venv .venv(or 3.13) and reinstall — everything else is identical.
Using it
Because the token is passed as a normal tool argument, you drive everything in plain English and Claude handles the JSON:
"Log into my trading account, username demo, password demo123." →
login"What's my portfolio?" →
get_portfolio"What's Apple trading at?" →
get_quote"Buy 15 shares of Nvidia." →
place_order"Show my order history." →
get_order_history
To see authentication reject an unauthenticated call, start a fresh chat and
ask for your portfolio before logging in — the tool returns a missing_token
error and never runs its logic.
Authentication design
How the token flows
login verifies credentials and returns a signed JWT. Every other tool takes
that token as a required parameter and verifies it as its first action. If
verification fails, the tool returns a structured error and never touches the
data layer.
Why a per-call token parameter rather than a session or a transport auth header:
It makes "verify on every call" literal and auditable. The security boundary is one line at the top of each tool (
_authenticate(token)); there is no connection-level trust to reason about.stdio has no per-request headers. Unlike HTTP, the stdio transport can't carry an
Authorizationheader per call, so the token rides in the tool arguments.It's stateless and portable. No server-side session store to manage or leak, and the exact same server works unchanged from any MCP client and would work over an HTTP transport too.
What "verify" means here
Verification uses jwt.decode(token, SECRET, algorithms=["HS256"]), which checks
the signature and the exp (expiry) claim — it does not merely decode the
payload. Each failure mode returns a distinct, structured error:
Situation | Error code |
No token supplied |
|
Not a readable JWT |
|
Signature doesn't match our secret (incl. forged tokens) |
|
Past its expiry |
|
Valid but missing |
|
Other security properties
Secret management.
JWT_SECRETcomes from the environment (.envlocally, which is git-ignored). The server raises on startup if it is unset.Per-user isolation. The username is read from the verified token's
subclaim, never from a caller-supplied argument. Every data-layer query is scoped by that username, so a valid token fordemocan only ever act ondemo's data.Password storage. Passwords are bcrypt-hashed; plaintext is never stored.
No user enumeration.
loginreturns the same error for a wrong password and a non-existent user.
Layout
auth.py JWT sign/verify + bcrypt password hashing (the entire security surface)
db.py SQLite schema, seed data, and queries (knows nothing about auth or MCP)
server.py MCP tool definitions; the only place auth + data meetauth.py is intentionally domain-agnostic — it contains no trading logic at all.
Testing
python -m pytest -qtests/test_auth.py— the JWT core: password hashing, valid tokens, and every rejection path (missing, malformed, tampered, forged-with-wrong-secret, expired).tests/test_tools.py— login, auth-gating on protected tools, successful authenticated trades, and graceful handling of bad input / domain violations.
Assumptions & trade-offs
Reasonable scope decisions for a take-home; called out for transparency.
Simulated market data. Prices come from a seeded SQLite table (with a small per-symbol day change), not a live feed. This keeps the project reproducible and key-free. A real feed could be added behind an env flag without changing any tool or auth code.
stdio transport. Chosen per the brief (HTTP/SSE is a bonus). With stdio, each user runs their own local instance, so the SQLite store is per-machine. A multi-user, internet-facing deployment would use the HTTP transport plus a shared database.
No token revocation / refresh. Tokens are valid until they expire (default 60 min). Revocation lists and refresh tokens were out of scope.
Market orders only, filled at the current price. No limit orders, slippage, or realized-P&L tracking; unrealized P&L is computed live in
get_portfolio.
With more time
Remote HTTP transport + OAuth for use as a shared connector (incl. claude.ai
Custom Connectors), token refresh/revocation, rate limiting on login, and
limit-order support.
Demo
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Trade Robinhood through natural language in Claude Code.
Paper trading for AI: live quotes, indicators, and virtual trades on stocks, crypto, and forex.
Automate trading on your own Alpaca account - build, backtest and run strategies via your AI.
Connect your AI to a funded trading account. Read & trade a simulated funded challenge.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables AI assistants like Claude to interact with Paper's trading platform API using natural language, allowing users to manage accounts, portfolios, trades, and access market data through conversational requests.232223MIT
- AlicenseNot gradedqualityDmaintenanceEnables natural language trading operations through Alpaca's Trading API, supporting stocks, options, crypto, portfolio management, and real-time market data access through AI assistants like Claude.MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants like Claude to run backtests, fetch market data, list strategies, and analyze trading algorithms via natural language.1,068GPL 3.0
- FlicenseNot gradedqualityCmaintenanceEnables conversational control of a Korean stock paper trading simulator. Users can view positions, adjust strategy parameters, and run backtests through natural language in Claude Desktop.-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Tejas-gaikwad/mcp_trade'
If you have feedback or need assistance with the MCP directory API, please join our Discord server