KB / mcp
MCP tool: portfolio_status
Last verified
portfolio_status is the one-call “show me everything” tool for an authenticated trading agent. It fans out five concurrent backend calls — account, stock positions, option positions, pending trades, recent history — and returns the combined view. Each leg is real Schwab pricing tracked against the platform’s paper-trading database (/app/data/trading.db, WAL mode).
Signature
portfolio_status() -> str # JSON-serialised dict
No parameters. The tool fans out concurrent asyncio.gather() calls to the five backend routes and assembles them into a single response.
Returns
{
"account": {
"account_id": "paper-001",
"balance": 99_840.12,
"starting_balance": 100_000.00,
"buying_power": 99_840.12,
"as_of": "2026-05-26T10:14:33-04:00"
},
"stock_positions": [
{
"symbol": "SPY",
"quantity": 10,
"avg_price": 535.80,
"current_price": 538.20,
"market_value": 5_382.00,
"unrealized_pl": 24.00,
"unrealized_pl_pct": 0.45
},
...
],
"option_positions": [
{
"symbol": "SPY",
"option_type": "call",
"strike": 540.0,
"expiration": "2026-06-20",
"quantity": 2,
"avg_price": 4.10,
"current_price": 4.25,
"market_value": 850.00,
"unrealized_pl": 30.00,
"delta": 0.48, "gamma": 0.012, "theta": -0.18, "vega": 0.42
},
...
],
"pending_trades": [
{
"trade_id": "trd-abc123",
"symbol": "AAPL",
"side": "buy",
"quantity": 5,
"price": 215.40,
"expires_at": "2026-05-26T10:15:33+00:00",
"status": "pending"
}
],
"recent_trades": [
{ "trade_id": "trd-xyz789", "symbol": "SPY", "side": "buy", "quantity": 10, "price": 535.80, "executed_at": "2026-05-23T14:02:11-04:00" },
...
]
}
- Position arrays normalise the backend’s
{"positions": [...]}envelope to a bare list for ergonomic consumption. pending_trades[*].expires_atis UTC ISO 8601 with offset — this is the locked-quote window fromplan_trade. Operational dates (executed_at,as_of) are ET ISO 8601 per Law 1.- Empty surfaces return empty arrays, not
null— a flat portfolio is still a valid portfolio.
Behaviour
- Cache TTL.
CACHE_TTL_PORTFOLIO = 10s(mcp/mcp_server/config.py). Mutation calls (plan_trade,execute_trade) invalidate this cache so subsequent reads see the new state immediately. - Concurrent fan-out. The five legs run via
asyncio.gather()— total round-trip is one network leg’s worth of latency, not five. - Auth required. All five underlying routes use
auth_required=Trueinmcp/mcp_server/tools/trading.py. The MCP server forwards the bearer token from the client config to each backend call. - Single account per server instance. The MCP server binds to one trading account via
TRADING_TOKEN. Multi-account workflows need multiple server configurations.
Examples
Session opener for a trading agent
Agent: market_pulse() -> regime + alerts
Agent: portfolio_status() -> current positions + cash + P&L
The pair gives an agent everything it needs to reason about adjustments without further calls.
Pre-trade sanity check
Operator: "Add 10 more SPY shares."
Agent: portfolio_status()
-> read account.buying_power, existing SPY quantity in stock_positions
Agent: get_quote(symbols="SPY")
Agent: plan_trade(symbol="SPY", side="buy", quantity=10)
Agent: execute_trade(trade_id="...", action="confirm")
P&L review
Operator: "How am I doing today?"
Agent: portfolio_status()
-> sum unrealized_pl across stock_positions + option_positions.
-> compare account.balance to account.starting_balance.
When to use
- Start of any trading conversation — establish current exposure.
- Before any
plan_tradecall — confirm cash + existing position. - P&L reviews, position audits, pending-order checks.
When NOT to use
- The conversation is market-data-only (use
market_pulse/get_quoteinstead). - You only need cash balance —
portfolio_statusis the lightest call that gives it, so use it anyway; there’s no thinner alternative. - You need to modify a position — use
plan_tradethenexecute_trade.
See also
plan_trade— quote and lock a price for 60s.execute_trade— confirm or cancel a planned trade.market_pulse— market-wide regime context before trading.- Implementation:
mcp/mcp_server/tools/trading.py:portfolio_status, backend routes/api/v1/trading/account,/positions,/positions/options,/trades/pending,/history.