datarekha

FastMCP — build MCP servers fast

A Pythonic framework that turns ordinary functions into MCP tools, resources, and prompts with simple decorators — so you can expose your own data and actions to any MCP client without writing protocol code by hand.

8 min read Intermediate Agentic AI Lesson 28 of 29

What you'll learn

  • What FastMCP adds on top of raw MCP — decorators that auto-generate the tool schema the model reads
  • The three primitives: tools (actions), resources (readable data), prompts (reusable templates)
  • How to run your server over stdio or HTTP and let Claude Desktop or an agent discover it

Before you start

MCP — the Model Context Protocol — is a standard so that any LLM client (Claude Desktop, an ADK agent, Cursor) can call external tools and read external data using the same wire format, regardless of who built them. If you have not read the MCP intro yet, start there.

FastMCP is a Python framework that sits on top of the official MCP SDK and removes the boilerplate. Instead of manually registering handlers and constructing JSON schemas, you decorate ordinary Python functions and FastMCP generates the schema, validates inputs, and speaks the protocol on your behalf. The result: your first working MCP server fits in about twenty lines.

Why decorators and type hints are the whole trick

When Claude (or any MCP client) connects to your server it asks: what tools do you have, and what arguments does each one take? The answer must be a precise JSON schema — field names, types, descriptions. Writing that schema by hand for every function is tedious and error-prone.

FastMCP solves this by reading your Python type hints and docstring at import time and synthesising the schema automatically. Your function signature is the contract the model reads. Change a parameter name or type hint, and the schema updates instantly. Add a sentence to the docstring, and the model sees a richer description immediately.

This is the core bet: a well-typed, well-documented Python function is already most of what a good tool schema needs.

The three primitives

MCP defines three kinds of things a server can expose:

PrimitivePurposeFastMCP decorator
ToolAn action the model can invoke — runs code, returns a result@mcp.tool
ResourceRead-only data the model (or client) can fetch — files, DB rows, configs@mcp.resource
PromptA reusable message template — lets the server ship canned system prompts@mcp.prompt

Most MCP servers you will build start with tools. Resources and prompts become useful once your server grows: resources let you expose structured data without tool overhead; prompts let you version your best system messages alongside the server code that uses them.

Building a minimal FastMCP server

Install with pip install fastmcp (see the current FastMCP docs for the exact version constraints).

from fastmcp import FastMCP

# Create the server — the name shows up in client UIs
mcp = FastMCP("my-tools")


@mcp.tool
def add(a: int, b: int) -> int:
    """Add two integers and return the sum."""
    return a + b


@mcp.tool
def lookup_order(order_id: str) -> dict:
    """Return status information for an order.

    Args:
        order_id: The unique order identifier (e.g. 'ORD-12345').
    """
    # Replace with your real database call
    return {"order_id": order_id, "status": "shipped", "eta": "2026-06-07"}


if __name__ == "__main__":
    mcp.run()  # defaults to stdio transport

That is a complete, runnable MCP server. The add tool exposes an a: int, b: int schema; the model cannot pass a string for a — FastMCP validates it. The docstrings become the tool descriptions the model reads when deciding whether to call a tool.

Exposing a resource

A resource is addressed by a URI. The client reads it; the model does not invoke it like a function.

@mcp.resource("config://app-settings")
def get_settings() -> dict:
    """Return the current application configuration."""
    return {"debug": False, "max_retries": 3, "region": "us-east-1"}

The URI scheme (config://) is arbitrary — choose something that makes sense for your domain. See the FastMCP docs for dynamic resource URIs that embed path parameters.

Adding a reusable prompt

@mcp.prompt
def support_system_prompt(customer_tier: str) -> str:
    """Return the system prompt for a support agent, tuned by customer tier."""
    if customer_tier == "enterprise":
        return "You are a senior support engineer with SLA: 1 h. Be concise."
    return "You are a friendly support agent. Resolve the issue in one reply."

Clients that support prompts can pull this template and inject it at the start of a conversation — keeping your prompt versions colocated with the code that implements them.

Transport: stdio vs HTTP

FastMCP supports two transports:

stdio — the server process communicates over stdin/stdout. This is the default (mcp.run()) and is what Claude Desktop uses when you add a server to its config. The client spawns your process; no port, no auth, no network.

HTTP (SSE or streamable HTTP) — the server listens on a port so remote clients can connect. Pass transport="http" (or transport="sse") and a port to mcp.run(). Check the current FastMCP docs for the exact call signature and authentication options, as these evolve with the spec.

if __name__ == "__main__":
    # For remote clients:
    mcp.run(transport="http", port=8000)

How Claude Desktop discovers and calls your tools

The diagram below shows the full path from your decorated functions to the model invoking them.

Your Python functions@mcp.tool@mcp.resource@mcp.promptFastMCP serverschema generationinput validationJSON-RPC / MCP wirestdio or HTTPMCP clientClaude Desktopagent / LLMCursor, etc.decoratescalls toolstype hints + docstring → auto-generated JSON schema the model reads

Decorated Python functions → FastMCP server (protocol plumbing) → MCP client invokes them

To wire up Claude Desktop, add an entry to its claude_desktop_config.json pointing at your server script:

{
  "mcpServers": {
    "my-tools": {
      "command": "python",
      "args": ["/absolute/path/to/server.py"]
    }
  }
}

Claude Desktop will spawn your server process on startup, call tools/list to discover what you expose, and then invoke individual tools during conversations exactly as it would invoke any built-in capability.

What you have now

A FastMCP server is a standard Python process. You can import your existing database clients, HTTP libraries, and business logic unchanged. FastMCP handles the protocol; you handle the domain logic. Because MCP is a vendor- neutral open standard, the same server works with Claude Desktop today, an ADK agent tomorrow, and whatever MCP-compatible client ships next quarter — write once, connect anywhere.

Quick check

0/3
Q1What does FastMCP use to automatically generate the JSON schema that the MCP client receives for a tool?
Q2You want to expose a static configuration object (no side effects, just readable data) via your MCP server. Which primitive is the right fit?
Q3Your team builds a FastMCP server that lets an agent update customer records in a CRM. A month later your company evaluates a different LLM client. Which statement is most accurate?

Practice this in an interview

All questions

Sign in to track your progress

Completed lessons, your XP, level, and streak save to your account — it's free and takes a few seconds.

Explore further

Related lessons

Skip to content