mcp-sentinel 0.1.0
Automated testing framework for MCP (Model Context Protocol) servers
Requires Python: >=3.10
Keywords: fuzz-testing, mcp, model-context-protocol, testing

<p align="center">
  <img src="assets/logo.svg" alt="MCPSentinel" width="120" height="120" />
</p>

<h1 align="center">MCPSentinel</h1>

<p align="center">
  Zero-config testing for MCP servers.<br/>
  Install. Point at your server. Get a full test report.
</p>

<p align="center">
  <a href="https://pypi.org/project/mcp-sentinel"><img src="https://img.shields.io/pypi/v/mcp-sentinel.svg" alt="PyPI" /></a>
  <img src="https://img.shields.io/badge/python-3.10%2B-green.svg" alt="Python" />
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-orange.svg" alt="License" /></a>
</p>

---

## Get Started

```bash
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

```bash
# 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 — `run` is the default subcommand and can be omitted.

---

## Other Commands

```bash
# 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:

```bash
mcpsentinel init
```

Creates `mcpsentinel.toml` — auto-discovered when present:

```toml
[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

```yaml
- 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](action.yml):

```yaml
- 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 strategies
- **`BaseChecker`** — add new evaluation logic
- **`BaseReporter`** — add new output formats

---

## Installation

```bash
pip install mcp-sentinel
```

**From source:**

```bash
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](https://github.com/Dev07-Harsh/mcp-sentinel).

```bash
git clone https://github.com/Dev07-Harsh/mcp-sentinel.git
cd mcp-sentinel
pip install -e ".[dev]"
pytest tests/unit
```

---

## Author

**Harsh Singh** — [GitHub](https://github.com/Dev07-Harsh)

## License

MIT License. See [LICENSE](LICENSE) for details.