Skip to main content

A more ergonomic interface for MCP servers

Project description

FastMCP 🚀

PyPI - Version Tests License

The fast, Pythonic way to build MCP servers

Model Context Protocol (MCP) servers are a new, standardized way to provide context and tools to your LLMs, and FastMCP makes building MCP servers simple and intuitive. Create tools, expose resources, and define prompts with clean, Pythonic code:

# demo.py

from fastmcp import FastMCP


mcp = FastMCP("Demo 🚀")


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

That's it! Give Claude access to the server by running:

fastmcp install demo.py

FastMCP handles all the complex protocol details and server management, so you can focus on building great tools. It's designed to be high-level and Pythonic - in most cases, decorating a function is all you need.

Key features:

  • Fast: High-level interface means less code and faster development
  • Simple: Build MCP servers with minimal boilerplate
  • Pythonic: Feels natural to Python developers
  • Complete*: FastMCP aims to provide a full implementation of the core MCP specification

(*emphasis on aims)

🚨 🚧 🏗️ FastMCP is under active development, as is the MCP specification itself. Core features are working but some advanced capabilities are still in progress.

Table of Contents

Installation

# We strongly recommend installing with uv
brew install uv  # on macOS
uv pip install fastmcp

Or with pip:

pip install fastmcp

Quickstart

Let's create a simple MCP server that exposes a calculator tool and some data:

from fastmcp import FastMCP


# Create an MCP server
mcp = FastMCP("Demo")


# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b


# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """Get a personalized greeting"""
    return f"Hello, {name}!"

To use this server, you have two options:

  1. Install it in Claude Desktop:
fastmcp install server.py
  1. Test it with the MCP Inspector:
fastmcp dev server.py

MCP Inspector

What is MCP?

The Model Context Protocol (MCP) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can:

  • Expose data through Resources (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
  • Provide functionality through Tools (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
  • Define interaction patterns through Prompts (reusable templates for LLM interactions)
  • And more!

There is a low-level Python SDK available for implementing the protocol directly, but FastMCP aims to make that easier by providing a high-level, Pythonic interface.

Core Concepts

Server

The FastMCP server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:

from fastmcp import FastMCP

# Create a named server
mcp = FastMCP("My App")

# Configure host/port for HTTP transport (optional)
mcp = FastMCP("My App", host="localhost", port=8000)

Note: All of the following code examples assume you've created a FastMCP server instance called mcp, as shown above.

Resources

Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects. Some examples:

  • File contents
  • Database schemas
  • API responses
  • System information

Resources can be static:

@mcp.resource("config://app")
def get_config() -> str:
    """Static configuration data"""
    return "App configuration here"

Or dynamic with parameters (FastMCP automatically handles these as MCP templates):

@mcp.resource("users://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
    """Dynamic user data"""
    return f"Profile data for user {user_id}"

Tools

Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects. They're similar to POST endpoints in a REST API.

Simple calculation example:

@mcp.tool()
def calculate_bmi(weight_kg: float, height_m: float) -> float:
    """Calculate BMI given weight in kg and height in meters"""
    return weight_kg / (height_m ** 2)

HTTP request example:

import httpx

@mcp.tool()
async def fetch_weather(city: str) -> str:
    """Fetch current weather for a city"""
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"https://api.weather.com/{city}"
        )
        return response.text

Prompts

Prompts are reusable templates that help LLMs interact with your server effectively. They're like "best practices" encoded into your server. A prompt can be as simple as a string:

@mcp.prompt()
def review_code(code: str) -> str:
    return f"Please review this code:\n\n{code}"

Or a more structured sequence of messages:

from fastmcp.prompts.base import UserMessage, AssistantMessage

@mcp.prompt()
def debug_error(error: str) -> list[Message]:
    return [
        UserMessage("I'm seeing this error:"),
        UserMessage(error),
        AssistantMessage("I'll help debug that. What have you tried so far?")
    ]

Images

FastMCP provides an Image class that automatically handles image data in your server:

from fastmcp import FastMCP, Image
from PIL import Image as PILImage

@mcp.tool()
def create_thumbnail(image_path: str) -> Image:
    """Create a thumbnail from an image"""
    img = PILImage.open(image_path)
    img.thumbnail((100, 100))
    
    # FastMCP automatically handles conversion and MIME types
    return Image(data=img.tobytes(), format="png")

@mcp.tool()
def load_image(path: str) -> Image:
    """Load an image from disk"""
    # FastMCP handles reading and format detection
    return Image(path=path)

Images can be used as the result of both tools and resources.

Context

The Context object gives your tools and resources access to MCP capabilities. To use it, add a parameter annotated with fastmcp.Context:

from fastmcp import FastMCP, Context

@mcp.tool()
async def long_task(files: list[str], ctx: Context) -> str:
    """Process multiple files with progress tracking"""
    for i, file in enumerate(files):
        ctx.info(f"Processing {file}")
        await ctx.report_progress(i, len(files))
        
        # Read another resource if needed
        data = await ctx.read_resource(f"file://{file}")
        
    return "Processing complete"

The Context object provides:

  • Progress reporting through report_progress()
  • Logging via debug(), info(), warning(), and error()
  • Resource access through read_resource()
  • Request metadata via request_id and client_id

Deployment

The FastMCP CLI helps you develop and deploy MCP servers.

Note that for all deployment commands, you are expected to provide the fully qualified path to your server object. For example, if you have a file server.py that contains a FastMCP server named my_server, you would provide path/to/server.py:my_server.

If your server variable has one of the standard names (mcp, server, or app), you can omit the server name from the path and just provide the file: path/to/server.py.

Development

Test and debug your server with the MCP Inspector:

# Provide the fully qualified path to your server
fastmcp dev server.py:my_mcp_server

# Or just the file if your server is named 'mcp', 'server', or 'app'
fastmcp dev server.py

Your server is run in an isolated environment, so you'll need to indicate any dependencies with the --with flag. FastMCP is automatically included. If you are working on a uv project, you can use the --with-editable flag to mount your current directory:

# With additional packages
fastmcp dev server.py --with pandas --with numpy

# Using your project's dependencies and up-to-date code
fastmcp dev server.py --with-editable .

Environment Variables

The MCP Inspector runs servers in an isolated environment. Environment variables must be set through the Inspector UI and are not inherited from your system. The Inspector does not currently support setting environment variables via command line (see Issue #94).

Claude Desktop

Install your server in Claude Desktop:

# Basic usage (name is taken from your FastMCP instance)
fastmcp install server.py

# With a custom name
fastmcp install server.py --name "My Server"

# With dependencies
fastmcp install server.py --with pandas --with numpy

The server name in Claude will be:

  1. The --name parameter if provided
  2. The name from your FastMCP instance
  3. The filename if the server can't be imported

Environment Variables

Claude Desktop runs servers in an isolated environment. Environment variables from your system are NOT automatically available to the server - you must explicitly provide them during installation:

# Single env var
fastmcp install server.py -e API_KEY=abc123

# Multiple env vars
fastmcp install server.py -e API_KEY=abc123 -e OTHER_VAR=value

# Load from .env file
fastmcp install server.py -f .env

Environment variables persist across reinstalls and are only updated when new values are provided:

# First install
fastmcp install server.py -e FOO=bar -e BAZ=123

# Second install - FOO and BAZ are preserved
fastmcp install server.py -e NEW=value

# Third install - FOO gets new value, others preserved
fastmcp install server.py -e FOO=newvalue

Examples

Here are a few examples of FastMCP servers. For more, see the examples/ directory.

Echo Server

A simple server demonstrating resources, tools, and prompts:

from fastmcp import FastMCP

mcp = FastMCP("Echo")

@mcp.resource("echo://{message}")
def echo_resource(message: str) -> str:
    """Echo a message as a resource"""
    return f"Resource echo: {message}"

@mcp.tool()
def echo_tool(message: str) -> str:
    """Echo a message as a tool"""
    return f"Tool echo: {message}"

@mcp.prompt()
def echo_prompt(message: str) -> str:
    """Create an echo prompt"""
    return f"Please process this message: {message}"

SQLite Explorer

A more complex example showing database integration:

from fastmcp import FastMCP
import sqlite3

mcp = FastMCP("SQLite Explorer")

@mcp.resource("schema://main")
def get_schema() -> str:
    """Provide the database schema as a resource"""
    conn = sqlite3.connect("database.db")
    schema = conn.execute(
        "SELECT sql FROM sqlite_master WHERE type='table'"
    ).fetchall()
    return "\n".join(sql[0] for sql in schema if sql[0])

@mcp.tool()
def query_data(sql: str) -> str:
    """Execute SQL queries safely"""
    conn = sqlite3.connect("database.db")
    try:
        result = conn.execute(sql).fetchall()
        return "\n".join(str(row) for row in result)
    except Exception as e:
        return f"Error: {str(e)}"

@mcp.prompt()
def analyze_table(table: str) -> str:
    """Create a prompt template for analyzing tables"""
    return f"""Please analyze this database table:
Table: {table}
Schema: 
{get_schema()}

What insights can you provide about the structure and relationships?"""

Project details


Release history Release notifications | RSS feed

This version

0.3.2

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastmcp-0.3.2.tar.gz (772.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastmcp-0.3.2-py3-none-any.whl (33.6 kB view details)

Uploaded Python 3

File details

Details for the file fastmcp-0.3.2.tar.gz.

File metadata

  • Download URL: fastmcp-0.3.2.tar.gz
  • Upload date:
  • Size: 772.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.5.5

File hashes

Hashes for fastmcp-0.3.2.tar.gz
Algorithm Hash digest
SHA256 cc89583fd791c9d568d7f12c898ff484b48d84189a31858131c63b4e9593a866
MD5 822aca75bb7563bba648fb536625b74d
BLAKE2b-256 dcaac8f995e9ef642dbf882ccac1884b8630fa7baba6760db2fd934db62629f1

See more details on using hashes here.

File details

Details for the file fastmcp-0.3.2-py3-none-any.whl.

File metadata

  • Download URL: fastmcp-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 33.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.5.5

File hashes

Hashes for fastmcp-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 3a65adb574439a6106a42b15049c47472fcbcc6d64bf3a70bdc08ce8abc01551
MD5 198573907298ee0a518948e60849a144
BLAKE2b-256 8e40bf3820977b7df443c80dc4d3db1a20078d565c106b358c4a13ed3a612c8d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page