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