Source code for tavily_fastmcp.models

"""Typed models for Tavily FastMCP.

Purpose:
    Define canonical request, response, catalog, and profile models.

Design:
    - Request models are strict and reject unknown fields.
    - Response models allow extra fields because upstream Tavily payloads
      may evolve.
    - Profile and catalog models are shared between direct Python helpers,
      packaged resources, and MCP prompts.

Examples:
    >>> SearchRequest(query="FastMCP docs").max_results
    5
    >>> ProfileSummary(slug="router", title="Router", summary="x").slug
    'router'
"""

from __future__ import annotations

from typing import Any, Literal

from pydantic import AnyUrl, BaseModel, ConfigDict, Field

[docs] type JsonObject = dict[str, Any]
[docs] class SearchRequest(BaseModel): """Canonical request model for Tavily search. Args: query: Natural-language search query. max_results: Maximum number of results. topic: Tavily topic mode. include_answer: Whether to include Tavily's answer field. include_raw_content: Whether to return cleaned page content. include_images: Whether to include image URLs. include_image_descriptions: Whether to include image descriptions. search_depth: Tavily search depth. time_range: Relative time filter. start_date: Inclusive start bound in ``YYYY-MM-DD`` format. end_date: Inclusive end bound in ``YYYY-MM-DD`` format. include_domains: Domains to include. exclude_domains: Domains to exclude. include_usage: Whether to return usage metadata. Returns: A validated request object. Raises: ValueError: If a field is invalid. Examples: >>> SearchRequest(query="FastMCP resources", max_results=3).max_results 3 """
[docs] model_config = ConfigDict(extra="forbid")
[docs] query: str
[docs] max_results: int = Field(default=5, ge=1, le=20)
[docs] topic: Literal["general", "news", "finance"] = "general"
[docs] include_answer: bool = False
[docs] include_raw_content: bool = False
[docs] include_images: bool = False
[docs] include_image_descriptions: bool = False
[docs] search_depth: Literal["basic", "advanced"] = "basic"
[docs] time_range: Literal["day", "week", "month", "year"] | None = None
[docs] start_date: str | None = None
[docs] end_date: str | None = None
[docs] include_domains: list[str] | None = None
[docs] exclude_domains: list[str] | None = None
[docs] include_usage: bool = False
[docs] class ExtractRequest(BaseModel): """Canonical request model for Tavily extract. Args: urls: URLs to extract. extract_depth: Extraction depth. include_images: Whether to include images. Returns: A validated request object. Raises: ValueError: If a field is invalid. Examples: >>> ExtractRequest(urls=["https://example.com"]).extract_depth 'basic' """
[docs] model_config = ConfigDict(extra="forbid")
[docs] urls: list[AnyUrl] = Field(min_length=1)
[docs] extract_depth: Literal["basic", "advanced"] = "basic"
[docs] include_images: bool = False
[docs] class MapRequest(BaseModel): """Canonical request model for Tavily map."""
[docs] model_config = ConfigDict(extra="forbid")
[docs] url: AnyUrl
[docs] instructions: str | None = None
[docs] class CrawlRequest(BaseModel): """Canonical request model for Tavily crawl."""
[docs] model_config = ConfigDict(extra="forbid")
[docs] url: AnyUrl
[docs] instructions: str | None = None
[docs] class ResearchRequest(BaseModel): """Canonical request model for Tavily research."""
[docs] model_config = ConfigDict(extra="forbid")
[docs] input: str
[docs] model: Literal["mini", "pro", "auto"] = "auto"
[docs] output_schema: JsonObject | None = None
[docs] stream: bool = False
[docs] citation_format: Literal["numbered", "mla", "apa", "chicago"] = "numbered"
[docs] class GetResearchRequest(BaseModel): """Canonical request model for retrieving a Tavily research task."""
[docs] model_config = ConfigDict(extra="forbid")
[docs] request_id: str
[docs] class SearchHit(BaseModel): """Normalized Tavily search hit."""
[docs] model_config = ConfigDict(extra="allow")
[docs] url: str
[docs] title: str | None = None
[docs] content: str | None = None
[docs] raw_content: str | None = None
[docs] score: float | None = None
[docs] published_date: str | None = None
[docs] class SearchResponse(BaseModel): """Normalized Tavily search response."""
[docs] model_config = ConfigDict(extra="allow")
[docs] query: str | None = None
[docs] answer: str | None = None
[docs] results: list[SearchHit] = Field(default_factory=list)
[docs] images: list[str] = Field(default_factory=list)
[docs] response_time: float | None = None
[docs] request_id: str | None = None
[docs] follow_up_questions: list[str] = Field(default_factory=list)
[docs] usage: JsonObject | None = None
[docs] class ExtractHit(BaseModel): """Normalized Tavily extract result item."""
[docs] model_config = ConfigDict(extra="allow")
[docs] url: str
[docs] raw_content: str | None = None
[docs] images: list[str] = Field(default_factory=list)
[docs] class ExtractResponse(BaseModel): """Normalized Tavily extract response."""
[docs] model_config = ConfigDict(extra="allow")
[docs] results: list[ExtractHit] = Field(default_factory=list)
[docs] failed_results: list[JsonObject] = Field(default_factory=list)
[docs] response_time: float | None = None
[docs] class MapResponse(BaseModel): """Normalized Tavily map response."""
[docs] model_config = ConfigDict(extra="allow")
[docs] base_url: str | None = None
[docs] results: list[str] = Field(default_factory=list)
[docs] request_id: str | None = None
[docs] response_time: float | None = None
[docs] class CrawlHit(BaseModel): """Normalized Tavily crawl result item."""
[docs] model_config = ConfigDict(extra="allow")
[docs] url: str
[docs] raw_content: str | None = None
[docs] class CrawlResponse(BaseModel): """Normalized Tavily crawl response."""
[docs] model_config = ConfigDict(extra="allow")
[docs] base_url: str | None = None
[docs] results: list[CrawlHit] = Field(default_factory=list)
[docs] request_id: str | None = None
[docs] response_time: float | None = None
[docs] class ResearchSource(BaseModel): """Source used by a Tavily research task."""
[docs] model_config = ConfigDict(extra="allow")
[docs] title: str | None = None
[docs] url: str | None = None
[docs] favicon: str | None = None
[docs] class ResearchResponse(BaseModel): """Normalized Tavily research response."""
[docs] model_config = ConfigDict(extra="allow")
[docs] request_id: str | None = None
[docs] created_at: str | None = None
[docs] completed_at: str | None = None
[docs] status: str | None = None
[docs] input: str | None = None
[docs] model: str | None = None
[docs] content: str | JsonObject | None = None
[docs] sources: list[ResearchSource] = Field(default_factory=list)
[docs] response_time: float | None = None
[docs] class ProfileSummary(BaseModel): """Summary metadata for a packaged prompt profile. Args: slug: Stable profile slug. title: Human-readable title. summary: One-sentence profile summary. tags: Tags for filtering and discovery. recommended_tools: Ordered preferred tool names. prompt_resource_uri: Resource URI for the prompt text. profile_resource_uri: Resource URI for structured profile metadata. Returns: A reusable profile summary object. Raises: ValueError: If a field is invalid. Examples: >>> ProfileSummary( ... slug="router", ... title="Router", ... summary="Route tasks", ... prompt_resource_uri="resource://x", ... profile_resource_uri="resource://y", ... ).slug 'router' """
[docs] slug: str
[docs] title: str
[docs] summary: str
[docs] tags: list[str] = Field(default_factory=list)
[docs] recommended_tools: list[str] = Field(default_factory=list)
[docs] prompt_resource_uri: str
[docs] profile_resource_uri: str
[docs] class PromptProfile(BaseModel): """Structured packaged profile with markdown prompt content. Args: slug: Stable profile slug. title: Human-readable title. summary: Short description. use_when: List of ideal use cases. avoid_when: List of anti-patterns. recommended_tools: Preferred tool sequence. tags: Discovery tags. meta: Arbitrary profile metadata. prompt_markdown: Full markdown prompt body. Returns: A rich profile object. Raises: ValueError: If a field is invalid. Examples: >>> profile = PromptProfile( ... slug="router", ... title="Router", ... summary="Route tasks", ... prompt_markdown="# Router", ... ) >>> profile.title 'Router' """
[docs] slug: str
[docs] title: str
[docs] summary: str
[docs] use_when: list[str] = Field(default_factory=list)
[docs] avoid_when: list[str] = Field(default_factory=list)
[docs] recommended_tools: list[str] = Field(default_factory=list)
[docs] tags: list[str] = Field(default_factory=list)
[docs] meta: JsonObject = Field(default_factory=dict)
[docs] prompt_markdown: str
[docs] class ServerCatalog(BaseModel): """Catalog of server metadata exposed through resources and tools."""
[docs] name: str
[docs] version: str
[docs] package_name: str
[docs] prompt_names: list[str] = Field(default_factory=list)
[docs] profile_slugs: list[str] = Field(default_factory=list)
[docs] tool_names: list[str] = Field(default_factory=list)
[docs] resource_uris: list[str] = Field(default_factory=list)
[docs] example_resource_uris: list[str] = Field(default_factory=list)
[docs] meta: JsonObject = Field(default_factory=dict)
[docs] class HealthResponse(BaseModel): """Simple health payload."""
[docs] status: Literal["ok"]
[docs] server_name: str
[docs] version: str