Automated testing framework for MCP (Model Context Protocol) servers
Project description
MCPSentinel
Zero-config testing for MCP servers.
Install. Point at your server. Get a full test report.
Get Started
pip install mcp-sentinel
mcpsentinel "python my_server.py"
That's it. No config file. No test code to write. MCPSentinel connects to your server, discovers every tool, generates hundreds of test cases, and prints the results:
MCPSentinel v0.1.0
Server: python my_server.py
Transport: stdio (auto-detected)
Modes: schema, fuzz
Output: terminal
Discovering tools... 3 tools found
Running 47 tests ━━━━━━━━━━━━━━━━━━━━━━ 100%
Results: 44 passed, 3 failed, 0 errors
What It Tests
MCPSentinel runs two test modes by default:
Schema validation — sends valid inputs, omits required fields one at a time, tests enum boundaries, type mismatches.
Adversarial fuzzing — SQL injection, XSS, path traversal, command injection, null bytes, format strings, oversized payloads, unicode stress tests. Every fuzz test expects the server to not crash — returning an error is fine.
Common Usage
# Test your server (zero config)
mcpsentinel "python my_server.py"
# Schema tests only
mcpsentinel "python server.py" -m schema
# HTML report
mcpsentinel "python server.py" -f html
# SSE server (transport auto-detected from URL)
mcpsentinel "http://localhost:8001/sse"
# Streamable HTTP
mcpsentinel "http://localhost:8001/mcp"
# Test specific tools
mcpsentinel "python server.py" --tools "search_*"
# Exclude admin tools
mcpsentinel "python server.py" --exclude "admin_*"
# Reproducible fuzz run
mcpsentinel "python server.py" --fuzz-seed 42
# Docker container
mcpsentinel "docker exec -i my-container python -m my_mcp_server"
# Re-run only previously failed tests
mcpsentinel "python server.py" --retry-failed
# Watch mode — re-run on file changes
mcpsentinel "python server.py" --watch
# Multiple report formats
mcpsentinel "python server.py" -f terminal -f json -f html -f junit
# CI-friendly: quiet mode + JUnit output
mcpsentinel "python server.py" -q -f junit -o ./test-results
mcpsentinel run "..."still works —runis the default subcommand and can be omitted.
Other Commands
# Discover tools on a server
mcpsentinel discover "python my_server.py"
# Generate a config file (optional)
mcpsentinel init
Options
| Option | Short | Default | Description |
|---|---|---|---|
--transport |
-t |
auto | Transport: stdio, sse, or streamable-http |
--mode |
-m |
schema,fuzz |
Test modes: schema, fuzz |
--config |
-c |
— | Path to mcpsentinel.toml |
--format |
-f |
terminal |
Output: terminal, json, html, junit |
--output-dir |
-o |
./reports |
Report output directory |
--tools |
— | Glob pattern to include tools | |
--exclude |
— | Glob pattern to exclude tools | |
--fuzz-seed |
— | Seed for reproducible fuzz tests | |
--timeout |
30 |
Timeout per tool call (seconds) | |
--concurrency |
1 |
Parallel test executions | |
--rate-limit |
0 |
Min delay between calls (ms) | |
--retry-failed |
Re-run only previously failed tests | ||
--watch |
-w |
Watch for file changes and re-run | |
--watch-path |
. |
Directory to watch | |
--verbose |
-v |
Show all call logs in real-time | |
--quiet |
-q |
Suppress terminal output |
Configuration (Optional)
MCPSentinel works without any config. If you want persistent settings:
mcpsentinel init
Creates mcpsentinel.toml — auto-discovered when present:
[server]
command = "python"
args = ["my_server.py"]
transport = "stdio"
startup_timeout = 30
[modes]
schema = true
fuzz = true
[fuzz]
seed = 42
[execution]
timeout_per_tool = 30
# tools = "search_*"
# exclude = "internal_*"
[reporting]
formats = ["terminal", "json"]
output_dir = "./reports"
verbose = false
quiet = false
CLI flags always override config file values.
Report Formats
| Format | Description |
|---|---|
| Terminal | Rich colored output with summary tables and failure details |
| HTML | Self-contained single-file report with dark/light theme, search, keyboard shortcuts |
| JSON | Full machine-readable report with every test case, call log, and timing data |
| JUnit XML | CI-compatible format for GitHub Actions, Jenkins, GitLab CI |
CI/CD Integration
GitHub Actions
- name: Test MCP Server
run: |
pip install mcp-sentinel
mcpsentinel "python my_server.py" -q -f junit -o ./test-results
- name: Publish Test Results
uses: dorny/test-reporter@v1
if: always()
with:
name: MCP Server Tests
path: test-results/mcpsentinel-report-*.xml
reporter: java-junit
Or use the MCPSentinel GitHub Action:
- uses: Dev07-Harsh/mcp-sentinel@main
with:
server-command: "python my_server.py"
Exit Codes
| Code | Meaning |
|---|---|
0 |
All tests passed |
1 |
One or more tests failed |
2 |
Configuration error |
3 |
No tools found on server |
Test Modes
Schema Mode
| Test Type | What It Does |
|---|---|
valid_minimal |
Sends only required parameters with valid types |
valid_full |
Sends all parameters (required + optional) |
defaults_only |
Sends only required params, omits optional |
required_missing_* |
Omits each required parameter one at a time |
enum_* |
Tests each declared enum value |
boundary_* |
Tests min/max for numeric parameters |
Fuzz Mode
| Test Type | What It Sends |
|---|---|
type_mismatch |
Wrong types for every parameter |
boundary_violation |
Values beyond declared min/max |
null_injection |
null for every parameter |
empty_value |
Empty strings, arrays, objects |
invalid_enum |
Values outside declared enum sets |
extra_fields |
Unexpected additional parameters |
injection_* |
SQL, command, path traversal, XSS, format strings |
encoding_* |
Unicode stress, newline/tab injection |
overflow |
100,000-character strings |
Architecture
src/mcpsentinel/
├── cli/ # Typer CLI (run, discover, init)
├── client/ # MCP protocol client (stdio, SSE, streamable-http)
├── config/ # TOML + CLI config loading
├── discovery/ # Tool discovery and schema analysis
├── generation/ # Test case generators (schema + fuzz)
├── execution/ # Test runner and tool executor
├── evaluation/ # Result checkers (schema + fuzz)
├── reporting/ # Terminal, HTML, JSON, JUnit reporters
├── logging/ # Per-call trace recording
├── models/ # Pydantic data models
└── errors.py # Error hierarchy
Extension Points
BaseGenerator— add new test generation strategiesBaseChecker— add new evaluation logicBaseReporter— add new output formats
Installation
pip install mcp-sentinel
From source:
git clone https://github.com/Dev07-Harsh/mcp-sentinel.git
cd mcp-sentinel
pip install -e ".[dev]"
Requirements: Python 3.10+
Contributing
Contributions welcome. Open an issue or pull request on GitHub.
git clone https://github.com/Dev07-Harsh/mcp-sentinel.git
cd mcp-sentinel
pip install -e ".[dev]"
pytest tests/unit
Author
Harsh Singh — GitHub
License
MIT License. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_sentinel-0.1.0.tar.gz.
File metadata
- Download URL: mcp_sentinel-0.1.0.tar.gz
- Upload date:
- Size: 66.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a504e40f6e02e48003dd8fc78116300ef54da1e06807d44a8eb71fe75ca2b070
|
|
| MD5 |
0d61aa95eaae4836892c7ba075647279
|
|
| BLAKE2b-256 |
b68bb2684661e5d031ee0334f15e6fdf86c4ffe81c262abbf2118256f0b0168c
|
Provenance
The following attestation bundles were made for mcp_sentinel-0.1.0.tar.gz:
Publisher:
publish.yml on Dev07-Harsh/mcp-sentinel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_sentinel-0.1.0.tar.gz -
Subject digest:
a504e40f6e02e48003dd8fc78116300ef54da1e06807d44a8eb71fe75ca2b070 - Sigstore transparency entry: 945704044
- Sigstore integration time:
-
Permalink:
Dev07-Harsh/mcp-sentinel@b115a651184aa5bc4881753ae47a155dff70a08f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Dev07-Harsh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b115a651184aa5bc4881753ae47a155dff70a08f -
Trigger Event:
release
-
Statement type:
File details
Details for the file mcp_sentinel-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mcp_sentinel-0.1.0-py3-none-any.whl
- Upload date:
- Size: 72.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
220b1e35075bacbef4dfe50719237e34b218df7db9c780e36667803324d80289
|
|
| MD5 |
7faec564176932302c6594bc600cf79d
|
|
| BLAKE2b-256 |
d19cdca116d82424c89977b870ea73e522a5efffdcb83849609c26a19d4d1786
|
Provenance
The following attestation bundles were made for mcp_sentinel-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Dev07-Harsh/mcp-sentinel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_sentinel-0.1.0-py3-none-any.whl -
Subject digest:
220b1e35075bacbef4dfe50719237e34b218df7db9c780e36667803324d80289 - Sigstore transparency entry: 945704073
- Sigstore integration time:
-
Permalink:
Dev07-Harsh/mcp-sentinel@b115a651184aa5bc4881753ae47a155dff70a08f -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Dev07-Harsh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b115a651184aa5bc4881753ae47a155dff70a08f -
Trigger Event:
release
-
Statement type: