Learn / Exchange & Broker MCP

How LLM tool calls go wrong on orders

Figures on this page are as of 2026-09. Fees, limits and margin tiers change — check the venue's own docs before acting on a number.

When people worry about a language model trading, they usually picture it deciding to do something reckless. That is not the interesting failure. The interesting failures are mundane: a number in the wrong place, a call that ran twice, a position the model did not know about.

Here they are, roughly in order of how often they bite.

1. The parameter is wrong and looks fine

This is the most common one by a wide margin, and the hardest to catch by reading.

  • Quantity off by a decimal. 0.5 where you meant 0.05. Both are plausible sizes. Neither looks wrong in a log.
  • Units confused. Base currency versus quote currency versus contracts. 1000 means very different things depending on which the venue expects, and the model is inferring from a tool schema it read once.
  • Side flipped. Particularly when the conversation has been discussing both directions, which is most of the time.
  • Order type mismatch. A stop submitted as a limit sits there instead of protecting you. It reports success.
  • Price in the wrong reference. An absolute price where the venue wants a delta, or vice versa.

What makes these dangerous is not their likelihood but their signature: the call succeeds, the exchange accepts it, and nothing reports an error. You find out from your position.

What actually helps: seeing the arguments before the call. This is exactly what the MCP specification recommends — clients “SHOULD show tool inputs to the user before calling the server”. For an order, the tool inputs are the trade. A size cap enforced in code helps too, because a decimal-place error usually produces something obviously outside your normal range.

What does not help: asking the model to double-check. The check is drawn from the same distribution as the original.

2. The retry that placed two orders

This one is underdiscussed and deserves more attention than it gets.

CCXT’s exception hierarchy splits at the top into two branches, and the split is the whole point:

  • ExchangeError — the exchange understood the request and refused it. The request was wrong; retrying unchanged fails again.
  • OperationFailed — and beneath it NetworkError, RequestTimeout, RateLimitExceeded, ExchangeNotAvailable. Something went wrong in transit.

The critical property: OperationFailed means the outcome is unknown, and for an order-placing call, unknown is not the same as failed. A RequestTimeout on createOrder may mean the exchange never received it. It may equally mean the order was accepted and filled, and the response was lost on the way back.

The naive handler retries on network errors, because that is what you do with network errors. Applied to order placement, it can double a position.

Worth noting that MCP’s own tool annotations get this right by default: idempotentHint defaults to false, and the schema describes it as whether “calling the tool repeatedly with the same arguments will have no additional effect”. For an order-placement tool that default is correct and load-bearing.

What actually helps: reconcile before retrying. On an ambiguous failure, query open orders and positions and find out what actually happened before sending anything again. Where the venue supports a client-supplied order ID, use it — that is what it is for.

What does not help: exponential backoff. It makes the retry later, not safer.

3. The model does not know what it cannot see

A model’s picture of your account is exactly the tools it has, and it has no sense of the shape of what is missing.

If the tools expose spot balances but not futures positions, you will get confident answers about your exposure that are confidently incomplete. If the position data was fetched three messages ago and the market has moved, the model is reasoning about a snapshot without knowing it is stale.

What actually helps: exposing complete data for whatever you ask it to reason about, and re-fetching before acting rather than reasoning from earlier in the conversation. Narrow, complete tool coverage beats broad, partial.

4. Instructions arriving through the context window

If the model reads anything you did not write — a news article, a scraped forum post, another tool’s output — that text lands in the same context as your instructions, and the architecture does not distinguish between them by origin.

MCP’s specification is alert to this in both directions. It requires servers to “sanitize tool outputs” and recommends clients “validate tool results before passing to LLM”. It also warns that tool annotations themselves are untrusted input:

“Clients should never make tool use decisions based on ToolAnnotations received from untrusted servers.”

A model holding order-placement tools and reading untrusted text is a combination worth avoiding rather than defending against. The defences are partial; the separation is not.

What actually helps: do not give the same session both untrusted input and order tools. Research in one place, trade in another.

5. The tool list changed under you

MCP servers can notify clients that their tool set has changed — notifications/tools/list_changed exists for this. It is a normal part of the protocol, not an edge case.

Which means the server you installed and reviewed as read-only can acquire an order-placement tool in an update. Nothing about that is malicious; it is how software evolves. But if your safety reasoning was “this server only reads”, it has an expiry date you did not set.

What actually helps: pin versions, and re-check the tool list after updating. Better, make the permission live on the exchange key, where a server update cannot reach it.

6. Sequencing that is individually valid and collectively wrong

Each call is fine. The sequence is not.

Opening a position before the protective stop is placed, and something failing in between. Cancelling a stop to replace it and not completing the replacement. Closing half a position with a rounding that leaves an awkward remainder.

Models are reasonably good at single calls and worse at multi-step state management, particularly when a step fails partway.

What actually helps: treat entry-and-stop as one unit that either fully succeeds or is fully unwound, rather than two calls that usually both work.

What this adds up to

The pattern across all six: the dangerous failures are quiet. They return success. The model does not flag them because from its side nothing went wrong.

Which is why “watch it carefully” is not a strategy. You cannot attend to a thing that does not announce itself. The controls that work are the ones that run whether or not anyone noticed something was off — arguments displayed before submission, caps evaluated as code, reconciliation after ambiguity.

FAQ

Can I prevent parameter errors by telling the model to be careful?

Not meaningfully. The instruction is an input to the same process that produced the error, so the verification is drawn from the same distribution as the mistake. What works is structural: show the arguments before the call, and cap size in code so that an out-of-range value is rejected rather than reviewed.

Is it safe to retry a failed order automatically?

Not without reconciling first. A network error or timeout on an order call means the outcome is unknown, not that it failed — the order may have been filled with the response lost in transit. Query open orders and positions to establish what actually happened, then decide. CCXT’s hierarchy makes this distinction explicit by separating ExchangeError from OperationFailed.

How would I even notice a wrong-parameter order?

Usually from your position rather than from any error, which is the problem. The practical detections are a size cap that rejects out-of-range orders before submission, and a review of the day’s fills against the day’s approvals. Neither is glamorous and both work.

Does a bigger or newer model fix these?

It reduces frequency without changing the category. Parameter errors, stale context and ambiguous retries are properties of the setup rather than of model quality, and the retry problem in particular is not about the model at all — it is about what a timeout means. Controls that do not depend on model quality are the ones worth building.