io.github.dbsectrainer/mcp-eval-runner
A standardized testing harness for MCP servers and agent workflows
Open source Open in the app JSON README (API)
About
A standardized testing harness for MCP servers and agent workflows
Details
- Kind
- MCP servers
- Topic
- Developer tools
- Publisher
- dbsectrainer
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 1.0.0
- Open pull requests
- 15
- Last push
- 2026-05-18T10:17:48Z
- Repository state
- ativo
- Language
- TypeScript
- License
- MIT
- Added
- 2026-08-29 03:02:41
- Updated
- 2026-08-29 03:02:41
- Origin id
io.github.dbsectrainer/mcp-eval-runner
README
# MCP Eval Runner
npm `mcp-eval-runner` package
A standardized testing harness for MCP servers and agent workflows. Define test cases as YAML fixtures (steps → expected tool calls → expected outputs), run regression suites directly from your MCP client, and get pass/fail results with diffs — without leaving Claude Code or Cursor.
[Tool reference](#tools) | [Configuration](#configuration) | [Fixture format](#fixture-format) | [Contributing](#contributing) | [Troubleshooting](#troubleshooting) | [Design principles](#design-principles)
## Key features
- **YAML fixtures**: Test cases are plain files in version control — diffable, reviewable, and shareable.
- **Two execution modes**: Live mode spawns a real MCP server and calls tools via stdio; simulation mode runs assertions against `expected_output` without a server.
- **Composable assertions**: Combine `output_contains`, `output_not_contains`, `output_equals`, `output_matches`, `schema_match`, `tool_called`, and `latency_under` per step.
- **Step output piping**: Reference a previous step's output in downstream inputs via `{{steps.<step_id>.output}}`.
- **Regression reports**: Compare the current run to any past run and surface what changed.
- **Watch mode**: Automatically reruns the affected fixture when files change.
- **CI-ready**: Includes a GitHub Action for running evals on every config change.
## Requirements
- Node.js v22.5.0 or newer.
- npm.
## Getting started
Add the following config to your MCP client:
```json
{
"mcpServers": {
"eval-runner": {
"command": "npx",
"args": ["-y", "mcp-eval-runner@latest"]
}
}
}
```
By default, eval fixtures are loaded from `./evals/` in the current working directory. To use a different path:
```json
{
"mcpServers": {
"eval-runner": {
"command": "npx",
"args": ["-y", "mcp-eval-runner@latest", "--fixtures=~/my-project/evals"]
}
}
}
```
### MCP Client configuration
Amp · Claude Code · Cline · Cursor · VS Code · Windsurf · Zed
## Your first prompt
Create a file at `evals/smoke.yaml`. Use **live mode** (recommended) by including a `server` block:
```yaml
name: smoke
description: "Verify eval runner itself is working"
server:
command: node
args: ["dist/index.js"]
steps:
- id: list_check
description: "List available test cases"
tool: list_cases
input: {}
expect:
output_contains: "smoke"
```
Then enter the following in your MCP client:
```
Run the eval suite.
```
Your client should return a pass/fail result for the smoke test.
## Fixture format
Fixtures are YAML (or JSON) files placed in the fixtures directory. Each file defines one test case.
### Top-level fields
| Field | Required | Description |
| ------------- | -------- | ----------------------------------------------------------------------------------------- |
| `name` | Yes | Unique name for the test case |
| `description` | No | Human-readable description |
| `server` | No | Server config — if present, runs in **live mode**; if absent, runs in **simulation mode** |
| `steps` | Yes | Array of steps to execute |
### `server` block (live mode)
```yaml
server:
command: node # executable to spawn
args: ["dist/index.js"] # arguments
env: # optional environment variables
MY_VAR: "value"
```
When `server` is present the eval runner spawns the server as a child process, connects via MCP stdio transport, and calls each step's tool against the live server.
### `steps` array
Each step has the following fields:
| Field | Required | Description |
| ----------------- | -------- | ------------------------------------------------------------- |
| `id` | Yes | Unique identifier within the fixture (used for output piping) |
| `tool` | Yes | MCP tool name to call |
| `description` | No | Human-readable step description |
| `input` | No | Key-value map of arguments passed to the tool (default: `{}`) |
| `expected_output` | No | Literal string used as output in simulation mode |
| `expect` | No | Assertions evaluated against the step output |
### Execution modes
**Live mode** — fixture has a `server` block:
- The server is spawned and each step calls the named tool via MCP stdio.
- Assertions run against the real tool response.
- Errors from the server cause the step (and by default the case) to fail immediately.
**Simulation mode** — no `server` block:
- No server is started.
- Each step's output is taken from `expected_output` (or empty string if absent).
- Assertions run against that static output.
- Useful for authoring and CI dry-runs, but `output_contains` assertions will always fail if `expected_output` is not set.
### Assertion types
All assertions go inside a step's `expect` block:
```yaml
expect:
output_contains: "substring" # output includes this text
output_not_contains: "error" # output must NOT include this text
output_equals: "exact string" # output exactly matches
output_matches: "regex pattern" # output matches a regular expression
tool_called: "tool_name" # verifies which tool was called
latency_under: 500 # latency in ms must be below this threshold
schema_match: # output (parsed as JSON) matches JSON Schema
type: object
required: [id]
properties:
id:
type: number
```
Multiple assertions in one `expect` block are all evaluated; the step fails if any assertion fails.
### Step output piping
Reference the output of a previous step in a downstream step's `input` using `{{steps.<step_id>.output}}`:
```yaml
steps:
- id: search_step
tool: search
input:
query: "mcp eval runner"
expected_output: "result: mcp-eval-runner v1.0"
expect:
output_contains: "mcp-eval-runner"
- id: summarize_step
tool: summarize
input:
text: "{{steps.search_step.output}}"
expected_output: "Summary: mcp-eval-runner v1.0"
expect:
output_contains: "Summary"
```
Piping works in both live mode and simulation mode.
### Note on `create_test_case`
Fixtures created with the `create_test_case` tool do not include a `server` block. They always run in simulation mode. To use live mode, add a `server` block manually to the generated YAML file.
## Tools
### Running
- `run_suite` — execute all fixtures in the fixtures directory; returns a pass/fail summary
- `run_case` — run a single named fixture by name
- `list_cases` — enumerate available fixtures with step counts and descriptions
### Authoring
- `create_test_case` — create a new YAML fixture file (simulation mode; no `server` block)
- `scaffold_fixture` — generate a boilerplate fixture with placeholder steps and pre-filled assertion comments
### Reporting
- `regression_report` — compare the current fixture state to the last run; surfaces regressions and fixes
- `compare_results` — diff two specific runs by run ID
- `generate_html_report` — generate a single-file HTML report for a completed run
### Operations
- `evaluate_deployment_gate` — CI gate; fails if recent pass rate drops below a configurable threshold
- `discover_fixtures` — discover fixture files across one or more directories (respects `FIXTURE_LIBRARY_DIRS`)
## Configuration
### `--fixtures` / `--fixtures-dir`
Directory to load YAML/JSON eval fixture files from.
Type: `string`
Default: `./evals`
### `--db` / `--db-path`
Path to the SQLite database file used to store run history.
Type: `string`
Default: `~/.mcp/evals.db`
### `--timeout`
Maximum time in milliseconds to wait for a single step before marking it as failed.
Type: `number`
Default: `30000`
### `--watch`
Watch the fixtures directory and rerun the affected fixture automatically when files change.
Type: `boolean`
Default: `false`
### `--format`
Output format for eval results.
Type: `string`
Choices: `console`, `json`, `html`
Default: `console`
### `--concurrency`
Number of test cases to run in parallel.
Type: `number`
Default: `1`
### `--http-port`
Start an HTTP server on this port instead of stdio transport.
Type: `number`
Default: disabled (uses stdio)
Pass flags via the `args` property in your JSON config:
```json
{
"mcpServers": {
"eval-runner": {
"command": "npx",
"args": ["-y", "mcp-eval-runner@latest", "--watch", "--timeout=60000"]
}
}
}
```
## Design principles
- **No mocking**: Live mode evals run against real servers. Correctness is non-negotiable.
- **Fixtures are text**: YAML/JSON in version control; no proprietary formats or databases.
- **Dogfood-first**: The eval runner's own smoke fixture tests the eval runner itself.
## Verification
Before publishing a new version, verify the server with MCP Inspector to confirm all tools are exposed correctly and the protocol handshake succeeds.
**Interactive UI** (opens browser):
```bash
npm run build && npm run inspect
```
**CLI mode** (scripted / CI-friendly):
```bash
# List all tools
npx @modelcontextprotocol/inspector --cli node dist/index.js --method tools/list
# List resources and prompts
npx @modelcontextprotocol/inspector --cli node dist/index.js --method resources/list
npx @modelcontextprotocol/inspector --cli node dist/index.js --method prompts/list
# Call a tool (example — replace with a relevant read-only tool for this plugin)
npx @modelcontextprotocol/inspector --cli node dist/index.js \
--method tools/call --tool-name list_cases
# Call a tool with arguments
npx @modelcontextprotocol/inspector --cli node dist/index.js \
--method tools/call --tool-name run_case --tool-arg name=smoke
```
Run before publishing to catch regressions in tool registration and runtime startup.
## Contributing
New assertion types go in `src/assertions.ts` — implement the `Assertion` interface and add a test. Integration tests live under `tests/` as unit tests and under `evals/` as eval fixtures.
```bash
npm install && npm test
```
## MCP Registry & Marketplace
This plugin is available on:
- [MCP Registry](https://registry.modelcontextprotocol.io)
- [MCP Market](https://mcpmarket.com)
Search for `mcp-eval-runner`.