Getting started¶
Install¶
toolproof needs Python 3.11 or newer. The package is called mcp-toolproof on PyPI; the command and the Python import are both toolproof.
Install it next to your server
If your server is written in Python, install toolproof into the same virtual environment, so that python my_server.py inside toolproof finds your server's dependencies. For servers in other languages it doesn't matter; see Servers in other languages.
1. Look at your server¶
Everything after -- is the command that starts your server. toolproof starts it, runs the MCP handshake, lists the tools, resources and prompts, and runs the static checks. For a server that is already running over HTTP:
Add --json to get the full tool definitions, including input schemas, as JSON.
2. Fuzz it¶
Before writing any tests, let toolproof try to break the server:
This calls every tool with generated inputs, both valid and invalid, and reports crashes, hangs, internal errors and similar problems. See Fuzzing before running it against a server whose tools change real data.
3. Write tests¶
Create toolproof.yaml next to your server:
server:
command: ["python", "my_server.py"]
tests:
- name: toronto weather
tool: get_weather
args: { city: Toronto }
expect:
is_error: false
contains: "Toronto"
jsonpath:
"$.temp_c": { type: number, min: -60, max: 60 }
max_latency_ms: 2000
- name: rejects empty city
tool: get_weather
args: { city: "" }
expect: { is_error: true }
Run it:
run exits with 0 when everything passes and 1 when anything fails, so it works as a CI step as is. See Configuration for every option and Assertions for what expect can check.
4. Add it to CI¶
name: toolproof
on: [push, pull_request]
jobs:
toolproof:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.12"
- run: pip install -e . mcp-toolproof
- run: toolproof run toolproof.yaml --junit report.xml
- uses: actions/upload-artifact@v7
if: always()
with:
name: toolproof-report
path: report.xml
More in Running in CI.
Try it on the examples¶
The repository ships a working server and a deliberately broken one: