KB / mcp
MCP tool: option_chain
Last verified
option_chain returns the full option chain for a symbol — calls and puts by expiration, with strike, bid, ask, last, volume, open interest, implied volatility, and the five Greeks (delta, gamma, theta, vega, rho). It wraps GET /api/v1/trading/options/chain/{symbol}, which is Schwab-backed and requires the auth service to be holding a valid token.
Signature
option_chain(
symbol: str, # underlying ticker, e.g. "SPY"
expiration: str | None = None, # filter to one expiration (YYYY-MM-DD); omit for all
strike_count: int = 50, # strikes around ATM (5–100, default 50)
) -> str # JSON-serialised dict
Validation (mcp/mcp_server/tools/public.py:option_chain):
symbolis upper-cased and stripped; empty →ValueError.strike_countoutside[5, 100]→ValueError.expirationis passed through as a query param; the backend validates the date format.
Returns
{
"symbol": "SPY",
"underlying_price": 538.20,
"expirations": {
"2026-06-20": {
"calls": [
{
"strike": 540.0,
"bid": 4.20, "ask": 4.30, "last": 4.25,
"volume": 12_340, "open_interest": 88_120,
"iv": 0.142,
"delta": 0.48, "gamma": 0.012, "theta": -0.18, "vega": 0.42, "rho": 0.08
},
...
],
"puts": [ ... same shape ... ]
},
"2026-07-18": { "calls": [...], "puts": [...] }
},
"as_of": "2026-05-26T10:14:33-04:00"
}
as_of is ET ISO 8601 with offset (Law 1). Greeks come straight from Schwab — they’re not re-computed on the platform.
Behaviour
- Cache TTL.
CACHE_TTL_CHAIN = 10s(mcp/mcp_server/config.py). The cache key includes symbol, expiration, and strike_count. - Schwab-only. No yfinance fallback. A missing or expired Schwab token surfaces as a backend error — by design, since silently degrading an option-chain read to “stock-only” would mislead a trading agent. Per DOCTRINE P0 — loud, never silent.
- Read-only, no MCP auth required. The public option-chain route does not require
TRADING_TOKEN. (The trading routes that execute option orders do.) strike_countsemantics. Returns the N strikes nearest the ATM strike, balanced above and below.strike_count=50returns ~25 calls and ~25 puts per expiration centered on ATM. Use larger counts for full-chain reads on wider underlyings; smaller for fast ATM-only checks.expirationfilter. Omit for the full chain across all listed expirations; pass"YYYY-MM-DD"to filter to one. The filter saves payload size and round-trip time when you only need one expiry.
Examples
Full chain, ATM-focused
Operator: "Show me SPY options."
Agent: option_chain(symbol="SPY")
Returns all expirations with the default 50 strikes around ATM each.
Single expiration
Operator: "What do SPY weeklies look like for next Friday?"
Agent: option_chain(symbol="SPY", expiration="2026-06-06")
Wide-net read for IV term structure
Agent: option_chain(symbol="SPY", strike_count=20)
-> 20 strikes per expiration across all listings.
-> Read IV at ATM for each expiration; build the term structure.
When to use
- Evaluating option strategies (covered calls, verticals, iron condors).
- Reading IV / IV skew before an option trade.
- Sanity-checking Greeks against position-level exposure.
- Building a custom term-structure view (call across all expirations with
strike_count=10).
When NOT to use
- You only need the stock price — use
get_quote. - You want dealer-gamma walls (price-magnet levels) — use
analyze_signals(aspect="gamma"); that aspect returns the per-strike call/put wall profile rather than the full chain.
See also
get_quote— underlying price only.analyze_signals—gammaaspect for wall levels,volatilitysubstrate via the deeper aspects.plan_trade— to actually trade a contract from the chain.- Implementation:
mcp/mcp_server/tools/public.py:option_chain, backend routeGET /api/v1/trading/options/chain/{symbol}.