# 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

Canonical: https://theagenticweekly.com/tests/mcp-python-servers · Last verified: 2026-10-25 · Published: 2026-10-25 · Author: Agentic Weekly (operated independently from Texas, US) · Evidence: 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.

> 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.

## Result at a glance

Table: FastMCP 4.1.3 and the official MCP Python SDK 2.3.0 (server side) test record

| Field | Value |
|---|---|
| Result | Passed |
| Version tested | fastmcp 4.1.3; mcp 2.3.0 |
| Date and time | 2026-10-25, 22:38 to 22:39 CDT (America/Chicago) |
| Task | A 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 used | none (no language model involved) |
| Hardware | Linux 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 1 | cold start 643 ms; tools/list 120.8 ms (3 tools); 50 x add_numbers: median 1.2 ms, p95 2.2 ms |
| FastMCP, rep 2 | cold start 735 ms; tools/list 139.3 ms (3 tools); 50 x add_numbers: median 1.3 ms, p95 2.5 ms |
| FastMCP, rep 3 | cold 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 1 | cold 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 1 | cold 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 2 | cold 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 3 | cold 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

Table: Commands run, wall-clock time and exit code

| Step | Wall time | Exit code | Notes |
|---|---|---|---|
| Latency run: FastMCP 4.1.3, run 1 (cold) | n/a | 0 | bench-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 1 | n/a | 0 | bench-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 2 | n/a | 0 | bench-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 3 | n/a | 0 | bench-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 1 | n/a | 0 | bench-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 1 | n/a | 0 | bench-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 2 | n/a | 0 | bench-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 3 | n/a | 0 | bench-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.0 | n/a | 1 | ExceptionGroup: 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](https://theagenticweekly.com/methodology#testing-rig) for the hardware, the local model and the rules we follow, and the [test hub](https://theagenticweekly.com/tests) for every other test.

## Sources

- [FastMCP repository](https://github.com/jlowin/fastmcp) (fetched 2026-10-25)
- [MCP Python SDK repository](https://github.com/modelcontextprotocol/python-sdk) (fetched 2026-10-25)

## Related

- [All test logs](https://theagenticweekly.com/tests)
- [Methodology and testing rig](https://theagenticweekly.com/methodology#testing-rig)
- [Study: MCP server startup and call latency over stdio](https://theagenticweekly.com/research/mcp-servers-latency-and-failures)
- [FastMCP facts and sources](https://theagenticweekly.com/tools/fastmcp)

## How to cite

Agentic Weekly, "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", last updated 2026-10-25, https://theagenticweekly.com/tests/mcp-python-servers
