Skip to content

MCP Server

The MCP server is the platform's interface to AI agents. It exposes tools, resources, and prompt templates through the Model Context Protocol. Agents call these to query intelligence data.

Why MCP (Not REST)

The spike's decision, validated:

  • Standardized for AI agent consumption — no custom API design
  • Schema generation is automatic from Pydantic models
  • Works with Claude Desktop, our agents, and any MCP-compatible client
  • Reduces integration surface — one protocol, many clients

Tools (Per Vertical)

Every vertical gets its own set of MCP tools. The DMC vertical ships with 5:

ToolDescription
search_dmcFull-text + filtered search (destination, service, specialty)
get_dmc_detailsFull DMC record by ID
list_destinationsAll indexed destinations
find_dmc_by_destinationAll DMCs in a destination
catalog_statsDatabase statistics

Tool Signatures (Pydantic)

from mcp_server.server import mcp
from models import DMC

@mcp.tool()
def search_dmc(
    query: str | None = None,
    destination: str | None = None,
    service: str | None = None,
    specialty: str | None = None,
    limit: int = 20,
) -> list[DMC]:
    """Search the DMC catalog with optional filters."""
    ...

The Pydantic type annotations become the JSON schema the agent sees. The docstring becomes the tool description. This is why the platform is Pydantic everywhere.

Resources (Per Vertical)

Resources are read-only data the agent can fetch. The DMC vertical ships with 3:

ResourceDescription
dmc://catalog/statsDatabase statistics
dmc://catalog/destinationsAll destinations with counts
dmc://catalog/servicesAll services with counts

Resources are useful for "give me the lay of the land" — the agent reads a resource to understand what's in the database before issuing targeted searches.

Prompt Templates (Per Vertical)

Prompt templates are pre-written prompts the agent can invoke. The DMC vertical ships with 2:

TemplateDescription
find_dmc_for_destination"Given a destination, recommend DMCs"
match_dmc_to_trip"Given a trip profile, suggest DMCs"

Templates are useful for standardizing common agent workflows. They reduce prompt engineering overhead.

Adding a New Vertical's Tools

# In mcp_server/server.py

@mcp.tool()
def search_restaurant(
    query: str | None = None,
    cuisine: str | None = None,
    city: str | None = None,
    price_tier: str | None = None,
    limit: int = 20,
) -> list[Restaurant]:
    """Search the restaurant catalog with optional filters."""
    ...

@mcp.tool()
def get_restaurant_details(restaurant_id: str) -> Restaurant:
    """Get full restaurant record by ID."""
    ...

Tools follow the same pattern across verticals: search, get_details, list_<dimension>, find_by_<dimension>, catalog_stats.

Transport

The spike runs the MCP server over stdio — the simplest transport, works locally and with Claude Desktop.

For production, the platform will run over HTTP/SSE (or the newer streamable HTTP transport) so remote agents can connect. The spike's local-only constraint is a known limitation.

MCP Config (Claude Desktop)

{
  "mcpServers": {
    "luxury-dmc": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/crawlers", "python", "crawler.py", "serve"]
    }
  }
}

How Our Agents Consume This

Our agents (Agent Architecture) call the MCP server through an MCP client. The orchestrator's tool cascade does NOT include the intelligence MCP directly — the Research Agents do, scoped to their domain.

Example: the Dining Research Agent might call search_restaurant(city="Tokyo", cuisine="sushi") to enrich a brief before returning results to the orchestrator.

Versioning

MCP tools are versioned implicitly by the Pydantic schema. When a tool's signature changes, it's a breaking change. Add new tools; don't break existing ones.

Marchay Platform Documentation