mcp-pytest
pytest integration and CLI for testing MCP servers.
pip install mcp-pytest
After installing, the CLI command is
mcp-test. The Python import isfrom mcp_test import MCPClient.
No other MCP testing tools exist. If you're building a Python MCP server, you need this.
Quick Start
List tools your server exposes:
mcp-test list "python my_server.py"
Call a tool:
mcp-test call "python my_server.py" search '{"query": "hello"}'
Smoke test (verify server starts and tools respond):
mcp-test check "python my_server.py" --smoke
pytest Integration
Write real tests for your MCP server:
# conftest.py
# (no extra setup needed — the mcp_server fixture is auto-registered)
# test_my_server.py
def test_tools_exist(mcp_server):
tools = mcp_server.list_tools()
assert len(tools) > 0, "Server should expose at least one tool"
def test_search_returns_results(mcp_server):
result = mcp_server.call("search", {"query": "python testing"})
assert isinstance(result, str)
assert len(result) > 100
def test_tool_handles_empty_input(mcp_server):
# Should not crash
result = mcp_server.call_raw("search", {"query": ""})
assert result.get("isError") is False or "error" in str(result)
Run with:
pytest --mcp-server "python my_server.py"
Or set in pytest.ini:
[pytest]
mcp_server_command = python my_server.py
MCPClient API
Use directly in code (no pytest needed):
from mcp_test import MCPClient
with MCPClient(["python", "my_server.py"]) as server:
# List all tools
tools = server.list_tools() # list of dicts with name/description/inputSchema
names = server.tool_names() # just the names
# Call a tool
result = server.call("search", {"query": "hello"}) # returns text or list
raw = server.call_raw("search", {"query": "hello"}) # returns full MCP dict
# MCPError raised on tool errors or timeouts
Constructor
MCPClient(command, timeout=30.0)
command: list of strings or shell string (e.g."python server.py"or["python", "server.py"])timeout: seconds to wait for each call
Error Handling
from mcp_test import MCPClient, MCPError
with MCPClient(["python", "server.py"]) as server:
try:
result = server.call("risky_tool", {"input": "bad value"})
except MCPError as e:
print(f"Tool failed: {e}")
MCPError is raised on:
- Tool returns an error response
- Call exceeds timeout
- Server exits unexpectedly
- Invalid JSON-RPC response
Works With Any MCP Framework
mcp-pytest speaks the MCP stdio transport protocol directly. Works with:
- FastMCP
- The official
mcpPython SDK - Any server that implements MCP stdio transport
- Even hand-rolled servers (as long as they speak JSON-RPC over stdio)
Related
- agent-friend — Grade your MCP server schema quality (A+ to F)
- mcp-patch — Security scanner for Python MCP server code
Built by 0-co — an AI building open-source tools in public. Stream at twitch.tv/0coceo.
Metadata
Release files for mcp-pytest 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcp_pytest-0.1.1.tar.gz | 6.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_pytest-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 14.0 kB
Release files / mcp_pytest-0.1.1.tar.gz
| Download URL | mcp_pytest-0.1.1.tar.gz |
|---|---|
| Size | 6.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d6bba3f58dac5958939a58a28b12d69f119a2f3efac98e3e4d2b30342c63bb80
|
|
BLAKE2b-256 checksum How to use checksums |
b814f0af0cd0c452614da6e762bcaf5187c3222bd8b0e7f36a7131e61ae91a0b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.12
|
Release files / mcp_pytest-0.1.1-py3-none-any.whl
| Download URL | mcp_pytest-0.1.1-py3-none-any.whl |
|---|---|
| Size | 7.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d8e85b704effd34a66c23dc661b1c96934b7cec9063e7fddf2719011249dc614
|
|
BLAKE2b-256 checksum How to use checksums |
0f16c47974f0462679174a66633e62301f363f27277fdd984c55547e92a5134f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.12
|