Source code for polymarket_mcp.models.gamma

"""Typed Gamma domain and tool I/O models.

Purpose:
    Define normalized market-discovery models for the Polymarket Gamma API and
    the MCP tool input and output contracts built on top of them.

Design:
    The models in this module separate:
    1. tool inputs,
    2. normalized domain objects, and
    3. MCP-friendly output envelopes.

    This keeps the service layer stable and avoids leaking arbitrary upstream
    JSON across the package.

Attributes:
    SearchPublicArgs:
        Input model for free-text public search.
    ListMarketsArgs:
        Input model for market listing and filtering.
    ListEventsArgs:
        Input model for event listing and filtering.
    Market:
        Normalized Polymarket market model.
    Event:
        Normalized Polymarket event model.
    SearchMarketsOutput:
        MCP output envelope for market search.
    ListEventsOutput:
        MCP output envelope for event listing.
    MarketDetailOutput:
        MCP output envelope for a single market.
    EventDetailOutput:
        MCP output envelope for a single event.
"""

from __future__ import annotations

from pydantic import BaseModel, ConfigDict, Field, computed_field


[docs] class SearchPublicArgs(BaseModel): """Arguments for Gamma public search. Args: query: Free-text query used to search markets, events, and related public entities. limit: Maximum number of results to request. Returns: SearchPublicArgs: Validated search arguments. Raises: ValueError: If validation fails. Examples: >>> args = SearchPublicArgs(query="fed decision", limit=5) >>> args.limit 5 """ model_config = ConfigDict(extra="forbid") query: str = Field(min_length=1) limit: int = Field(default=10, ge=1, le=100)
[docs] class ListMarketsArgs(BaseModel): """Arguments for listing or filtering Gamma markets. Args: limit: Maximum number of markets to return. active: Whether to prefer active markets. closed: Whether to include closed markets. slug: Optional exact market slug filter. tag_id: Optional tag identifier filter. series_slug: Optional series slug filter. Returns: ListMarketsArgs: Validated market filter arguments. Raises: ValueError: If validation fails. Examples: >>> args = ListMarketsArgs(limit=10, active=True, closed=False) >>> args.active True """ model_config = ConfigDict(extra="forbid") limit: int = Field(default=10, ge=1, le=100) active: bool = True closed: bool = False slug: str | None = None tag_id: int | None = None series_slug: str | None = None
[docs] class ListEventsArgs(BaseModel): """Arguments for listing or filtering Gamma events. Args: limit: Maximum number of events to return. active: Whether to prefer active events. closed: Whether to include closed events. slug: Optional exact event slug filter. Returns: ListEventsArgs: Validated event filter arguments. Raises: ValueError: If validation fails. Examples: >>> args = ListEventsArgs(limit=10, active=True, closed=False) >>> args.closed False """ model_config = ConfigDict(extra="forbid") limit: int = Field(default=10, ge=1, le=100) active: bool = True closed: bool = False slug: str | None = None
[docs] class Market(BaseModel): """Normalized Polymarket market model. Args: id: Optional upstream market identifier. slug: Canonical market slug from Polymarket URLs. question: Human-readable market question text. active: Whether the market is currently active. closed: Whether the market is closed. liquidity: Reported liquidity value when present. volume: Reported volume value when present. event_slug: Parent event slug when known. clob_token_ids: Associated CLOB token identifiers, if available. Returns: Market: Normalized market model. Raises: ValueError: If validation fails. Examples: >>> market = Market(slug="fed-decision", question="Will the Fed cut?") >>> market.slug 'fed-decision' """ model_config = ConfigDict(extra="allow") id: str | None = None slug: str question: str | None = None active: bool | None = None closed: bool | None = None liquidity: float | None = None volume: float | None = None event_slug: str | None = None clob_token_ids: list[str] = Field(default_factory=list)
[docs] class Event(BaseModel): """Normalized Polymarket event model. Args: id: Optional upstream event identifier. slug: Canonical event slug from Polymarket URLs. title: Human-readable event title. active: Whether the event is currently active. closed: Whether the event is closed. markets: Nested normalized markets associated with the event. Returns: Event: Normalized event model. Raises: ValueError: If validation fails. Examples: >>> event = Event(slug="fed-event", title="Fed Event") >>> event.title 'Fed Event' """ model_config = ConfigDict(extra="allow") id: str | None = None slug: str title: str | None = None active: bool | None = None closed: bool | None = None markets: list[Market] = Field(default_factory=list)
[docs] class SearchMarketsOutput(BaseModel): """Tool output for public Gamma search. Args: query: Original search query. markets: Matching normalized markets. Returns: SearchMarketsOutput: Search result envelope. Raises: ValueError: If validation fails. Examples: >>> output = SearchMarketsOutput(query="fed", markets=[]) >>> output.count 0 """ model_config = ConfigDict(extra="forbid") query: str markets: list[Market] = Field(default_factory=list) @computed_field @property def count(self) -> int: """Return the number of matching markets. Returns: int: Number of returned markets. Raises: None. Examples: >>> SearchMarketsOutput(query="x", markets=[]).count 0 """ return len(self.markets)
[docs] class ListEventsOutput(BaseModel): """Tool output for Gamma event listing. Args: events: Matching normalized events. Returns: ListEventsOutput: Event listing envelope. Raises: ValueError: If validation fails. Examples: >>> output = ListEventsOutput(events=[]) >>> output.count 0 """ model_config = ConfigDict(extra="forbid") events: list[Event] = Field(default_factory=list) @computed_field @property def count(self) -> int: """Return the number of returned events. Returns: int: Number of returned events. Raises: None. Examples: >>> ListEventsOutput(events=[]).count 0 """ return len(self.events)
[docs] class MarketDetailOutput(BaseModel): """Tool output for a single market lookup. Args: market: The normalized market payload. Returns: MarketDetailOutput: Single-market envelope. Raises: ValueError: If validation fails. Examples: >>> output = MarketDetailOutput(market=Market(slug="x")) >>> output.market.slug 'x' """ model_config = ConfigDict(extra="forbid") market: Market
[docs] class EventDetailOutput(BaseModel): """Tool output for a single event lookup. Args: event: The normalized event payload. Returns: EventDetailOutput: Single-event envelope. Raises: ValueError: If validation fails. Examples: >>> output = EventDetailOutput(event=Event(slug="x")) >>> output.event.slug 'x' """ model_config = ConfigDict(extra="forbid") event: Event