Skip to content
fastmcp-patterns logo

FastMCP Patterns

fastmcp-patterns

FastMCP server patterns for building MCP servers. Use when implementing MCP tools, resources, or server configuration.

SKILL.md

Full skill instructions

FastMCP Patterns

Server Setup with Lifespan

from contextlib import asynccontextmanager
from mcp.server.fastmcp import FastMCP

@asynccontextmanager
async def lifespan(server: FastMCP):
    """Initialize resources on startup, cleanup on shutdown."""
    driver = create_neo4j_driver(config)
    driver.verify_connectivity()

    try:
        yield {"driver": driver, "config": config}
    finally:
        driver.close()

mcp = FastMCP(
    "requirements-graphrag-mcp",
    lifespan=lifespan,
)

Tool Registration

Basic Tool with Pydantic Validation

from pydantic import BaseModel, Field

class SearchInput(BaseModel):
    query: str = Field(..., description="Search query text")
    limit: int = Field(default=10, ge=1, le=100, description="Max results")

@mcp.tool()
async def semantic_search(input: SearchInput) -> list[dict]:
    """Search articles using semantic similarity."""
    driver = mcp.state["driver"]
    return await execute_vector_search(driver, input.query, input.limit)

Tool with Annotations

from mcp.server.fastmcp import Context

@mcp.tool(
    annotations={
        "readOnlyHint": True,
        "openWorldHint": False,
    }
)
async def get_schema(ctx: Context) -> dict:
    """Get database schema. Read-only operation."""
    driver = ctx.state["driver"]
    return await fetch_schema(driver)

Resource Registration

@mcp.resource("schema://database")
async def database_schema() -> str:
    """Expose database schema as a resource."""
    driver = mcp.state["driver"]
    schema = await fetch_schema(driver)
    return json.dumps(schema, indent=2)

Error Handling Pattern

from requirements_graphrag_api.exceptions import (
    Neo4jConnectionError,
    QueryExecutionError,
)

@mcp.tool()
async def execute_cypher(query: str) -> dict:
    """Execute a Cypher query."""
    try:
        driver = mcp.state["driver"]
        return await run_query(driver, query)
    except Neo4jConnectionError as e:
        return {"error": "Database connection failed", "details": str(e)}
    except QueryExecutionError as e:
        return {"error": "Query execution failed", "details": str(e)}

Configuration Pattern

from dataclasses import dataclass

@dataclass(frozen=True, slots=True)
class AppConfig:
    neo4j_uri: str
    neo4j_username: str
    neo4j_password: str
    neo4j_database: str = "neo4j"
    neo4j_max_connection_pool_size: int = 5

    @classmethod
    def from_env(cls) -> "AppConfig":
        return cls(
            neo4j_uri=os.environ["NEO4J_URI"],
            neo4j_username=os.environ["NEO4J_USERNAME"],
            neo4j_password=os.environ["NEO4J_PASSWORD"],
            neo4j_database=os.environ.get("NEO4J_DATABASE", "neo4j"),
        )

Entry Point

# src/​requirements_graphrag_api/​__main__.py
from requirements_graphrag_api.server import mcp

def main():
    mcp.run()

if __name__ == "__main__":
    main()

pyproject.toml Script

[project.scripts]
requirements-graphrag-api = "requirements_graphrag_api.__main__:main"