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]
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 MapRequest(BaseModel):
"""Canonical request model for Tavily map."""
[docs]
model_config = ConfigDict(extra="forbid")
[docs]
instructions: str | None = None
[docs]
class CrawlRequest(BaseModel):
"""Canonical request model for Tavily crawl."""
[docs]
model_config = ConfigDict(extra="forbid")
[docs]
instructions: str | None = None
[docs]
class ResearchRequest(BaseModel):
"""Canonical request model for Tavily research."""
[docs]
model_config = ConfigDict(extra="forbid")
[docs]
model: Literal["mini", "pro", "auto"] = "auto"
[docs]
output_schema: JsonObject | None = None
[docs]
class GetResearchRequest(BaseModel):
"""Canonical request model for retrieving a Tavily research task."""
[docs]
model_config = ConfigDict(extra="forbid")
[docs]
class SearchHit(BaseModel):
"""Normalized Tavily search hit."""
[docs]
model_config = ConfigDict(extra="allow")
[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 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]
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]
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]
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]
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]
use_when: list[str] = Field(default_factory=list)
[docs]
avoid_when: list[str] = Field(default_factory=list)
[docs]
class ServerCatalog(BaseModel):
"""Catalog of server metadata exposed through resources and tools."""
[docs]
prompt_names: list[str] = Field(default_factory=list)
[docs]
profile_slugs: 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]
class HealthResponse(BaseModel):
"""Simple health payload."""