Testing FastMCP Servers

FastMCP includes a built-in client for testing without spawning subprocesses.

In-Memory Testing

The simplest pattern - connect a Client directly to a FastMCP instance:

import pytest
from fastmcp import Client
from my_server import mcp


@pytest.mark.asyncio
async def test_add_tool():
    async with Client(mcp) as client:
        result = await client.call_tool("add", {"a": 2, "b": 3})
        assert result[0].text == "5"


@pytest.mark.asyncio
async def test_list_tools():
    async with Client(mcp) as client:
        tools = await client.list_tools()
        tool_names = [t.name for t in tools]
        assert "add" in tool_names
        assert "search" in tool_names


@pytest.mark.asyncio
async def test_read_resource():
    async with Client(mcp) as client:
        resource = await client.read_resource("config://settings")
        # resource content is a list of ResourceContent
        assert "version" in resource[0].text


@pytest.mark.asyncio
async def test_get_prompt():
    async with Client(mcp) as client:
        prompt = await client.get_prompt("analyze", args={"data": "test data"})
        assert "test data" in prompt.messages[0].content.text

Testing with Handlers

Capture server messages and sampling requests:

@pytest.mark.asyncio
async def test_with_message_handler():
    messages = []

    def on_message(level, content):
        messages.append((level, content))

    async with Client(mcp, message_handler=on_message) as client:
        await client.call_tool("search", {"query": "test"})
        assert any("Searching" in msg for _, msg in messages)

Subprocess Testing

Test the actual stdio transport:

from fastmcp import Client
from fastmcp.client.transports import PythonStdioTransport


@pytest.mark.asyncio
async def test_stdio_transport():
    transport = PythonStdioTransport(
        command="uv",
        args=["run", "python", "server.py"],
    )
    async with Client(transport) as client:
        result = await client.call_tool("add", {"a": 1, "b": 2})
        assert result[0].text == "3"

HTTP Testing

from fastmcp.utilities.tests import run_server_in_process


def start_server(host, port):
    from my_server import mcp
    import asyncio
    asyncio.run(mcp.run_http_async(host=host, port=port, transport="sse"))


@pytest.mark.asyncio
async def test_http_server():
    with run_server_in_process(start_server, provide_host_and_port=True) as url:
        async with Client(url) as client:
            tools = await client.list_tools()
            assert len(tools) > 0

Test Setup

# pyproject.toml
[project.optional-dependencies]
dev = ["pytest", "pytest-asyncio"]
uv run pytest tests/ -v