# Task: connect my AI agent or app to Papertrade over MCP

Papertrade (https://papertrade.world) is a paper-trading simulator for 45 stock markets with real broker fees, live prices and replays of past trading days. It's built for testing AI trading agents: everything uses virtual money and nothing reaches a real broker. It exposes a remote MCP (Model Context Protocol) server so an agent can create simulators, look up stocks, trade and read its own results.

Read this whole brief first. Then look at my codebase, connect it to the Papertrade MCP server in the framework and language it already uses, and build the feature I ask for (for example: an agent that day-trades a simulator every morning, or a chat feature that can place paper trades). If I haven't said what to build, propose a plan and ask before writing a lot of code.

## Server
- URL: https://papertrade.world/api/mcp
- Transport: Streamable HTTP (remote MCP). No stdio, no local install.
- Auth, two options:
  1. OAuth 2.1 sign-in (for apps where a person connects their own account): the server supports discovery (protected-resource and authorization-server metadata), dynamic client registration and PKCE. Most MCP clients handle this automatically.
  2. API key (for servers, scripts and background agents): send `Authorization: Bearer <key>` on every request. Keys start with `pt_` and are created at https://papertrade.world/mcp#keys. Read it from the `PAPERTRADE_API_KEY` environment variable; never hard-code, log or commit it.
- Every tool acts as the signed-in user, on their simulators only. Each call is logged in their Papertrade activity, tagged with the app or key name.

## Connecting from code
Use the official MCP SDK or your LLM provider's built-in MCP support; check the current docs for exact names, since these APIs move quickly.
- TypeScript: `@modelcontextprotocol/sdk` with a Streamable HTTP client transport pointed at the URL, passing the Authorization header in the request options.
- Python: the `mcp` package's Streamable HTTP client, with the same header.
- OpenAI Responses API: an MCP tool entry with the server URL, a label like `papertrade`, and the Authorization header.
- Anthropic Messages API: an MCP server entry with the URL and the key as its authorization token.
- Agent frameworks (OpenAI Agents SDK, Claude Agent SDK, LangChain, Vercel AI SDK, Mastra…): add it as a remote/Streamable HTTP MCP server with that header.

## How an agent should use the tools
- Start with `market_status` (which exchanges are open) and `list_simulators`; create one with `create_simulator` if needed.
- Find exact symbols with `search_instruments` (format `PREFIX:TICKER`, e.g. `US:AAPL`, `NSE:INFY`).
- Live simulators accept orders only while their exchange is open; `get_simulator` shows `ordersOpen` and the reason when not. Historic simulators replay a past day: drive them with `control_replay`.
- `place_order` can return `status: "REJECTED"` with a `message` (closed market, not enough margin, after the broker's square-off). Read it and adapt; never assume an order filled.
- Protect entries with `stopLoss` / `target` (and optionally `trailingStop`); close with `exit_positions`.
- Judge results with `get_report`: net P&L after fees, win rate, profit factor and day-by-day results (profitable days, streaks).
- Money is in the simulator's currency; times are epoch milliseconds.

## Tools (14)

### `market_status`

Data provider per market, whether the Kite session is connected, and whether each exchange (IN = NSE, US = NYSE) is in session right now. Live simulators accept orders only while their exchange is open — not on weekends, exchange holidays or outside regular hours.

No parameters.

### `list_simulators`

List all trading simulators with mode, replay clock, equity and P&L.

No parameters.

### `list_brokers`

Brokers whose fees can be simulated, per market: commission rule, whether statutory/regulatory charges apply (India: STT, exchange, SEBI, stamp, GST; US: SEC fee, FINRA TAF), max intraday leverage, and auto square-off time. Every market lists its major local brokers and apps; their fees and the market's transaction taxes (e.g. UK stamp duty, Hong Kong stamp duty) are applied on every fill.

Parameters:
- `market` (string, one of 45 values, optional): Only brokers for this market

### `create_simulator`

Create a paper-trading simulator for one market (IN India, US United States, CA Canada, BR Brazil, MX Mexico, AR Argentina, CL Chile, GB United Kingdom, IE Ireland, DE Germany, FR France, NL Netherlands, BE Belgium, PT Portugal, IT Italy, ES Spain, CH Switzerland, AT Austria, SE Sweden, NO Norway, DK Denmark, FI Finland, PL Poland, CZ Czechia, HU Hungary, GR Greece, TR Türkiye, EE Estonia, IL Israel, SA Saudi Arabia, AE United Arab Emirates, QA Qatar, ZA South Africa, JP Japan, HK Hong Kong, CN China, TW Taiwan, KR South Korea, SG Singapore, MY Malaysia, TH Thailand, ID Indonesia, VN Vietnam, AU Australia, NZ New Zealand), each with its own exchange hours, timezone and currency — e.g. IN (NSE/BSE, ₹, 09:15–15:30 IST), US (NYSE/NASDAQ, $, 09:30–16:00 ET), GB (LSE, £), JP (Tokyo, ¥). mode 'live' trades on real-time prices and accepts orders only while the exchange is in session (not on weekends, exchange holidays or outside regular hours — see market_status); mode 'historic' replays a past trading day (needs date, starts paused at the open). Every fill is charged the chosen broker's intraday fees plus statutory charges; positions use the chosen intraday leverage (margin = order value ÷ leverage). Indian brokers auto square off open positions at their cut-off (e.g. Zerodha 3:20 PM) for a fee and refuse new orders after it; US brokers don't.

Parameters:
- `name` (string, required)
- `mode` ("live" | "historic", required)
- `market` (string, one of 45 values, optional): Market id (default "IN"), e.g. "US", "GB", "DE", "JP", "HK", "AU"
- `date` (string, optional): Historic only: past trading day, YYYY-MM-DD
- `capital` (number, optional): Starting virtual cash in the market's currency (default about 100,000 US dollars' worth, e.g. ₹10,00,000 India, $100,000 US, £100,000 UK)
- `broker` (string, one of 173 values, optional): Broker fees to simulate (default: the market's first listed broker, e.g. "zerodha" in India, "robinhood" in the US, "trading212-gb" in the UK; "none" = no fees). Must belong to the market; see list_brokers.
- `leverage` (integer, optional): Intraday leverage (max 5× India, 1× China, 2× elsewhere; default: the maximum)

### `get_simulator`

Full state of a simulator: clock, funds (equity, P&L, available margin), watchlist prices, positions and recent orders.

Parameters:
- `simulatorId` (string, required): Simulator id, e.g. "sim_1a2b3c4d5e" (from list_simulators)

### `get_report`

Results report for a simulator (use at the end of a session): net/gross P&L, charges breakdown, peak margin and leverage used, round-trip trades with win rate and profit factor, day-by-day results (daily: P&L per trading day, green vs red days, best/worst day, streaks; useful to judge an agent over weeks), per-stock P&L, who placed orders, equity curve and plain-language insights.

Parameters:
- `simulatorId` (string, required): Simulator id, e.g. "sim_1a2b3c4d5e" (from list_simulators)

### `delete_simulator`

Permanently delete a simulator and its history.

Parameters:
- `simulatorId` (string, required): Simulator id, e.g. "sim_1a2b3c4d5e" (from list_simulators)

### `search_instruments`

Search stocks by symbol or company name in one market (e.g. IN "NSE:INFY", US "US:AAPL", GB "LSE:HSBA", JP "TSE:7203", HK "HKEX:0700"). Returns exact symbols to use in other tools; use the simulator's market.

Parameters:
- `query` (string, required)
- `market` (string, one of 45 values, optional): Market to search (default "IN")

### `add_to_watchlist`

Track one or more instruments in a simulator so their prices update on the dashboard.

Parameters:
- `simulatorId` (string, required): Simulator id, e.g. "sim_1a2b3c4d5e" (from list_simulators)
- `symbols` (string[], required)

### `remove_from_watchlist`

Stop tracking an instrument (does not close positions).

Parameters:
- `simulatorId` (string, required): Simulator id, e.g. "sim_1a2b3c4d5e" (from list_simulators)
- `symbol` (string, required): Instrument as "PREFIX:SYMBOL" ("NSE:INFY", "BSE:TCS", "US:AAPL"); a bare symbol uses the simulator's market

### `place_order`

Place an intraday order with virtual money. Types: MARKET fills now (replay time for historic); LIMIT rests until price reaches limitPrice; SL-M (stop-market) waits for triggerPrice then fills at market; SL (stop-limit) waits for triggerPrice then rests at limitPrice. A SELL stop's trigger must be below the current price (it triggers on the way down), a BUY stop's above. Protect a MARKET/LIMIT entry by attaching stopLoss and/or target prices: once the entry fills they become exit orders that cancel each other when one fills (and are cancelled if you close the position yourself). trailingStop {type: points|percent, value} makes the stop follow the best price; on an SL-M it trails the trigger. Selling without a position opens a short. Margin = order value ÷ leverage. Rejected after the broker's auto square-off time (see get_simulator.squareOff / ordersOpen).

Parameters:
- `simulatorId` (string, required): Simulator id, e.g. "sim_1a2b3c4d5e" (from list_simulators)
- `symbol` (string, required): Instrument as "PREFIX:SYMBOL" ("NSE:INFY", "BSE:TCS", "US:AAPL"); a bare symbol uses the simulator's market
- `side` ("BUY" | "SELL", required)
- `qty` (integer, required)
- `type` ("MARKET" | "LIMIT" | "SL" | "SL-M", optional)
- `limitPrice` (number, optional): LIMIT and SL orders
- `triggerPrice` (number, optional): SL and SL-M orders (optional for SL-M with trailingStop)
- `stopLoss` (number, optional): MARKET/LIMIT entries: exit price if it goes against you
- `target` (number, optional): MARKET/LIMIT entries: exit price to take profit
- `trailingStop` ({ type, value }, optional): Trail the stop loss (entries) or the trigger (SL-M) by points or percent of the best price

### `cancel_order`

Cancel an OPEN order: limit, stop-loss (SL / SL-M) or a bracket's stop-loss / target exit.

Parameters:
- `simulatorId` (string, required): Simulator id, e.g. "sim_1a2b3c4d5e" (from list_simulators)
- `orderId` (string, required)

### `exit_positions`

Square off a position at market, or all open positions if symbol is omitted.

Parameters:
- `simulatorId` (string, required): Simulator id, e.g. "sim_1a2b3c4d5e" (from list_simulators)
- `symbol` (string, optional): Instrument as "PREFIX:SYMBOL" ("NSE:INFY", "BSE:TCS", "US:AAPL"); a bare symbol uses the simulator's market

### `control_replay`

Historic simulators only: play, pause, set speed (1/2/5/10/30/60/120x) or jump the replay clock forward by N minutes.

Parameters:
- `simulatorId` (string, required): Simulator id, e.g. "sim_1a2b3c4d5e" (from list_simulators)
- `action` ("play" | "pause" | "speed" | "advance", required)
- `speed` (number, optional): For action=speed
- `minutes` (integer, optional): For action=advance

## Notes
- No MCP in your stack? The same features are available as a plain REST API with the same key: https://papertrade.world/docs/api (an AI brief for it is at https://papertrade.world/docs/api/prompt).
- Human-readable setup guides for Claude, ChatGPT, Cursor and others: https://papertrade.world/docs