PitBridge
Join the waitlist

The Model Context Protocol (MCP) is an open standard for connecting AI agents to tools and data. Instead of wiring an agent to one bespoke API, you run an MCP server that advertises a set of tools. The agent reads that list when it connects and calls any tool by name, with typed arguments and typed results.

A trading MCP server applies that idea to a trading platform. It exposes actions like listing accounts, reading positions and placing an order as MCP tools. An agent connected to it can read current state and propose the next order in plain tool calls. The server is not a strategy and not a bot. It is the typed surface an agent talks to, plus the transport that carries the calls.

MCP in one paragraph: the protocol under the tools

MCP is an open standard built on JSON-RPC 2.0, introduced by Anthropic in late 2024 and now spoken by a range of agent clients, Claude among them. A server can expose three kinds of primitive: tools (executable actions), resources (read-only data an agent can load) and prompts (reusable templates). A trading server in v0 uses the tools primitive only. The moving parts are a host application, such as Claude Desktop, that runs an MCP client, and that client connects to your server. Discovery is a fixed handshake: on connect the client calls tools/list to learn what the server can do, then invokes any tool with tools/call. That standardization is the whole point. The same protocol and the same two verbs reach a trading account, a file store or a database without writing new glue for each one.

The tool surface

The useful mental model is a menu of typed functions. A trading MCP server splits its tools into reads and writes. Reads return state and never change anything: accounts, positions, orders, account state, guardrail status. Writes request a change: place an order, cancel one, close a position, flatten the account. Each tool declares its argument schema, so the agent knows that place_order needs an account, an instrument, a side and a quantity, and that the quantity is an integer.

reads5

  • get_accounts
  • get_positions
  • get_orders
  • get_account_state
  • get_guardrail_status

Return state. They never change anything.

writes4

  • place_order
  • cancel_order
  • close_position
  • flatten_account

Request a change. Every place_order still passes the guardrail engine.

The nine tools an MCP client sees at connect time. There is no tool to lift the kill switch, arm live, or change a guardrail: those are operator-only on the CLI.

The write tools declare a fuller schema than a quantity alone. place_order accepts an order_type (MARKET by default, plus LIMIT and STOPMARKET), an optional limit_px and stop_px for those types, and a tif (DAY by default, or GTC). The agent generates all of it from a language model, so the schema is the first line of defense against a malformed call.

place_order schema
# place_order arguments (typed, validated before the guardrails run)
account     string   sim
instrument  string   MES 09-26
side        enum     BUY or SELL
qty         integer  2
order_type  enum     MARKET (default), LIMIT, STOPMARKET
limit_px    float    optional, required for LIMIT
stop_px     float    optional, required for STOPMARKET
tif         enum     DAY (default) or GTC

# a zero or negative qty is rejected before any guardrail runs
place_order account=sim instrument="MES 09-26" side=BUY qty=0  -> SCHEMA_INVALID

The place_order argument schema. Field names match the daemon exactly.

A qty that is not a positive integer, or a side that is not BUY or SELL, is rejected with SCHEMA_INVALID before any risk logic runs. Schema validation is cheap and deterministic, and it catches a whole class of mistakes that prompt instructions cannot reliably prevent.

Two transports: stdio and streamable HTTP

MCP servers speak one of two transports, and both carry JSON-RPC 2.0. Over stdio the server runs as a local subprocess of the client and they exchange messages on standard input and output. This is what a desktop client like Claude Desktop uses: it launches the server, talks to it directly, and nothing touches the network. Over streamable HTTP (spec revision 2025-03-26, which superseded the older HTTP with server-sent-events transport) the server listens on a local port and a custom agent or script connects to that single endpoint, streaming responses over optional server-sent events. This suits your own code, a local automation, or a client on the same machine that prefers HTTP.

Registering the stdio server with a client is a small config block. For Claude Desktop it goes in claude_desktop_config.json:

claude_desktop_config.json
{
"mcpServers": {
  "pitbridge": {
    "command": "uv",
    "args": ["run", "--directory", "/ABSOLUTE/PATH/TO/pitbridge/daemon",
             "pitbridge", "mcp",
             "--config", "/ABSOLUTE/PATH/TO/config.toml"],
    "env": { "PITBRIDGE_HOME": "/ABSOLUTE/PATH/TO/pitbridge-test" }
  }
}
}

The Claude Desktop config block. Claude Code registers the same server from a shell.

claude mcp add
claude mcp add pitbridge -- \
uv run --directory /ABSOLUTE/PATH/TO/pitbridge/daemon \
pitbridge mcp --config /ABSOLUTE/PATH/TO/config.toml

The one-line Claude Code equivalent. Restart the client and it sees the nine tools.

Which transport, and a gotcha

The rule of thumb is short. Use stdio for a desktop client on your own machine, and streamable HTTP for your own agent, script or local automation. Both carry the same tools; the choice is only about who launches the server and how the client reaches it, not about what the agent can do. One honesty note on PitBridge itself: it serves MCP over stdio today, streamable HTTP is on the roadmap, and a custom agent can use the localhost REST surface meanwhile.

How it differs from a REST API, a webhook, and a broker API

A trading MCP server is not the only way to send an order. It is worth placing it next to the interfaces it replaces or sits beside. The distinguishing question is who decides the order and where a control can sit.

interfacewho decides the ordercapability discoverystate-awarewhere a control can sit
REST or broker API (NT8 ATI, IBKR API)your code, wired in advancenone, you read the docsyou track it yourselfin your code, and skippable
Webhooka fixed rule fires a preset ordernonenoat the receiver
Cloud MCP endpointagent, via a third-party servertools/listyeson someone else’s box, in the network path
Local-first trading MCP (PitBridge)agent proposes, daemon adjudicatestools/listyesout-of-process guardrail on your machine, unskippable

A broker or platform API is a direct order route with no reasoning layer and no built-in choke point. A webhook adds a fixed trigger, still with no live-state reasoning. MCP adds tool discovery and live-state reasoning, and, done local-first, a single enforced control point on your own machine. The deep dives live elsewhere: MCP vs webhooks argues the trigger-versus-conversation split, and local-first automation covers why the order route staying on your machine is the part that matters.

The lifecycle of one order intent

The important property of a trading MCP server is that a tool call is a request, not a guarantee. Walk one order intent through the path:

  1. The agent connects and reads the tool list.
  2. It calls read tools to build a picture of the account: get_positions, get_orders, get_account_state for realized loss and halt status.
  3. It decides to act and calls place_order with typed arguments: account, instrument, side and qty.
  4. The server validates the schema, then hands the request to the guardrail engine.
  5. The engine checks the request against your configured limits and returns an allow, or a block with a typed reason_code.
  6. Only an allowed order continues to the platform.
agent tool calls
# read state, then place two orders. the second breaks the per-order cap.
get_account_state                                              -> link_up: true, day_pnl: 0.0, day_halted: false
place_order account=sim instrument="MES 09-26" side=BUY qty=2  -> SUBMITTED, then FILLED filled_qty=2
place_order account=sim instrument="MES 09-26" side=BUY qty=20 -> BLOCKED reason_code=MAX_CONTRACTS_PER_ORDER

Example agent tool calls against the local daemon. Real tool names and reason codes.

This is why the guardrail engine sits after the tool call, not inside the agent. A model can be instructed to respect a daily loss limit, but instructions are advisory; a check that runs in the daemon, out of the model’s reach, is enforced. The guardrails that an LLM cannot override spoke argues that mechanism in full.

What the guardrail chain checks, and the codes it returns

Every mutating call runs the same fixed pipeline: schema, then permission, then guardrails, then confirm, then submit, then audit. The guardrail stage is a frozen chain of twelve checks in a fixed evaluation order, with the kill switch first and human confirm last. Each check can emit a stable reason_code. The first blocking guardrail wins, and evaluation stops there.

stage or guardrailreason code(s) it can emit
engine shape checks (before the chain)SCHEMA_INVALID, INVALID_QTY, UNKNOWN_ACCOUNT
kill_switchKILL_SWITCH
link_downLINK_DOWN
instrument_allowlistINSTRUMENT_NOT_ALLOWED
position_capsMAX_CONTRACTS_PER_ORDER, MAX_POSITION
trading_windowNO_TRADE_DAY, OUTSIDE_TRADING_WINDOW
daily_loss_haltDAILY_LOSS_HALT
profit_lockPROFIT_LOCK
cooldownCOOLDOWN_AFTER_LOSS, COOLDOWN_AFTER_ORDER
rate_limitMAX_ORDERS_PER_MINUTE / _HOUR / _DAY
duplicate_protectionDUPLICATE_ORDER
human_confirm (last)HUMAN_CONFIRM_FIRST_ORDER / _EVERY_LIVE_ORDER / _SIZE_INCREASE

These codes are an API contract, not error strings. They are stable, machine-readable and append-only: renaming or removing one is a breaking change. A blocked order is returned as a structured result, blocked=true plus a reason_code and a human-readable detail, never a raised exception that would tear down the agent’s session. The four action outcomes an agent sees are SUBMITTED, BLOCKED, PENDING_CONFIRM and DONE. Because the code is typed, the agent can read why an order stopped and explain it rather than guessing. The guardrails page lists exactly what the engine refuses.

The security model of a trading MCP server

Connecting a language model to an order surface introduces risks a plain broker script does not have. Prompt injection, sometimes called tool poisoning, is when untrusted text the model reads persuades it to call a tool it should not. The confused-deputy problem is the general shape: a component acting for a user is tricked into using its authority for something the user never intended. A trading MCP server has to assume the driving model can be misled, and narrow the blast radius rather than trust it to behave.

  • Tool-surface minimization. No tool to release the kill switch, arm live trading, or mutate a guardrail or config value exists on the agent surface, so a compromised or injected agent cannot widen its own authority.
  • Out-of-process enforcement. The guardrail engine adjudicates every place_order regardless of what the model was told. That is the point of the guardrails an LLM cannot override.
  • Localhost bind and a pairing token. The daemon binds 127.0.0.1 and the AddOn presents a pairing_token, so no order is relayed off the machine.
  • De-risking always allowed. Cancel, close and flatten stay available even under a kill, so you can always get flat.
  • A tamper-evident, hash-chained audit log. audit verify plus an anchor file catches tampering, including deletion of the tail of the log.
  • Separate account modes. read_only, paper and live are distinct states, so trying an agent never touches a funded account by accident.

Permissions and account modes

A trading MCP server should let you scope what an agent can reach, and two controls do most of the work. Tool permissions decide which tools are exposed at all: offer the read tools and withhold place_order entirely, which gives an agent full visibility and zero write access. Account modes decide which account the writes touch.

modewhat a write doeshow you reach it
read_onlyrejected, reads onlythe default safe state
paperhits a simulation accountset the account mode in config
livehits a funded accountrequires a separately-shipped live plugin and an operator arm-live step, impossible from the agent surface

On top of modes, the human_confirm gate adds a human in the loop, with variants for the first order of a session, every live-mode order, or any order that increases size beyond the session maximum so far. Read-only, paper and live are separate states on purpose, so that trying an agent never risks a funded account by accident.

A worked example you can run on a Mac, no NinjaTrader needed

You can exercise the whole surface on a Mac against a fake AddOn, a small simulator that stands in for the real NinjaTrader AddOn, with no Windows box and no market feed. Start with a config for one Sim101 paper account and a few guardrails.

config.toml
[accounts.sim]
nt_account = "Sim101"
mode = "paper"

[accounts.sim.guardrails]
instruments = ["MES 09-26"]
max_contracts_per_order = 5
max_position = 10
daily_loss_halt = 400
trading_window = { tz = "America/New_York", open = "09:30", close = "16:00" }

A minimal paper config. Real field names, taken from the testing guide.

Start the daemon, then connect the fake AddOn. Until an AddOn connects and sends its first account state, every order is blocked with LINK_DOWN. That is the reconcile-first rule: no queueing orders against a dead link. Once the link is fresh, the agent reads state and proposes orders. A valid order fills; an off-allowlist instrument is refused.

agent tool calls (paper)
get_account_state                                              -> link_up: true, day_pnl: 0.0
place_order account=sim instrument="MES 09-26" side=BUY qty=2  -> SUBMITTED, then FILLED
place_order account=sim instrument="NQ 09-26"  side=BUY qty=1  -> BLOCKED reason_code=INSTRUMENT_NOT_ALLOWED

The allowlist blocks an off-list instrument before the fake broker ever sees it.

Engage the kill switch from the CLI. A valid entry now returns KILL_SWITCH, but de-risking still works, so you can always get flat. Releasing the kill is operator-only.

kill switch (CLI)
pitbridge kill --reason "stepping away"
place_order account=sim instrument="MES 09-26" side=BUY qty=1  -> BLOCKED reason_code=KILL_SWITCH
flatten_account account=sim                                    -> DONE   (de-risking allowed under a kill)
pitbridge unkill                                               # release is CLI-only, off the agent surface

Under a kill, new entries stop but flatten still runs. The agent cannot lift the kill.

Every request, decision and outcome is written to an append-only, hash-chained audit log, so you can ask why any order decided the way it did and verify the chain is intact.

audit trail (CLI)
pitbridge audit why <order_id>     # request, guardrail decision, submit result
pitbridge audit verify             # chain OK (N entries), tamper-evident

The audit log explains and verifies every decision after the fact.

For the full Claude setup against NinjaTrader 8, read connect Claude to NinjaTrader 8 safely. When your platform and prop firms are supported, tell us on the waitlist. PitBridge is trading infrastructure, not financial advice: it enforces the rules you configure and does not promise any trading outcome.

Read the pillar: MCP for futures trading

Questions

Is a trading MCP server the same as a trading bot?

No. An MCP server is a set of typed tools plus a transport. It does not decide when to trade. An agent connected to it decides, and in PitBridge every place_order still passes the guardrail engine before it reaches the platform.

Do I need to write code to use one?

Not for a standard client. An MCP client like Claude Desktop or Claude Code connects with a small config block. Custom code can also call a server directly; PitBridge serves MCP over stdio today, with streamable HTTP on the roadmap, and offers a localhost REST API meanwhile.

Where do the guardrails run?

In PitBridge the MCP server, the guardrail engine and your keys sit in the same local daemon. The order route never leaves your machine, so the checks cannot be skipped by a network hop.

Can I give an agent read-only access?

Yes. Tool permissions and account modes let you expose read tools like get_positions while withholding place_order, or point the whole session at a paper account first.

Can the agent disable the guardrails or raise a limit?

No. There is no tool for it. Config values, the kill switch and the arm-live step are operator-only on the CLI, off the agent surface entirely, so a compromised or misled agent cannot widen its own authority.

What is the difference between the stdio and HTTP transport?

It is about who launches the server and how the client reaches it. Over stdio the client launches the server as a local subprocess; over streamable HTTP the client connects to a local port. The tools are the same either way. PitBridge serves stdio today; streamable HTTP is on its roadmap.

Does the agent get live market data through these tools?

No. The v0 surface exposes no market-data tool. The agent brings its own data, and the server is only the account action surface. Its job is reading account state and proposing orders, not quoting the market.

PitBridge is in development. NinjaTrader 8 is first.

Tell us your platform and we email you when your setup is supported. Nothing else.