| description | Best practices for running mcpbr evaluations including cost optimization, sample sizing, MCP server configuration, and result interpretation. |
| faq | [{"q":"What are the best practices for running mcpbr evaluations?","a":"Start with small sample sizes (n=5-10) to validate your setup, use templates for common scenarios, monitor costs by tracking token usage, and save results to compare different configurations. Always test your MCP server standalone before benchmarking."},{"q":"How can I optimize mcpbr evaluation costs?","a":"Use faster/cheaper models like Haiku for development, start with small samples, reduce max_iterations for initial testing, use --mcp-only to skip baseline runs during development, and enable verbose logging to catch issues early."},{"q":"What's the recommended workflow for testing a new MCP server?","a":"1) Test server standalone, 2) Run quick-test template with n=1, 3) Scale to n=5-10, 4) Analyze tool usage in results, 5) Optimize based on findings, 6) Run full evaluation with n=25-50+."},{"q":"How do I avoid common mcpbr pitfalls?","a":"Test Docker setup first, verify API keys are set, use pre-built images when available, set appropriate timeouts for your tasks, start with small samples, and always save results to enable comparisons and regression detection."}] |
Best Practices Guide
This guide helps you get the most value from mcpbr while avoiding common pitfalls. Whether you're testing a new MCP server, optimizing costs, or setting up CI/CD pipelines, these practices will help you work effectively.
Quick Reference
| Scenario | Recommended Approach |
|---|
| First-time setup | Use quick-test template, verify with n=1 |
| MCP server testing | Standalone test → quick-test → scale gradually |
| Cost optimization | Use Haiku model, small samples, --mcp-only flag |
| Production evaluation | Use production template, save all outputs |
| CI/CD integration | Use regression detection, JUnit XML, notifications |
| Security testing | Start with cybergym-basic, progress to advanced |
| Debugging failures | Enable -vv, use --log-dir, analyze tool usage |
Benchmark Selection Guidelines
Choosing the Right Benchmark
Use SWE-bench when:
- Testing code exploration and bug-fixing capabilities
- Evaluating Python-focused MCP servers
- Need proven, standardized benchmarks
- Want fast evaluation with pre-built images
Use CyberGym when:
- Testing security analysis capabilities
- Evaluating C/C++ code understanding
- Need vulnerability detection benchmarks
- Want to test different difficulty levels
SWE-bench Best Practices
Start Small, Scale Gradually
mcpbr run -c config.yaml -n 1 -v
mcpbr run -c config.yaml -n 5 -o results-5.json
mcpbr run -c config.yaml -n 25 -o results-25.json
mcpbr run -c config.yaml -o results-full.json
Use Pre-built Images
use_prebuilt_images: true
Pre-built images provide:
- Validated dependency installation
- Consistent evaluation environment
- Faster startup (no package installation)
- Working Python imports inside containers
Anti-pattern: Disabling pre-built images without good reason
mcpbr run -c config.yaml --no-prebuilt
CyberGym Best Practices
Choose Appropriate Difficulty Level
| Level | Context | Use Case | Typical Success Rate |
|---|
| 0 | Minimal | Test discovery abilities | Low (10-20%) |
| 1 | Type only | Balanced challenge | Medium (20-40%) |
| 2 | Description | Practical testing | Higher (40-60%) |
| 3 | Full context | Maximum guidance | Highest (60-80%) |
Start with Level 2 for Most Use Cases
mcpbr run -c config.yaml --benchmark cybergym --level 2 -n 5
Increase Timeouts for Compilation
benchmark: cybergym
timeout_seconds: 600
max_iterations: 15
Anti-pattern: Using level 3 for all testing
mcpbr run -c config.yaml --benchmark cybergym --level 3
MCP Server Configuration Best Practices
Selecting MCP Servers
Match Server Capabilities to Benchmark Needs
For SWE-bench (bug fixing):
- Filesystem access (read/write)
- Code search capabilities
- Test execution tools
- Git operations
For CyberGym (security):
- Code analysis tools
- AST parsing
- Vulnerability pattern detection
- Build system integration
Configuration Patterns
Good: Clear, Minimal Configuration
mcp_server:
name: "mcpbr"
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "{workdir}"]
env: {}
Better: With Environment Variables
mcp_server:
name: "codebase"
command: "npx"
args: ["-y", "@supermodeltools/mcp-server"]
env:
SUPERMODEL_API_KEY: "${SUPERMODEL_API_KEY}"
LOG_LEVEL: "info"
Anti-pattern: Hardcoded Secrets
mcp_server:
env:
API_KEY: "sk-1234..."
Testing Your MCP Server
Step 1: Standalone Verification
npx -y @modelcontextprotocol/server-filesystem /tmp/test
python -m my_mcp_server --workspace /tmp/test
Step 2: Quick Smoke Test
mcpbr run -c config.yaml -n 1 -v -M
Step 3: Analyze Tool Usage
mcpbr run -c config.yaml -n 5 -o results.json
cat results.json | jq '.tasks[0].mcp.tool_usage'
Step 4: Compare Against Baseline
mcpbr run -c config.yaml -n 10 -o results.json
Red Flags:
- MCP tools never appear in tool_usage
- Tool usage is always 0 or very low
- Similar results between MCP and baseline
- Server startup warnings in logs
Performance Optimization Tips
Docker Resource Management
Set Appropriate Concurrency
max_concurrent: 4
max_concurrent: 8
max_concurrent: 2
max_concurrent: 1
Monitor Resource Usage
docker stats
docker ps | grep mcpbr
Clean Up Orphaned Containers
mcpbr cleanup --dry-run
mcpbr cleanup -f
Apple Silicon Optimization
Expected Performance:
- Tasks take 2-3x longer than native x86_64
- This is normal due to emulation
- Pre-built images help reduce overhead
Recommended Settings:
max_concurrent: 2
timeout_seconds: 600
use_prebuilt_images: true
Install Rosetta 2 (if not already installed)
softwareupdate --install-rosetta
Timeout Tuning
Default Timeouts by Benchmark
| Benchmark | Recommended Timeout | Max Iterations |
|---|
| SWE-bench | 300-600s | 10-30 |
| CyberGym | 600-900s | 15-30 |
Adjust Based on Task Complexity
timeout_seconds: 300
max_iterations: 10
timeout_seconds: 600
max_iterations: 30
Anti-pattern: Extremely Long Timeouts
timeout_seconds: 3600
max_iterations: 100
Model Selection
Development/Testing:
model: "haiku"
Production/Benchmarking:
model: "sonnet"
Maximum Performance:
model: "opus"
Cost Management Strategies
Understanding Costs
Token Usage Factors:
- Model choice (Haiku < Sonnet < Opus)
- Number of iterations (more turns = more tokens)
- Task complexity (complex bugs require more exploration)
- Sample size (most obvious cost driver)
Typical Costs (per task, Sonnet model):
- Simple task: $0.10-0.30 (5-10K output tokens)
- Medium task: $0.30-0.80 (10-20K output tokens)
- Complex task: $0.80-2.00 (20-50K output tokens)
Cost Optimization Strategies
1. Start Small
mcpbr run -c config.yaml -n 1
mcpbr run -c config.yaml -n 5
mcpbr run -c config.yaml -n 50
2. Use Faster Models for Development
model: "haiku"
sample_size: 5
max_iterations: 5
timeout_seconds: 180
3. Skip Baseline During Iteration
mcpbr run -c config.yaml -M -n 5
4. Reduce Iterations
max_iterations: 10
5. Monitor Token Usage
mcpbr run -c config.yaml -n 5 -o results.json
cat results.json | jq '.tasks[] | {id: .instance_id, tokens: .mcp.tokens}'
Anti-pattern: Running Full Evaluations Repeatedly
mcpbr run -c config.yaml
mcpbr run -c config.yaml
Good Pattern: Incremental Testing
mcpbr run -c config.yaml -n 1 -M
mcpbr run -c config.yaml -n 5 -M
mcpbr run -c config.yaml -n 10
mcpbr run -c config.yaml -n 50 -o final.json
Cost Tracking
Track Costs Per Run
import json
with open("results.json") as f:
results = json.load(f)
INPUT_COST = 3.00 / 1_000_000
OUTPUT_COST = 15.00 / 1_000_000
total_cost = 0
for task in results["tasks"]:
mcp = task.get("mcp", {})
tokens = mcp.get("tokens", {})
input_tokens = tokens.get("input", 0)
output_tokens = tokens.get("output", 0)
task_cost = (input_tokens * INPUT_COST) + (output_tokens * OUTPUT_COST)
total_cost += task_cost
print(f"Total cost: ${total_cost:.2f}")
print(f"Average per task: ${total_cost / len(results['tasks']):.2f}")
Result Interpretation Guidelines
Understanding Resolution Rates
What "Resolved" Means:
- Patch was generated
- Patch applied cleanly
- All FAIL_TO_PASS tests now pass
- All PASS_TO_PASS tests still pass
Interpreting Improvement:
MCP: 32% resolved (8/25)
Baseline: 20% resolved (5/25)
Improvement: +60%
This means:
- MCP agent is 60% better than baseline
- Your MCP server helped on 3 additional tasks
- Both agents struggled (absolute rates are low)
Success Rate Benchmarks
Typical Resolution Rates (SWE-bench Lite):
| Configuration | Expected Range | Interpretation |
|---|
| Baseline (Sonnet) | 15-25% | Normal for single-shot |
| Basic filesystem MCP | 20-30% | Modest improvement |
| Advanced MCP server | 30-45% | Significant value |
| State-of-the-art | 45-60% | Excellent performance |
Low Rates (Both < 15%):
- Tasks may be inherently difficult
- Sample may include hard tasks
- Timeouts may be too short
- Model may need more iterations
High Baseline (> 25%):
- Sample may include easier tasks
- Good task selection
- Model is performing well
Low Improvement (< 10%):
- MCP tools not providing value
- Tools not being used effectively
- Baseline already sufficient
Analyzing Tool Usage
Extract Tool Statistics
cat results.json | jq '.tasks[0].mcp.tool_usage'
Healthy Tool Distribution:
{
"Grep": 15,
"Read": 20,
"Bash": 25,
"Edit": 5,
"mcp__read": 10
}
Red Flags:
{
"TodoWrite": 50,
"mcp__search": 0
}
Comparing Configurations
Save Results with Descriptive Names
mcpbr run -c filesystem.yaml -o results-filesystem.json
mcpbr run -c supermodel.yaml -o results-supermodel.json
Compare Resolution Rates
import json
def compare_results(file1, file2):
with open(file1) as f1, open(file2) as f2:
r1 = json.load(f1)
r2 = json.load(f2)
rate1 = r1["summary"]["mcp"]["rate"]
rate2 = r2["summary"]["mcp"]["rate"]
print(f"{file1}: {rate1:.1%}")
print(f"{file2}: {rate2:.1%}")
print(f"Difference: {(rate2 - rate1):.1%}")
compare_results("results-filesystem.json", "results-supermodel.json")
Security Considerations
API Key Management
Good: Environment Variables
export ANTHROPIC_API_KEY="sk-ant-..."
mcpbr run -c config.yaml
Better: Shell Profile
export ANTHROPIC_API_KEY="sk-ant-..."
Best: Secret Management
export ANTHROPIC_API_KEY=$(op read "op://vault/mcpbr/api_key")
export ANTHROPIC_API_KEY=$(aws secretsmanager get-secret-value \
--secret-id mcpbr/anthropic-key --query SecretString --output text)
Anti-pattern: Hardcoded in Config
env:
ANTHROPIC_API_KEY: "sk-ant-..."
Docker Security
Network Isolation (when external access not needed)
docker_network_mode: "none"
Container Cleanup
mcpbr cleanup -f
docker ps | grep mcpbr
Data Security
Sensitive Repositories:
- mcpbr runs on public datasets (SWE-bench, CyberGym)
- Do NOT use with proprietary code
- Task data is sent to Anthropic API
- Logs may contain code snippets
Log Management:
mcpbr run -c config.yaml --log-dir logs/
chmod 700 logs/
CI/CD Integration Patterns
GitHub Actions
Basic Workflow
name: MCP Benchmark
on:
pull_request:
paths:
- 'mcp-server/**'
jobs:
benchmark:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install mcpbr
run: pip install mcpbr
- name: Run benchmark
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
mcpbr run -c config.yaml -n 10 -o results.json
- name: Upload results
uses: actions/upload-artifact@v3
with:
name: benchmark-results
path:
With Regression Detection
- name: Download baseline
run: |
gh run download --name baseline-results --dir .
- name: Run with regression detection
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
mcpbr run -c config.yaml -n 25 \
--baseline-results baseline.json \
--regression-threshold 0.1 \
--slack-webhook ${{ secrets.SLACK_WEBHOOK }} \
-o current.json
With JUnit XML
- name: Run benchmark
run: mcpbr run -c config.yaml --output-junit junit.xml
- name: Publish test results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: junit.xml
GitLab CI
mcpbr-benchmark:
image: python:3.11
services:
- docker:dind
variables:
DOCKER_HOST: tcp://docker:2375
script:
- pip install mcpbr
- mcpbr run -c config.yaml -n 10 --output-junit junit.xml
artifacts:
reports:
junit: junit.xml
paths:
- results.json
only:
- merge_requests
Cost Control in CI/CD
Sample Size Limits
mcpbr run -c config.yaml -n 10
mcpbr run -c config.yaml -n 50
Conditional Execution
on:
push:
paths:
- 'mcp-server/**'
- 'config.yaml'
Debugging and Troubleshooting
Diagnostic Workflow
Step 1: Verify Prerequisites
docker info
echo $ANTHROPIC_API_KEY | head -c 10
which claude
Step 2: Test MCP Server Standalone
npx -y @modelcontextprotocol/server-filesystem /tmp/test
python -m my_mcp_server --workspace /tmp/test
Step 3: Run Single Task with Verbose Logging
mcpbr run -c config.yaml -n 1 -vv --log-dir debug/
Step 4: Analyze Logs
cat debug/*.json | jq '.events[] | select(.type == "system")'
cat debug/*.json | jq '.events[] | select(.type == "assistant") |
.message.content[] | select(.type == "tool_use") | .name'
Common Issues and Solutions
MCP Server Not Starting
Warning: MCP server add failed (exit 1)
Solutions:
- Test server command directly
- Check environment variables are set
- Verify command is in PATH
- Check server logs for errors
No Patch Generated
No changes made by Claude Code
Causes:
- Task too complex for iterations limit
- Agent couldn't find solution
- Agent made changes then reverted
Solutions:
max_iterations: 30
timeout_seconds: 600
Timeouts
Timeout after 300 seconds
Solutions:
timeout_seconds: 600
max_concurrent: 2
Tests Failing
FAIL_TO_PASS: 0/2 passed
This means:
- Patch applied successfully
- But didn't fix the bug
- Agent made incorrect changes
- Not an mcpbr issue - agent behavior
Debug Flags
Verbose Output Levels
mcpbr run -c config.yaml
mcpbr run -c config.yaml -v
mcpbr run -c config.yaml -vv
Per-Instance Logs
mcpbr run -c config.yaml --log-dir logs/
ls logs/
Single Log File
mcpbr run -c config.yaml --log-file full.log
Iterative Development Workflow
Phase 1: Quick Validation
Goal: Verify basic functionality
npx -y @modelcontextprotocol/server-filesystem /tmp/test
mcpbr init -t quick-test
mcpbr run -c mcpbr.yaml -v
Success Criteria:
- No server startup errors
- Task completes without timeout
- Patch generated (even if incorrect)
Phase 2: Small-Scale Testing
Goal: Validate at small scale
mcpbr run -c config.yaml -n 5 -M -o dev-mcp.json
cat dev-mcp.json | jq '.tasks[].mcp.tool_usage'
cat dev-mcp.json | jq '.tasks[].mcp.tool_usage |
to_entries | map(select(.key | startswith("mcp")))'
Success Criteria:
- MCP tools appear in tool_usage
- At least 1-2 tasks resolved
- No consistent errors
Phase 3: Baseline Comparison
Goal: Measure improvement
mcpbr run -c config.yaml -n 10 -o comparison.json
cat comparison.json | jq '.summary'
cat comparison.json | jq '.tasks[] |
select(.mcp.resolved == true and .baseline.resolved == false) |
.instance_id'
Success Criteria:
- MCP rate > baseline rate
- At least 1-2 MCP-only wins
- Improvement > 10%
Phase 4: Optimization
Goal: Improve performance based on findings
Analyze Failures:
cat comparison.json | jq '.tasks[] |
select(.mcp.resolved == false) |
{id: .instance_id, error: .mcp.error, iterations: .mcp.iterations}'
Common Optimizations:
- Increase iterations if hitting limits
- Adjust timeout if tasks timeout
- Modify MCP server configuration
- Update agent prompt
Phase 5: Production Evaluation
Goal: Final comprehensive benchmark
mcpbr run -c config.yaml -n 50 -o production.json -r report.md
cp production.json baseline.json
mcpbr run -c config.yaml -n 50 \
-o results.json \
-y results.yaml \
-r report.md \
--output-junit junit.xml \
--log-dir logs/
Success Criteria:
- Statistically significant sample (n >= 25)
- Results saved for future comparison
- Improvement is consistent
- Documentation completed
Templates and Configuration
Using Templates Effectively
Start with Templates
mcpbr templates
mcpbr init -t quick-test
mcpbr init -t filesystem
mcpbr init -t production
Customize After Generation
mcpbr init -t filesystem
vim mcpbr.yaml
mcpbr run -c mcpbr.yaml -n 1 -v
Configuration Patterns
Development Configuration
mcp_server:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "{workdir}"]
model: "haiku"
sample_size: 5
max_concurrent: 1
timeout_seconds: 180
max_iterations: 5
use_prebuilt_images: true
Production Configuration
mcp_server:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "{workdir}"]
model: "sonnet"
sample_size: 50
max_concurrent: 4
timeout_seconds: 600
max_iterations: 30
use_prebuilt_images: true
CI/CD Configuration
mcp_server:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "{workdir}"]
model: "sonnet"
sample_size: 10
max_concurrent: 2
timeout_seconds: 300
max_iterations: 15
use_prebuilt_images: true
Examples and Use Cases
Use Case 1: Testing a New MCP Server
Scenario: You've built a custom MCP server with advanced code search
Workflow:
mcpbr init -t custom-python -o my-server.yaml
python -m my_mcp_server --workspace /tmp/test
mcpbr run -c my-server.yaml -n 1 -v -M
mcpbr run -c my-server.yaml -n 10 -o results.json
cat results.json | jq '.tasks[0].mcp.tool_usage'
mcpbr run -c my-server.yaml -n 50 -o final.json -r report.md
Use Case 2: Comparing Two MCP Servers
Scenario: Evaluating filesystem vs. Supermodel
Workflow:
mcpbr init -t filesystem -o filesystem.yaml
mcpbr init -t supermodel -o supermodel.yaml
export SUPERMODEL_API_KEY="your-key"
mcpbr run -c filesystem.yaml -n 25 -o fs-results.json
mcpbr run -c supermodel.yaml -n 25 -o sm-results.json
python compare.py fs-results.json sm-results.json
Use Case 3: Cost-Optimized Development
Scenario: Limited budget, need to test iteratively
Workflow:
mcpbr init -t quick-test
mcpbr run -c mcpbr.yaml -M
mcpbr run -c mcpbr.yaml -M
mcpbr run -c mcpbr.yaml -o results.json
mcpbr run -c mcpbr.yaml -o final.json
Use Case 4: CI/CD Integration
Scenario: Automated regression testing on PR
Workflow:
name: MCP Regression Test
on:
pull_request:
paths: ['mcp-server/**']
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Download baseline
run: gh run download --name baseline --dir .
- name: Install mcpbr
run: pip install mcpbr
- name: Run regression test
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
mcpbr run -c config.yaml -n 10 \
--baseline-results baseline.json \
--regression-threshold 0.1 \
--slack-webhook ${{ secrets.SLACK_WEBHOOK }} \
-o current.json \
--output-junit junit.xml
- name: Publish
Use Case 5: Security Research
Scenario: Evaluating vulnerability detection capabilities
Workflow:
mcpbr init -t cybergym-basic
mcpbr run -c mcpbr.yaml -n 1 -v --log-dir logs/
cat logs/*.json | jq '.events[] | select(.type == "assistant") |
.message.content[] | select(.type == "text") | .text' | grep -i poc
mcpbr run -c mcpbr.yaml -n 5 -o level1.json
mcpbr init -t cybergym-advanced -o level3.yaml
mcpbr run -c level3.yaml -n 5 -o level3.json
python compare.py level1.json level3.json
Anti-Patterns to Avoid
Configuration Anti-Patterns
Bad: Hardcoded secrets
mcp_server:
env:
API_KEY: "sk-1234..."
Bad: Unrealistic timeouts
timeout_seconds: 3600
max_iterations: 100
Bad: Excessive concurrency
max_concurrent: 20
Workflow Anti-Patterns
Bad: Running full benchmark during development
mcpbr run -c config.yaml
Bad: Not saving results
mcpbr run -c config.yaml
Bad: Skipping standalone testing
mcpbr run -c broken-config.yaml -n 50
Analysis Anti-Patterns
Bad: Focusing only on resolution rate
rate = results["summary"]["mcp"]["rate"]
print(f"Rate: {rate}")
Bad: Not checking tool usage
print(f"Resolved: {results['summary']['mcp']['resolved']}")
Bad: Comparing different samples
mcpbr run -c config-a.yaml -n 10
mcpbr run -c config-b.yaml -n 10
Quick Start Checklist
Before First Run:
For New MCP Server:
For Production Run:
Additional Resources
Getting Help
Before Asking for Help:
- Check troubleshooting guide
- Run with
-vv --log-dir debug/
- Test MCP server standalone
- Verify prerequisites
When Reporting Issues:
- Include mcpbr version (
mcpbr --version)
- Include Python version
- Include Docker version
- Include config file (redact secrets!)
- Include relevant logs
- Describe expected vs actual behavior
Community: