# Tripwire — Contract Testing for MCP Servers
[](https://crates.io/crates/trip-test)
[](https://opensource.org/licenses/MIT)
[](https://www.rust-lang.org/)
Contract testing and regression safety for Model Context Protocol (MCP) servers. Catch breaking changes before they ship.
## The Problem
MCP servers expose tools that AI agents depend on. A schema change breaks every agent that depends on it — **silently**, with no build-time error or test failure. It surfaces later as a 500 error or refused tool call in production.
**Example:** Rename a required parameter from `limit` to `max_results`.
- Old agents call: `search(q="test", limit=10)` → ❌ fails
- No CI warning
- No regression test catches it
- Agents break in production
## The Solution
Tripwire treats MCP server contracts like REST APIs. Record a baseline, detect breaking changes in CI, fail PRs automatically.
Think of it as **Postman + Jest snapshots, but for MCP servers**.
## Quick Start
### Installation
**Via Cargo:**
```bash
cargo install trip-test
```
**Via Homebrew (coming soon):**
```bash
brew install trip-test
```
**From source:**
```bash
git clone https://github.com/arjav1528/trip-test
cd trip-test
cargo install --path .
```
### Basic Usage
**1. Connect to your server and list tools:**
```bash
trip-test connect --server "python -m my_mcp_server"
```
Output:
```
Connecting to: python -m my_mcp_server
Tools:
- search (Search records)
inputs: { q: string, limit: integer, }
- fetch (Fetch a record)
inputs: { id: string, }
```
**2. Record a baseline snapshot:**
```bash
trip-test record --server "python -m my_mcp_server" --out baseline.trip-test.json
```
Interactive prompts guide you to invoke a few tools. Captures tool schemas + responses.
**3. Check for regressions:**
```bash
trip-test check --snapshot baseline.trip-test.json --server "python -m my_mcp_server"
```
Replays recorded exchanges. Passes if behavior matches.
```
Results: 2 passed, 0 failed
```
**4. Detect breaking changes:**
```bash
trip-test diff --baseline baseline.trip-test.json --server "python -m my_mcp_server"
```
Compares contracts. Classifies changes.
```
🚨 BREAKING CHANGES:
• search: Parameter 'limit' removed (was required: true)
• search: Parameter 'max_results' added (required: true)
⚠️ NON-BREAKING CHANGES:
• search: Description updated
Overall Verdict: BREAKING
```
## CLI Commands
### `connect`
List all tools and their schemas from a server.
```bash
trip-test connect --server "python -m my_server"
```
### `call`
Invoke a single tool and see the exchange.
```bash
trip-test call \
--server "python -m my_server" \
--tool search \
--args '{"q":"acme","limit":10}'
```
Output:
```json
{
"results": [...],
"total": 42
}
```
### `record`
Interactively record tool calls into a snapshot file.
```bash
trip-test record --server "python -m my_server" --out baseline.trip-test.json
```
Prompts you to select tools and invoke them. Captures input + output. Saves to JSON.
### `check`
Replay a snapshot and verify the server still matches.
```bash
trip-test check --snapshot baseline.trip-test.json --server "python -m my_server"
```
Exit code: `0` if all pass, `1` if any fail.
### `diff`
Compare baseline contract vs live server. Classify changes.
```bash
trip-test diff --baseline baseline.trip-test.json --server "python -m my_server"
```
Output: BREAKING, NON-BREAKING, or ADDITIVE changes.
Exit code: `0` if safe, `1` if breaking.
### Global Flags
- `--verbose` or `-v` — Enable debug output
- `--help` or `-h` — Show usage
- `--version` — Print version
- `--config <file>` — Load settings from TOML file
## Configuration
### TOML Configuration File
Create `trip-test.toml` in your project root to avoid repeating flags:
```toml
[snapshot]
# Path to your baseline snapshot file (relative to repo root)
baseline = "contracts/baseline.trip-test.json"
[server]
# Command to start your MCP server
# Can be any command that spawns an MCP server:
# - Python: "python -m my_package"
# - Node.js: "node src/index.js"
# - Rust: "./target/release/my-server"
# - Docker: "docker run my-image"
command = "python -m my_mcp_server"
# Timeout for server operations (milliseconds)
timeout_ms = 5000
[diff]
# Whether to treat additive changes (new tools/params) as warnings
treat_additive_as_warning = false
# Whether to treat non-breaking changes (descriptions) as warnings
treat_non_breaking_as_warning = false
```
Then just run:
```bash
trip-test diff --config trip-test.toml
```
### Configuration Examples
**Python server with virtual environment:**
```toml
[server]
command = "python -m venv/bin/python -m my_server"
```
**Node.js server with npm script:**
```toml
[server]
command = "npm run start:mcp"
```
**Rust server (local development):**
```toml
[server]
command = "cargo run --release -- --stdio"
```
**Docker container:**
```toml
[server]
command = "docker run --rm my-mcp-server:latest"
```
**With environment variables:**
```toml
[server]
# Unix/Linux/Mac
command = "env RUST_LOG=debug ./target/release/server"
# Or use shell directly
command = "bash -c 'export RUST_LOG=debug && ./target/release/server'"
```
**Multiple servers (use separate config files):**
```bash
# test-server-v1.toml
trip-test diff --config test-server-v1.toml
# test-server-v2.toml
trip-test diff --config test-server-v2.toml
```
## Snapshot File Format
Snapshots are JSON files that capture a contract baseline.
```json
{
"formatVersion": 1,
"meta": {
"name": "my-server-baseline",
"recordedAt": "2026-08-09T12:00:00Z",
"serverName": "my-server",
"serverVersion": "1.0.0"
},
"toolCatalog": [
{
"name": "search",
"description": "Search records",
"inputSchema": {
"type": "object",
"properties": {
"q": { "type": "string" },
"limit": { "type": "integer" }
},
"required": ["q", "limit"]
}
}
],
"exchanges": [
{
"id": "ex-001",
"tool": "search",
"input": { "q": "acme", "limit": 10 },
"matchMode": "structural",
"expected": {
"isError": false,
"content": [{ "type": "text", "text": "..." }]
}
}
]
}
```
Version-control this file. It's your regression baseline.
## CI/CD Integration
This section shows how to integrate trip-test into your existing CI/CD pipeline.
### GitHub Actions
#### Basic Setup
Create `.github/workflows/trip-test.yml` in any MCP server repository:
```yaml
name: Tripwire Contract Check
on:
pull_request:
paths:
- 'src/**'
- 'Cargo.toml'
- '.github/workflows/trip-test.yml'
push:
branches: [main]
jobs:
contract-check:
name: Check MCP Contract
runs-on: ubuntu-latest
steps:
# 1. Checkout code
- uses: actions/checkout@v4
with:
fetch-depth: 0
# 2. Setup Rust (if building Rust server)
- uses: dtolnay/rust-toolchain@stable
- uses: swatinem/rust-cache@v2
# 3. Build server
- name: Build MCP server
run: cargo build --release
# 4. Install trip-test
- name: Install trip-test
run: cargo install trip-test
# 5. Run contract check
- name: Check contract
id: check
run: |
trip-test diff \
--baseline contracts/baseline.trip-test.json \
--server "./target/release/my-server" \
--format json > report.json || true
cat report.json
# 6. Comment on PR
- name: Post PR comment
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('report.json'));
let comment = '## 🔍 Tripwire Contract Check\n\n';
if (report.overall_verdict === 'BREAKING') {
comment += '### ❌ **Breaking Changes Detected**\n\n';
comment += 'The following breaking changes were found:\n\n';
comment += '| Tool | Change | Details |\n';
comment += '|------|--------|----------|\n';
report.breaking_changes.forEach(c => {
comment += `| \`${c.tool_name}\` | ${c.change_type} | ${c.details} |\n`;
});
} else {
comment += '### ✅ **Contract is Safe**\n\n';
comment += 'No breaking changes detected.\n\n';
}
if (report.non_breaking_changes.length > 0) {
comment += '\n### ⚠️ Non-Breaking Changes\n\n';
comment += '| Tool | Change | Details |\n';
comment += '|------|--------|----------|\n';
report.non_breaking_changes.forEach(c => {
comment += `| \`${c.tool_name}\` | ${c.change_type} | ${c.details} |\n`;
});
}
if (report.additive_changes.length > 0) {
comment += '\n### ✨ Additive Changes\n\n';
comment += '| Tool | Change | Details |\n';
comment += '|------|--------|----------|\n';
report.additive_changes.forEach(c => {
comment += `| \`${c.tool_name}\` | ${c.change_type} | ${c.details} |\n`;
});
}
comment += '\n---\n';
comment += `**Verdict:** \`${report.overall_verdict}\`\n`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
# 7. Fail if breaking changes
- name: Enforce contract safety
if: always()
run: |
if grep -q '"overall_verdict": "BREAKING"' report.json; then
echo "❌ Breaking changes detected! PR check failed."
exit 1
fi
```
#### For Python Servers
```yaml
name: Tripwire Contract Check (Python)
on: [pull_request, push]
jobs:
contract-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
cache: 'pip'
- name: Install dependencies
run: |
pip install -e .
pip install mcp
- name: Install trip-test
run: cargo install trip-test
- name: Check contract
run: |
trip-test diff \
--config trip-test.toml \
--format json > report.json || true
- name: Post result
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('report.json'));
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## Tripwire Check\n\nVerdict: **${report.overall_verdict}**`
});
- name: Enforce safety
run: |
if grep -q '"overall_verdict": "BREAKING"' report.json; then
exit 1
fi
```
#### For Node.js Servers
```yaml
name: Tripwire Contract Check (Node.js)
on: [pull_request, push]
jobs:
contract-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Install trip-test
run: cargo install trip-test
- name: Check contract
run: |
trip-test diff \
--config trip-test.toml \
--format json > report.json || true
- name: Post result
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('report.json'));
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## Tripwire Check\n\nVerdict: **${report.overall_verdict}**`
});
- name: Enforce safety
run: |
if grep -q '"overall_verdict": "BREAKING"' report.json; then
exit 1
fi
```
### GitLab CI
```yaml
contract-check:
image: rust:latest
before_script:
- apt-get update && apt-get install -y python3
- cargo install trip-test
script:
# Build your server (adjust for your build system)
- cargo build --release
# Run contract check
- trip-test diff --config trip-test.toml --format json > report.json || true
# Check for breaking changes
- |
if grep -q '"overall_verdict": "BREAKING"' report.json; then
echo "❌ Breaking changes detected!"
cat report.json
exit 1
else
echo "✅ Contract is safe"
fi
artifacts:
paths:
- report.json
expire_in: 30 days
```
### Generic CI (Jenkins, CircleCI, etc.)
The core pattern is:
```bash
# 1. Build server
<your-build-command>
# 2. Install trip-test (if not cached)
cargo install trip-test
# 3. Run check
# 4. Parse report
if grep -q '"overall_verdict": "BREAKING"' report.json; then
echo "❌ Contract violation!"
cat report.json
exit 1
fi
# 5. Optional: upload report
<your-artifact-upload>
```
### Integration Checklist
When adding trip-test to an existing MCP server:
- [ ] Create `trip-test.toml` with correct server command
- [ ] Create `contracts/` directory
- [ ] Record baseline: `trip-test record --server "..." --out contracts/baseline.trip-test.json`
- [ ] Commit `contracts/baseline.trip-test.json` and `trip-test.toml`
- [ ] Add CI workflow (GitHub Actions / GitLab CI / etc.)
- [ ] Test locally: `trip-test diff --config trip-test.toml`
- [ ] Open a test PR with intentional breaking change
- [ ] Verify CI fails and posts comment
- [ ] Revert test change
- [ ] Merge and ship ✅
### Example: Adding Tripwire to Existing Showpad MCP Server
```bash
# 1. Clone server
git clone https://github.com/showpad/mcp-showql
cd mcp-showql
# 2. Install trip-test
cargo install trip-test
# 3. Create config
cat > trip-test.toml << 'EOF'
[snapshot]
baseline = "contracts/baseline.trip-test.json"
[server]
command = "cargo run --release -- --stdio"
timeout_ms = 5000
EOF
# 4. Create contracts directory
mkdir -p contracts
# 5. Record baseline (interactively)
trip-test record --server "cargo run --release -- --stdio" --out contracts/baseline.trip-test.json
# 6. Verify
trip-test diff --config trip-test.toml
# 7. Commit
git add trip-test.toml contracts/baseline.trip-test.json
git commit -m "chore: add MCP contract testing with trip-test"
# 8. Add GitHub Actions
cat > .github/workflows/contract-check.yml << 'EOF'
name: Tripwire Contract Check
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo install trip-test
- run: trip-test diff --config trip-test.toml --format json > report.json || true
- run: |
if grep -q '"overall_verdict": "BREAKING"' report.json; then
exit 1
fi
EOF
# 9. Push and open PR
git push origin add-trip-test
```
### Troubleshooting CI Integration
**CI fails to build server:**
- Check that build command in `trip-test.toml` works locally
- Ensure all build dependencies are in CI environment
- For Python: verify venv/dependencies
- For Node.js: verify npm install runs
- For Rust: verify Cargo.toml exists
**CI fails to install trip-test:**
- Add `rustup` if not present: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`
- Or pre-build trip-test as a cached artifact
- Or use: `pip install trip-test` (if available)
**Report not found:**
- Check that server command in config works
- Verify baseline snapshot exists: `contracts/baseline.trip-test.json`
- Run locally first: `trip-test diff --config trip-test.toml`
**PR comment not posting:**
- Ensure GitHub token has `issues:write` permission
- Check that issue/PR number is correct
- Verify repository is not private (or token has private repo access)
## Testing Your MCP Server
### Complete Testing Workflow
This section walks you through a complete testing setup from scratch.
#### Step 1: Installation
```bash
# Clone your MCP server repository
git clone https://github.com/your-org/my-mcp-server
cd my-mcp-server
# Install trip-test
cargo install trip-test
# Or, if you have Homebrew:
brew install trip-test
```
#### Step 2: Create Project Structure
```bash
# Create a contracts directory for snapshots
mkdir -p contracts
# Create initial trip-test config
cat > trip-test.toml << 'EOF'
[snapshot]
baseline = "contracts/baseline.trip-test.json"
[server]
command = "python -m my_mcp_server"
timeout_ms = 5000
[diff]
treat_additive_as_warning = false
treat_non_breaking_as_warning = false
EOF
```
#### Step 3: Test Server Connection
Verify your server works:
```bash
# List all tools exposed by your server
trip-test connect --server "python -m my_mcp_server"
```
Expected output:
```
Connecting to: python -m my_mcp_server
Tools:
- search (Search records)
inputs: { q: string, limit: integer, }
- fetch (Fetch a record by ID)
inputs: { id: string, }
- create (Create a new record)
inputs: { title: string, content: string, }
```
If this fails, check:
- Is your server command correct? (Try running it manually)
- Does your server implement the MCP `initialize` handshake?
- Are tools properly advertised with `inputSchema`?
#### Step 4: Test Individual Tool Calls
Before recording, test each tool manually:
```bash
# Test the search tool
trip-test call \
--server "python -m my_mcp_server" \
--tool search \
--args '{"q":"acme","limit":10}'
# Test the fetch tool
trip-test call \
--server "python -m my_mcp_server" \
--tool fetch \
--args '{"id":"123"}'
```
This verifies:
- Tools are callable
- Arguments are accepted
- Responses are valid JSON
- No runtime errors
#### Step 5: Record Baseline Snapshot
Once individual tools work, record the baseline:
```bash
# Interactively record exchanges
trip-test record --server "python -m my_mcp_server" --out contracts/baseline.trip-test.json
```
The tool will:
1. Connect to your server
2. List all tools
3. Prompt you to select tools to test
4. Ask for input arguments for each
5. Record the request and response
6. Save everything to `baseline.trip-test.json`
Example session:
```
Connected to: python -m my_mcp_server
Tools available:
1. search (Search records)
2. fetch (Fetch a record by ID)
Enter tool number to record (or 0 to finish): 1
Enter arguments as JSON: {"q":"test","limit":5}
Calling search...
Result: {"results":[...],"total":42}
✓ Exchange recorded!
Enter tool number to record (or 0 to finish): 2
Enter arguments as JSON: {"id":"123"}
Calling fetch...
Result: {"id":"123","title":"...","content":"..."}
✓ Exchange recorded!
Enter tool number to record (or 0 to finish): 0
Snapshot saved to: contracts/baseline.trip-test.json
```
#### Step 6: Inspect the Snapshot
View what was recorded:
```bash
# Pretty-print the snapshot
# Or use your editor
code contracts/baseline.trip-test.json
```
The snapshot captures:
- Tool schemas (names, descriptions, input parameters)
- Recorded exchanges (what you called, what you got back)
- Metadata (when recorded, server version)
#### Step 7: Commit Baseline
Lock in your contract:
```bash
git add contracts/baseline.trip-test.json trip-test.toml
git commit -m "baseline: record MCP contract v1.0"
git push
```
### Testing Workflow Scenarios
#### Scenario 1: Developer Makes Safe Change
```bash
# Developer adds an optional parameter (safe)
# Edits server code and rebuilds
python -m build
# Run contract check
trip-test check --config trip-test.toml
# Output:
# Replaying ex-001: search
# Input: {"q": "test", "limit": 5}
# ✓ PASS
#
# Results: 1 passed, 0 failed
```
**CI will pass** ✅
#### Scenario 2: Developer Makes Breaking Change
```bash
# Developer renames a required parameter
# Before: search(q, limit)
# After: search(q, max_results)
# Developer commits and opens PR
git commit -m "api: rename limit → max_results"
git push origin feature-branch
# CI automatically runs
trip-test diff --config trip-test.toml
# Output:
# 🚨 BREAKING CHANGES:
# • search: Parameter 'limit' removed (was required: true)
# • search: Parameter 'max_results' added (required: true)
#
# Overall Verdict: BREAKING
```
**CI will fail** ❌ and **block the PR**
**Resolution options:**
Option A: Fix the breaking change
```bash
# Revert to old parameter name
git revert HEAD
git push
# CI passes on new commit
```
Option B: Intentionally break the contract
```bash
# Update baseline to reflect new contract
trip-test record --server "python -m my_mcp_server" --out contracts/baseline.trip-test.json
# Commit the new baseline
git add contracts/baseline.trip-test.json
git commit -m "api: rename limit → max_results (breaking change)"
# New baseline is now locked in
# Future PRs will compare against this
```
#### Scenario 3: Detect Non-Breaking Change
```bash
# Developer improves tool descriptions
# Before: "Search records"
# After: "Search records by query (case-insensitive)"
trip-test diff --config trip-test.toml
# Output:
# ⚠️ NON-BREAKING CHANGES:
# • search: Description changed
#
# Overall Verdict: SAFE (no breaking changes)
```
**CI will pass** ✅
### Real Server Examples
#### Python MCP Server (with venv)
```bash
# Create venv
python -m venv venv
source venv/bin/activate
pip install mcp
# Test connection
trip-test connect --server "python -m my_mcp_server"
# Config file
cat > trip-test.toml << 'EOF'
[server]
command = "python -m my_mcp_server"
EOF
```
#### Node.js MCP Server
```bash
# Install dependencies
npm install
# Build if needed
npm run build
# Test connection
trip-test connect --server "node dist/index.js"
# Config file
cat > trip-test.toml << 'EOF'
[server]
command = "node dist/index.js"
EOF
```
#### Rust MCP Server
```bash
# Build in release mode for performance
cargo build --release
# Test connection
trip-test connect --server "./target/release/my-server"
# Config file with proper invocation
cat > trip-test.toml << 'EOF'
[server]
command = "./target/release/my-server --stdio"
EOF
```
#### Docker Container
```bash
# Build your MCP server image
docker build -t my-mcp-server .
# Test connection
trip-test connect --server "docker run --rm my-mcp-server"
# Config file
cat > trip-test.toml << 'EOF'
[server]
command = "docker run --rm my-mcp-server"
EOF
```
#### Testing Multiple Versions
Keep separate configs for different versions:
```bash
# test-v1.toml
cat > test-v1.toml << 'EOF'
[snapshot]
baseline = "contracts/baseline-v1.trip-test.json"
[server]
command = "git checkout v1.0.0 && cargo build --release && ./target/release/server"
EOF
# test-v2.toml
cat > test-v2.toml << 'EOF'
[snapshot]
baseline = "contracts/baseline-v2.trip-test.json"
[server]
command = "git checkout main && cargo build --release && ./target/release/server"
EOF
# Test both
trip-test diff --config test-v1.toml
trip-test diff --config test-v2.toml
```
### Testing Against Example Servers
Tripwire ships with example MCP servers for learning:
```bash
# Clone trip-test
git clone https://github.com/arjav1528/trip-test
cd trip-test
# Build example servers
cargo build --examples
# Test against basic example
trip-test connect --server "./target/debug/examples/test-server"
# Record baseline from example
trip-test record \
--server "./target/debug/examples/test-server" \
--out example-baseline.trip-test.json
# Test against modified example
trip-test diff \
--baseline example-baseline.trip-test.json \
--server "./target/debug/examples/test-server-modified"
# Expected output: BREAKING changes detected ❌
```
## How It Works
### Architecture
```
┌──────────────────┐
│ Your CLI │
│ (trip-test) │
└────────┬─────────┘
│ JSON-RPC (stdio)
│
┌────────▼─────────┐
│ Your MCP Server │
│ (any language) │
└──────────────────┘
```
1. **Connect**: Spawn your MCP server as a subprocess
2. **Handshake**: Perform MCP `initialize` protocol
3. **List**: Fetch all tools + input schemas
4. **Call**: Invoke tools with your args
5. **Record**: Save exchanges to snapshot JSON
6. **Diff**: Compare baseline schema vs live schema
7. **Classify**: Mark each change as breaking/non-breaking/additive
### Change Classification Rules
| Tool removed | **BREAKING** | `search` tool deleted |
| Tool added | **ADDITIVE** | New `fetch` tool added |
| Required param removed | **BREAKING** | `limit` param removed |
| Required param added | **BREAKING** | New required `max_results` |
| Optional param added | **ADDITIVE** | Optional `sort` param added |
| Type narrowed | **BREAKING** | `string` → `enum` |
| Type widened | **NON-BREAKING** | `enum` → `string` |
| Enum value removed | **BREAKING** | Removed option "asc" |
| Enum value added | **NON-BREAKING** | Added option "desc" |
| Description changed | **NON-BREAKING** | Help text updated |
## Output Formats
### Pretty (default)
```bash
trip-test diff --baseline baseline.trip-test.json --server "python -m my_server"
```
Human-readable terminal output with colors.
### JSON (for CI)
```bash
trip-test diff --baseline baseline.trip-test.json --server "python -m my_server" --format json
```
Machine-readable JSON:
```json
{
"overall_verdict": "BREAKING",
"breaking_changes": [
{
"tool_name": "search",
"change_type": "Parameter removed",
"details": "Parameter 'limit' was removed (was required: true)",
"class": "BREAKING"
}
],
"non_breaking_changes": [...],
"additive_changes": [...]
}
```
## Limitations & Known Issues
**MVP Scope (current):**
- Supports **stdio transport only** (spawn subprocess)
- Flat + one level of nested schema changes (handles most cases)
- No `$ref` resolution (document workaround)
- No credential management (pass headers via `--header` flag planned)
- No output schema validation (input schemas only)
**Planned (Phase 2+):**
- HTTP transport (remote servers)
- Web UI (interactive tool browser)
- Watch mode (alert on drift)
- Snapshot registry (share baselines)
- Test generation (auto-generate snapshots from schemas)
## Contributing
We welcome contributions! See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
### Local Development
```bash
# Clone repo
git clone https://github.com/arjav1528/trip-test
cd trip-test
# Build
cargo build
# Test against example server
cargo build --example test-server
cargo run -- connect --server "./target/debug/examples/test-server"
# Run tests
cargo test
# Lint
cargo clippy
# Format
cargo fmt
```
### Project Structure
```
trip-test/
├── src/
│ ├── main.rs # CLI entry point
│ ├── lib.rs # Public API
│ ├── mcp.rs # MCP protocol client
│ ├── snapshot.rs # Snapshot file format
│ ├── diff.rs # Diff engine & classification
│ ├── config.rs # TOML configuration
│ └── logger.rs # Logging utilities
├── examples/
│ ├── test-server.rs # Dummy MCP server for testing
│ └── test-server-modified.rs
├── .github/workflows/
│ └── trip-test.yml # CI workflow
├── Cargo.toml
├── LICENSE
└── README.md
```
## License
MIT License — see [LICENSE](./LICENSE) for details.
## Acknowledgments
Inspired by:
- [Postman](https://www.postman.com/) — API testing
- [Jest snapshots](https://jestjs.io/docs/snapshot-testing) — regression detection
- [OpenAPI/Swagger](https://swagger.io/) — schema-first design
## Support
- **GitHub Issues**: [Report bugs or request features](https://github.com/arjav1528/trip-test/issues)
- **Discussions**: [Ask questions](https://github.com/arjav1528/trip-test/discussions)
- **Documentation**: [Full docs](https://docs.rs/trip-test)
## Roadmap
- [x] Core MVP (snapshot + diff + CI)
- [x] GitHub Actions integration
- [x] JSON output for CI/CD
- [x] Configuration file support
- [x] Published on crates.io
- [ ] HTTP transport support
- [ ] Web UI dashboard
- [ ] Watch mode & alerts
- [ ] Snapshot registry
- [ ] Test generation
---
**Made with ❤️ for MCP developers**
Questions? Open an [issue](https://github.com/arjav1528/trip-test/issues) or [discussion](https://github.com/arjav1528/trip-test/discussions).