Skip to main content
Glama
narumiruna

Yahoo Finance MCP Server

yfinance_get_option_chain

Read-onlyIdempotent

Fetch option chain data for a stock including calls and puts with strike prices, expiration dates, bid/ask, volume, open interest, and implied volatility to analyze options pricing and IV surfaces.

Instructions

Fetch option chain data (calls and puts) for a stock with available strike prices.

Returns JSON with calls and/or puts data for each expiration date.

JSON fields include:
- contractSymbol: Option contract identifier
- strike: Strike price
- lastPrice: Last traded price
- bid/ask: Bid and ask prices
- volume: Trading volume
- openInterest: Open interest
- impliedVolatility: Implied volatility (IV)
- inTheMoney: Whether option is ITM
- contractSize: Contract size (REGULAR)
- currency: Currency (USD)

Use this to analyze options pricing, IV surfaces, and strike levels.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
symbolYesStock ticker symbol (e.g., 'AAPL', 'GOOGL', 'MSFT')
expiration_dateNoOption expiration date in YYYY-MM-DD format. Use the 'yfinance_get_option_dates' tool to find available dates, or omit to fetch all available expiration dates.
option_typeNoWhich options to return: 'calls', 'puts', or 'all' (both calls and puts).all

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The main tool handler for 'yfinance_get_option_chain'. Function get_option_chain() creates a Ticker, fetches available option dates, and for each requested date calls _fetch_option_chain_for_date() to retrieve calls/puts data.
    @mcp.tool(
        name="yfinance_get_option_chain",
        annotations=ToolAnnotations(
            readOnlyHint=True,
            destructiveHint=False,
            idempotentHint=True,
            openWorldHint=True,
        ),
    )
    async def get_option_chain(
        symbol: Annotated[str, Field(description="Stock ticker symbol (e.g., 'AAPL', 'GOOGL', 'MSFT')")],
        expiration_date: Annotated[
            str | None,
            Field(
                description=(
                    "Option expiration date in YYYY-MM-DD format. "
                    "Use the 'yfinance_get_option_dates' tool to find available dates, "
                    "or omit to fetch all available expiration dates."
                )
            ),
        ] = None,
        option_type: Annotated[
            OptionChainType,
            Field(description=("Which options to return: 'calls', 'puts', or 'all' (both calls and puts).")),
        ] = "all",
    ) -> str:
        """Fetch option chain data (calls and puts) for a stock with available strike prices.
    
        Returns JSON with calls and/or puts data for each expiration date.
    
        JSON fields include:
        - contractSymbol: Option contract identifier
        - strike: Strike price
        - lastPrice: Last traded price
        - bid/ask: Bid and ask prices
        - volume: Trading volume
        - openInterest: Open interest
        - impliedVolatility: Implied volatility (IV)
        - inTheMoney: Whether option is ITM
        - contractSize: Contract size (REGULAR)
        - currency: Currency (USD)
    
        Use this to analyze options pricing, IV surfaces, and strike levels.
        """
        try:
            ticker = await asyncio.to_thread(yf.Ticker, symbol)
        except _RETRYABLE_YFINANCE_EXCEPTIONS as exc:
            return _create_retryable_error_response(f"fetching options for '{symbol}'", exc, {"symbol": symbol})
        except Exception as exc:
            return create_error_response(
                f"Failed to fetch options for '{symbol}'. Verify the symbol is correct.",
                error_code="API_ERROR",
                details={"symbol": symbol, "exception": str(exc)},
            )
    
        try:
            available_dates = await asyncio.to_thread(lambda: ticker.options)
        except Exception as exc:
            return _create_option_dates_fetch_error(
                symbol,
                exc,
                f"Failed to fetch option dates for '{symbol}'. The symbol may not have options.",
            )
    
        if not available_dates:
            return create_error_response(
                f"No options available for symbol '{symbol}'. "
                "This symbol may not have listed options (e.g., ETFs, stocks without options).",
                error_code="NO_DATA",
                details={"symbol": symbol},
            )
    
        if expiration_date is not None and expiration_date not in available_dates:
            return create_error_response(
                f"Invalid expiration date '{expiration_date}' for '{symbol}'. Valid dates: {', '.join(available_dates)}",
                error_code="INVALID_PARAMS",
                details={
                    "symbol": symbol,
                    "expiration_date": expiration_date,
                    "valid_dates": available_dates,
                },
            )
    
        dates_to_fetch = [expiration_date] if expiration_date else list(available_dates)
        result: dict[str, Any] = {}
        fetch_errors: list[tuple[str, Exception]] = []
    
        for date in dates_to_fetch:
            try:
                date_result = await _fetch_option_chain_for_date(ticker, date, option_type)
            except Exception as exc:
                logger.warning("Failed to fetch option chain for {} {}: {}", symbol, date, exc)
                fetch_errors.append((date, exc))
                continue
            result.update(date_result)
    
        if result:
            return dump_json(result)
    
        if fetch_errors:
            return _create_option_chain_fetch_error(symbol, dates_to_fetch, fetch_errors)
    
        return create_error_response(
            f"No option data retrieved for '{symbol}'.",
            error_code="NO_DATA",
            details={"symbol": symbol, "dates_requested": list(dates_to_fetch)},
        )
  • Helper function _fetch_option_chain_for_date() that actually fetches option chain data for a single expiration date from yfinance and formats it as JSON with calls and/or puts.
    async def _fetch_option_chain_for_date(
        ticker: yf.Ticker,
        date: str,
        option_type: OptionChainType,
    ) -> dict[str, Any]:
        """Fetch option chain for a single expiration date."""
        opt = await asyncio.to_thread(lambda d=date: ticker.option_chain(d))
    
        calls_df = opt.calls
        puts_df = opt.puts
        date_data: dict[str, Any] = {}
    
        if calls_df is not None and not calls_df.empty and option_type in {"all", "calls"}:
            calls_df = calls_df.copy()
            calls_df["optionType"] = "CALL"
            date_data["calls"] = calls_df.to_dict(orient="records")
    
        if puts_df is not None and not puts_df.empty and option_type in {"all", "puts"}:
            puts_df = puts_df.copy()
            puts_df["optionType"] = "PUT"
            date_data["puts"] = puts_df.to_dict(orient="records")
    
        return {date: date_data} if date_data else {}
  • OptionChainType Literal type defining valid option_type parameter values: 'calls', 'puts', or 'all'.
    OptionChainType = Literal[
        "calls",
        "puts",
        "all",
    ]
  • The @mcp.tool decorator registers the get_option_chain function as the 'yfinance_get_option_chain' MCP tool with read-only, non-destructive, idempotent, and open-world annotations.
    @mcp.tool(
        name="yfinance_get_option_chain",
        annotations=ToolAnnotations(
            readOnlyHint=True,
            destructiveHint=False,
            idempotentHint=True,
            openWorldHint=True,
        ),
  • Helper function _create_option_chain_fetch_error() for generating structured error responses when option chain fetching fails.
    def _create_option_chain_fetch_error(
        symbol: str,
        dates_to_fetch: list[str],
        fetch_errors: list[tuple[str, Exception]],
    ) -> str:
        failed_dates = [date for date, _ in fetch_errors]
    
        if len(dates_to_fetch) == 1:
            failed_date, exc = fetch_errors[0]
            if _is_retryable_yfinance_error(exc):
                return _create_retryable_error_response(
                    f"fetching option chain for '{symbol}' on '{failed_date}'",
                    exc,
                    {"symbol": symbol, "expiration_date": failed_date},
                )
    
            return create_error_response(
                f"Failed to fetch option chain for '{symbol}' on '{failed_date}'.",
                error_code="API_ERROR",
                details={"symbol": symbol, "expiration_date": failed_date, "exception": str(exc)},
            )
    
        retryable_exceptions = [exc for _, exc in fetch_errors if _is_retryable_yfinance_error(exc)]
    
        if retryable_exceptions:
            return _create_retryable_error_response(
                f"fetching option chain for '{symbol}'",
                _select_retryable_exception(retryable_exceptions),
                {
                    "symbol": symbol,
                    "dates_requested": dates_to_fetch,
                    "failed_dates": failed_dates,
                },
            )
    
        representative_exception = fetch_errors[0][1]
        return create_error_response(
            f"Failed to fetch option chain for '{symbol}' for all requested dates.",
            error_code="API_ERROR",
            details={
                "symbol": symbol,
                "dates_requested": dates_to_fetch,
                "failed_dates": failed_dates,
                "exception": str(representative_exception),
            },
        )
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, destructiveHint, idempotentHint, and openWorldHint. The description adds value by detailing the JSON fields returned (e.g., contractSymbol, strike, impliedVolatility) and the intended use case for options analysis, without contradicting annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the purpose and then lists the JSON fields. It is moderately concise; the field list is helpful but could be slightly more condensed. However, it remains clear and well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is sufficiently complete for a data-fetching tool: it explains what data is returned, how to use parameters, and references a sibling tool for dates. The presence of an output schema (though not provided) is compensated by the detailed field listing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for all three parameters. The description adds semantic value by explaining the expiration_date parameter's relationship with yfinance_get_option_dates and by listing the fields in the output, which aids understanding beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool fetches option chain data (calls and puts) for a stock, with specific mention of strike prices and expiration dates. It distinguishes itself from sibling tools like yfinance_get_option_dates by explicitly referencing it for finding available dates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides implicit usage guidance by referencing yfinance_get_option_dates to obtain expiration dates, but it does not explicitly state when to use this tool over others or when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/narumiruna/yfinance-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server