KB / mcp
MCP tool: execute_trade
Last verified
execute_trade is the second half of the two-step trade flow. It either confirms a pending trade at the price plan_trade locked, or cancels it and releases the reserved buying power. Either way, this is the deliberate moment of commitment — every actual position change goes through this tool.
Signature
execute_trade(
trade_id: str, # the trade_id returned by plan_trade
action: str, # "confirm" to fill at the locked price, or "cancel" to abort
) -> str # JSON-serialised dict
Validation (mcp/mcp_server/tools/trading.py:execute_trade):
actionis lower-cased and stripped.actionoutside{"confirm", "cancel"}→ValueError("action must be 'confirm' or 'cancel'.").- Invalid / expired / already-confirmed
trade_idsurfaces as a backend error with the actual status.
confirm routes to POST /api/v1/trading/trades/{trade_id}/confirm; cancel routes to DELETE /api/v1/trading/trades/{trade_id}.
Returns
On action="confirm"
{
"trade_id": "trd-abc123",
"status": "executed",
"symbol": "AAPL",
"side": "buy",
"quantity": 10,
"executed_price": 215.40,
"total": 2154.00,
"executed_at": "2026-05-26T10:14:55-04:00",
"new_balance": 97_686.12,
"new_position": {
"symbol": "AAPL",
"quantity": 10,
"avg_price": 215.40
}
}
On action="cancel"
{
"trade_id": "trd-abc123",
"status": "cancelled",
"cancelled_at": "2026-05-26T10:14:48-04:00",
"released_buying_power": 2154.00
}
executed_at / cancelled_at are ET ISO 8601 with offset (Law 1).
Behaviour
- Single-claim semantics. The confirm path is wrapped in
BEGIN IMMEDIATE+UPDATE … SET status='executing' WHERE id=? AND status='pending'. Only the caller whoserowcount==1proceeds to the actual execution; concurrent confirms against the sametrade_idget a 400 with the actual current status. This makes accidental double-confirms impossible. - No cache. Mutation tool — every call hits the backend. The tool invalidates the
portfolio_statuscache so the post-trade state is reflected immediately on the next portfolio read. - Cancel is also auth’d. Both confirm and cancel require the bearer token. Cancelling someone else’s pending trade is not a thing.
- Expired window. Once
expires_athas passed, confirm returns an error. Cancel against an already-expired trade is generally a no-op (the backend has cleaned it up) — surface as a benign status message.
Examples
Confirm immediately after plan_trade
Agent: plan_trade(symbol="AAPL", side="buy", quantity=10)
-> trade_id "trd-abc123", price 215.40
Agent: execute_trade(trade_id="trd-abc123", action="confirm")
-> filled, new_balance 97_686.12
Operator changes their mind
Agent: plan_trade(symbol="SPY", side="buy", quantity=10)
-> trade_id "trd-xyz789", price 538.20
Operator: "Actually, hold off."
Agent: execute_trade(trade_id="trd-xyz789", action="cancel")
-> released_buying_power 5382.00
Stale trade_id
Agent: execute_trade(trade_id="trd-old111", action="confirm")
-> backend returns 400 "Trade has expired" (window elapsed)
Agent (to operator): "That quote expired — want me to re-plan at the current price?"
Invalid action
Agent: execute_trade(trade_id="trd-abc", action="modify")
-> ValueError("action must be 'confirm' or 'cancel'.")
modify is not a supported action — the platform does not support in-flight quote modification. Cancel and re-plan instead.
When to use
- Immediately after
plan_trade, once the operator has confirmed (or rejected) the locked price. - To explicitly cancel a pending trade rather than waiting for the 60-second timeout.
When NOT to use
- The 60-second window has expired — call
plan_tradeagain to re-quote. - You don’t have a valid
trade_idfrom a recentplan_tradecall. - You want to modify the order — not supported. Cancel and re-plan.
See also
plan_trade— the first half of the flow.portfolio_status— confirm the post-execution state.- Implementation:
mcp/mcp_server/tools/trading.py:execute_trade, backend routesPOST /api/v1/trading/trades/{trade_id}/confirmandDELETE /api/v1/trading/trades/{trade_id}.