FastMCP 4.1.3 and the official MCP Python SDK 2.3.0 (server side) fastmcp 4.1.3; mcp 2.3.0: our test log

The same three-tool server written with FastMCP 4.1.3 and with the official MCP Python SDK 2.3.0 answered calls equally fast (about 1 ms); FastMCP started in 643 to 735 ms against 461 to 516 ms for the SDK on repeats.

Tested by us on 2026-10-25. Local open-weight model, not the vendor's hosted models. A smoke test on a CPU-only box, not a benchmark.

Result at a glance

FastMCP 4.1.3 and the official MCP Python SDK 2.3.0 (server side) test record
FieldValue
ResultPassed
Version testedfastmcp 4.1.3; mcp 2.3.0
Date and time2026-10-25, 22:38 to 22:39 CDT (America/Chicago)
TaskA small Python client written with the official MCP Python SDK (2.3.0) spawns the server as a child process over stdio, times the initialize handshake (cold start: spawn to initialize result), times one tools/list, then times 50 sequential tools/call requests (the count differs per test; this one used 50) and reports the median and 95th percentile. Numbers are milliseconds on the rig described on the methodology page.
Model usednone (no language model involved)
HardwareLinux x86_64 virtual machine (Debian 13), 8 vCPU (Intel Xeon, 1 thread per core), 15 GiB RAM, no GPU
FastMCP 4.1.3, run 1 (cold)cold start 1589 ms; tools/list 367.8 ms (3 tools); 50 x add_numbers: median 1.3 ms, p95 2.1 ms
FastMCP, rep 1cold start 643 ms; tools/list 120.8 ms (3 tools); 50 x add_numbers: median 1.2 ms, p95 2.2 ms
FastMCP, rep 2cold start 735 ms; tools/list 139.3 ms (3 tools); 50 x add_numbers: median 1.3 ms, p95 2.5 ms
FastMCP, rep 3cold start 645 ms; tools/list 127.3 ms (3 tools); 50 x add_numbers: median 1.3 ms, p95 2.2 ms
Official SDK MCPServer 2.3.0, run 1cold start 472 ms; tools/list 2.3 ms (3 tools); 50 x add_numbers: median 0.8 ms, p95 1.6 ms
Official SDK, rep 1cold start 461 ms; tools/list 1.8 ms (3 tools); 50 x add_numbers: median 0.7 ms, p95 1.3 ms
Official SDK, rep 2cold start 516 ms; tools/list 2.6 ms (3 tools); 50 x add_numbers: median 0.8 ms, p95 1.7 ms
Official SDK, rep 3cold start 463 ms; tools/list 2.4 ms (3 tools); 50 x add_numbers: median 0.9 ms, p95 1.7 ms

What we found

  • Warm repeats (3 each): FastMCP cold start [643, 735, 645] ms, official SDK [461, 516, 463] ms. The very first FastMCP run took 1589 ms (first import compiles bytecode), so the first-run number overstates real startup.
  • tools/list took about 129 ms on FastMCP against about 2.3 ms on the SDK, a difference you will never notice.
  • Both servers exposed the same three tools (add_numbers, echo, word_count) and returned correct results; call latency was about 1 ms at the median for both.
  • The official SDK's high-level server class moved: a server written against the 1.x import path (from mcp.server.fastmcp import FastMCP) failed to start under SDK 2.3.0 with 'ExceptionGroup: unhandled errors in a TaskGroup'. The 2.x equivalent is mcp.server.mcpserver.MCPServer, which is what the passing run uses. We saw the failure and did not dig into the cause further.

What we ran, step by step

Commands run, wall-clock time and exit code
StepWall timeExit codeNotes
Latency run: FastMCP 4.1.3, run 1 (cold)n/a0bench-fastmcp 4.1.3 (protocol 2025-11-25). cold start 1589 ms; tools/list 367.8 ms (3 tools); 50 x add_numbers: median 1.3 ms, p95 2.1 ms. Load 1.51.
Latency run: FastMCP, rep 1n/a0bench-fastmcp 4.1.3 (protocol 2025-11-25). cold start 643 ms; tools/list 120.8 ms (3 tools); 50 x add_numbers: median 1.2 ms, p95 2.2 ms. Load 1.47.
Latency run: FastMCP, rep 2n/a0bench-fastmcp 4.1.3 (protocol 2025-11-25). cold start 735 ms; tools/list 139.3 ms (3 tools); 50 x add_numbers: median 1.3 ms, p95 2.5 ms. Load 1.43.
Latency run: FastMCP, rep 3n/a0bench-fastmcp 4.1.3 (protocol 2025-11-25). cold start 645 ms; tools/list 127.3 ms (3 tools); 50 x add_numbers: median 1.3 ms, p95 2.2 ms. Load 1.43.
Latency run: Official SDK MCPServer 2.3.0, run 1n/a0bench-official (protocol 2025-11-25). cold start 472 ms; tools/list 2.3 ms (3 tools); 50 x add_numbers: median 0.8 ms, p95 1.6 ms. Load 1.47.
Latency run: Official SDK, rep 1n/a0bench-official (protocol 2025-11-25). cold start 461 ms; tools/list 1.8 ms (3 tools); 50 x add_numbers: median 0.7 ms, p95 1.3 ms. Load 1.43.
Latency run: Official SDK, rep 2n/a0bench-official (protocol 2025-11-25). cold start 516 ms; tools/list 2.6 ms (3 tools); 50 x add_numbers: median 0.8 ms, p95 1.7 ms. Load 1.43.
Latency run: Official SDK, rep 3n/a0bench-official (protocol 2025-11-25). cold start 463 ms; tools/list 2.4 ms (3 tools); 50 x add_numbers: median 0.9 ms, p95 1.7 ms. Load 1.40.
Negative result: 1.x import path under SDK 2.3.0n/a1ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception). Load 1.56.
Exact commands (paths shortened)
# Latency run: FastMCP 4.1.3, run 1 (cold)
work/py/fastmcp/bin/python servers/fastmcp_server.py

# Latency run: FastMCP, rep 1
work/py/fastmcp/bin/python servers/fastmcp_server.py

# Latency run: FastMCP, rep 2
work/py/fastmcp/bin/python servers/fastmcp_server.py

# Latency run: FastMCP, rep 3
work/py/fastmcp/bin/python servers/fastmcp_server.py

# Latency run: Official SDK MCPServer 2.3.0, run 1
work/py/mcp-python-sdk/bin/python servers/official_server_v2.py

# Latency run: Official SDK, rep 1
work/py/mcp-python-sdk/bin/python servers/official_server_v2.py

# Latency run: Official SDK, rep 2
work/py/mcp-python-sdk/bin/python servers/official_server_v2.py

# Latency run: Official SDK, rep 3
work/py/mcp-python-sdk/bin/python servers/official_server_v2.py

# Negative result: 1.x import path under SDK 2.3.0
work/py/mcp-python-sdk/bin/python servers/official_server.py

Raw output (excerpts)

Output of the timed call (FastMCP 4.1.3, run 1 (cold)), first 300 characters
add_numbers({"a": 17, "b": 25})
42
servers/official_server_v2.py, the SDK server used for the numbers
from mcp.server.mcpserver import MCPServer
mcp = MCPServer("bench-official")
@mcp.tool()
def add_numbers(a: int, b: int) -> int:
    """Add two integers."""
    return a + b
@mcp.tool()
def echo(message: str) -> str:
    """Echo a message."""
    return message
@mcp.tool()
def word_count(text: str) -> int:
    """Count words."""
    return len(text.split())
if __name__ == "__main__":
    mcp.run(transport="stdio")
servers/fastmcp_server.py, the FastMCP server
from fastmcp import FastMCP
mcp = FastMCP("bench-fastmcp")
@mcp.tool
def add_numbers(a: int, b: int) -> int:
    """Add two integers."""
    return a + b
@mcp.tool
def echo(message: str) -> str:
    """Echo a message."""
    return message
@mcp.tool
def word_count(text: str) -> int:
    """Count words."""
    return len(text.split())
if __name__ == "__main__":
    mcp.run(transport="stdio", show_banner=False)

Gotchas and things that broke

  • Copy-pasted 1.x examples can fail at import or start under the 2.x SDK; pin the SDK version in the examples you publish.
  • FastMCP and the official SDK now share version 2.3.0 of the underlying mcp package in the same environment (FastMCP's install listed mcp 2.3.0 and mcp-types 2.3.0).

What we did not test

  • Remote (HTTP) transport, authentication and concurrent clients: only local stdio with one client was measured.
  • Large payloads: calls used tiny inputs, so these latencies are protocol and process overhead, not throughput.
  • Anything about answer quality: no model was involved in the latency numbers.
  • These are single smoke-test runs; it is not a benchmark. The machine was shared with other jobs.

Reproduce it

Versions change. These commands install whatever is latest on the day you run them unless a version is pinned, so expect different results later. The version we measured is in the table above.

uv venv -p 3.13 .venv && VIRTUAL_ENV=.venv uv pip install fastmcp mcp
# save the two server scripts (above) and any MCP client; we used the official Python SDK client over stdio

How to read this test

Every number on this page was measured on this one machine, which also ran other jobs, so timings are indicative and vary run to run. A pass means our small task worked once or as stated, a fail means it did not work as we ran it; neither says how the tool behaves with a vendor's frontier model, on a GPU, or at scale. Where a tool could not run without an account or a GPU, we say so instead of guessing.

See the testing rig for the hardware, the local model and the rules we follow, and the test hub for every other test.

  • GitHub MCP Server: GitHub MCP Server 2.0.3 started over stdio in a median 266 ms and listed 46 tools in a median 15 ms; we did not make any authenticated call.
  • MCP Everything (reference) server: MCP Everything (reference) server answered over stdio in 356 ms cold (v1.0.0, Node 20) and 252 ms (v2.0.1, Node 24); median call 0.5 to 0.4 ms.
  • MCP Fetch server: The MCP Fetch server 2026.10.24 refused to fetch a local test page by default (a deliberate loopback block); with --allow-private-ips it fetched it in 698.3 ms median.
  • MCP Filesystem server: MCP Filesystem server answered over stdio in 279 ms cold (v1.0.0, Node 20) and 187 ms (v2.0.1, Node 24); median call 0.8 to 1.0 ms.
  • MCP Git server: The MCP Git server 2026.10.19 started in 512 ms, listed 12 tools and answered git_status in 3.2 ms median.
  • MCP Inspector (CLI mode): MCP Inspector listed the filesystem server's 14 tools from the command line on both 0.15.0 (Node 20) and 2.12.0 (Node 24) in under a second; the 2.x install is smaller.

All test logs · How we test

Sources

Markdown version for agents: /tests/mcp-python-servers.md