Thank you for your interest in contributing to testmcpy! We're excited to have you join our community of contributors building better tools for testing LLM tool-calling capabilities.
We welcome all types of contributions:
- Bug reports and fixes
- New features and evaluators
- Documentation improvements
- Example test cases
- Performance optimizations
- Community support
This guide will help you get started, whether you're fixing a typo or adding a major feature.
- Quick Start
- Development Setup
- Contribution Workflow
- Commit Message Format
- Pull Request Guidelines
- Code Review Process
- Testing Requirements
- Code Quality Standards
- Community Guidelines
- Getting Help
Want to contribute quickly? Here's the fastest path:
# 1. Fork the repository on GitHub
# 2. Clone your fork
git clone https://github.com/YOUR_USERNAME/testmcpy.git
cd testmcpy
# 3. Set up development environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e ".[dev,all]"
# 4. Create a branch for your work
git checkout -b feat/my-new-feature
# 5. Make your changes, test them
testmcpy run tests/
# 6. Format and lint your code
black .
flake8 .
# 7. Commit and push
git add .
git commit -m "feat: add amazing new feature"
git push origin feat/my-new-feature
# 8. Open a pull request on GitHubThat's it! Now let's dive into the details.
- Python 3.9 or higher (3.9, 3.10, 3.11, or 3.12)
- Git
- (Optional) Ollama for testing local LLM providers
- (Optional) API keys for Anthropic or OpenAI if testing those providers
-
Clone the repository:
git clone https://github.com/preset-io/testmcpy.git cd testmcpy -
Create a virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install the package in editable mode with development dependencies:
pip install -e ".[dev]" -
(Optional) Install optional features:
# For web UI development pip install -e ".[server]" # For Claude SDK integration pip install -e ".[sdk]" # For all features pip install -e ".[all]"
-
Install pre-commit hooks (recommended):
pre-commit install
We follow a standard fork-and-pull workflow. Here's the detailed process:
Fork the repository on GitHub, then clone your fork:
git clone https://github.com/YOUR_USERNAME/testmcpy.git
cd testmcpyAdd the upstream repository as a remote:
git remote add upstream https://github.com/preset-io/testmcpy.gitAlways create a new branch for your work. Use descriptive branch names with prefixes:
feat/- New featuresfix/- Bug fixesdocs/- Documentation changesrefactor/- Code refactoringtest/- Adding or updating testschore/- Maintenance tasks
# Example branch names
git checkout -b feat/parameter-validation-evaluator
git checkout -b fix/chat-command-error
git checkout -b docs/update-readme-examplesWrite your code following our standards (see Code Quality Standards below). Make sure to:
- Add type hints for new functions
- Update documentation for user-facing changes
- Add tests for new functionality
- Keep changes focused on a single concern
Before committing, ensure everything works:
# Run the test suite
testmcpy run tests/
# Test with multiple providers if applicable
testmcpy run tests/ --provider ollama --model llama3.1:8b
testmcpy run tests/ --provider anthropic --model claude-haiku-4-5
# Format and lint
black .
flake8 .
# Type check (if you have mypy installed)
mypy testmcpyWrite clear, descriptive commit messages following our format (see Commit Message Format below):
git add .
git commit -m "feat: add deep parameter validation evaluators"Regularly sync with the upstream repository:
git fetch upstream
git rebase upstream/maingit push origin feat/your-feature-nameGo to GitHub and open a pull request from your fork to the main repository. Fill out the PR template with:
- Clear description of changes
- Why the change is needed
- How you tested it
- Screenshots (for UI changes)
- Related issue numbers
Be responsive to feedback from reviewers. Make requested changes and push updates:
# Make changes based on feedback
git add .
git commit -m "fix: address review feedback"
git push origin feat/your-feature-nameWe use conventional commits to keep our history clean and enable automated changelog generation.
<type>: <short description>
<optional longer description>
<optional footer>
feat: New feature for usersfix: Bug fix for usersdocs: Documentation changesrefactor: Code refactoring (no functional changes)test: Adding or updating testschore: Maintenance tasks, dependency updatesperf: Performance improvementsstyle: Code style changes (formatting, etc.)
Simple feature:
feat: add parameter_value_in_range evaluator
Bug fix with description:
fix: resolve chat command hanging on empty response
The chat command would hang indefinitely when receiving an empty
response from the LLM. This fix adds proper timeout handling and
error messages for this scenario.
Fixes #42
Feature with breaking change:
feat: change evaluator return format to include metadata
BREAKING CHANGE: Evaluators now return a dict with 'passed', 'score',
and 'reason' keys instead of just a boolean. Update custom evaluators
to use the new format.
Documentation update:
docs: add examples for custom evaluator development
Multiple changes:
feat: add deep parameter validation evaluators
Implements 4 new evaluators for checking tool call parameters:
- tool_called_with_parameter
- tool_called_with_parameters
- parameter_value_in_range
- tool_call_count
Includes comprehensive tests and documentation examples.
Closes #123
- Use the imperative mood ("add" not "added" or "adds")
- Keep the first line under 72 characters
- Don't capitalize the first letter after the type
- Don't end the first line with a period
- Leave a blank line before the body
- Wrap the body at 72 characters
- Reference issues and PRs when applicable
- Code follows project style guide (Black formatting, type hints)
- All tests pass (
testmcpy run tests/) - Code is properly formatted (
black .) - No linting errors (
flake8 .) - New tests added for new functionality
- Documentation updated if needed
- Commit messages follow our format
- Branch is up to date with main
When you open a PR, fill out the template completely:
Summary: Briefly explain what this PR does in 1-2 sentences.
Changes: List the main changes made:
- Added X evaluator
- Fixed Y bug in chat command
- Updated Z documentation
Testing: Describe how you tested:
- Manual testing with Ollama and Claude
- Added unit tests in
tests/unit/test_evaluators.py - Verified existing tests still pass
Related Issues: Link any related issues:
- Fixes #123
- Related to #456
- Keep PRs focused: One PR should address one issue or add one feature
- Small is better: Smaller PRs are easier to review and merge
- Write good descriptions: Help reviewers understand your changes
- Add screenshots: For UI changes, include before/after screenshots
- Update documentation: Keep docs in sync with code changes
- Respond promptly: Address review feedback in a timely manner
- Don't force push: After review starts, add new commits instead of rebasing
Good PR example:
## Summary
Add support for validating tool call parameters to ensure LLMs pass
correct values to MCP tools.
## Changes
- Added `parameter_value_in_range` evaluator
- Added `tool_called_with_parameter` evaluator
- Added tests in `tests/unit/test_param_evaluators.py`
- Updated evaluator reference documentation
## Testing
- Tested with Ollama (llama3.1:8b) and Claude (claude-haiku-4-5)
- All existing tests pass
- New tests cover edge cases (missing params, wrong types, etc.)
## Related Issues
Fixes #42- Initial response: We aim to respond to PRs within 2-3 business days
- Review time: Most PRs are reviewed within a week
- Iterations: Expect 1-2 rounds of feedback for most PRs
- Approval: At least one maintainer approval required before merge
- CI checks: All CI checks must pass before merge
Reviewers will check:
- Functionality: Does it work as intended?
- Tests: Are there adequate tests?
- Code quality: Is the code clean and maintainable?
- Documentation: Are changes documented?
- Breaking changes: Are they necessary and well-communicated?
- Performance: Any performance implications?
- Security: Any security concerns?
- Multi-provider support: Works with all LLM providers?
- Write clear descriptions: Help reviewers understand context
- Add tests: PRs with tests are easier to approve
- Keep it small: Smaller PRs get reviewed faster
- Follow guidelines: Adhering to our standards speeds up review
- Be responsive: Quick responses to feedback help maintain momentum
- Self-review: Review your own PR before submitting
Once approved:
- Maintainers will merge your PR (usually via squash merge)
- Your contribution will be included in the next release
- You'll be credited in release notes
All code changes should include appropriate tests. Good tests make code more maintainable and give confidence that changes work correctly.
- Unit Tests: Test individual functions and evaluators
- Integration Tests: Test YAML test file execution
- Provider Tests: Test with different LLM providers (optional but recommended)
# tests/unit/test_evaluators.py
import pytest
from testmcpy.evaluators import WasMcpToolCalled
def test_was_mcp_tool_called_success():
"""Test that evaluator passes when correct tool is called."""
evaluator = WasMcpToolCalled(tool_name="create_chart")
result = {
"tool_calls": [{"name": "create_chart", "args": {}}]
}
evaluation = evaluator.evaluate(result)
assert evaluation["passed"] is True
assert "create_chart" in evaluation["reason"]
def test_was_mcp_tool_called_failure():
"""Test that evaluator fails when wrong tool is called."""
evaluator = WasMcpToolCalled(tool_name="create_chart")
result = {
"tool_calls": [{"name": "delete_chart", "args": {}}]
}
evaluation = evaluator.evaluate(result)
assert evaluation["passed"] is False# Run all tests
testmcpy run tests/
# Run specific test file
testmcpy run tests/basic_test.yaml
# Run with specific model
testmcpy run tests/ --model llama3.1:8b --provider ollama
# Run with Claude
testmcpy run tests/ --model claude-haiku-4-5 --provider anthropicTest cases are defined in YAML format:
version: "1.0"
name: "Example Test Suite"
tests:
- name: "test_tool_calling"
prompt: "Create a bar chart showing sales by region"
expected_tools:
- "create_chart"
evaluators:
- name: "was_mcp_tool_called"
args:
tool_name: "create_chart"
- name: "execution_successful"
- name: "within_time_limit"
args:
max_seconds: 30When adding new features:
- Evaluators: Add unit tests with pass and fail cases
- CLI commands: Add integration tests with YAML test files
- Bug fixes: Add tests that reproduce the bug
- Edge cases: Test error handling and boundary conditions
We maintain high code quality standards to ensure the codebase is maintainable and reliable.
We use Black for code formatting with a line length of 100 characters.
# Format all code
black .
# Check formatting without making changes
black --check .Black is opinionated and eliminates debates about code style. If Black formats it, it's correct.
We use Flake8 for catching common issues.
# Run linting
flake8 .
# Run with specific config
flake8 testmcpy --max-line-length=100We encourage comprehensive type hints. Use mypy for type checking:
# Type check the codebase
mypy testmcpy
# Check a specific file
mypy testmcpy/cli.pyExample with good type hints:
from typing import Dict, List, Optional
async def evaluate_test(
test_case: Dict[str, Any],
result: Dict[str, Any],
evaluators: List[str]
) -> Dict[str, bool]:
"""Evaluate test results using specified evaluators.
Args:
test_case: Test case configuration
result: Execution result from LLM
evaluators: List of evaluator names to run
Returns:
Dictionary mapping evaluator names to pass/fail results
"""
# Implementation
pass- Use descriptive names:
get_tool_calls()notget_tc() - Keep functions small: One function, one purpose
- Document complex logic: Add comments for non-obvious code
- Use type hints: Help others understand your code
- Handle errors gracefully: Don't let exceptions crash the CLI
- Use async/await: For I/O operations with LLMs and APIs
- Docstrings: Use Google-style docstrings for all public functions
- Comments: Explain why, not what (code shows what)
- Type hints: Required for all public functions
- Examples: Add examples in docstrings for complex functions
Example:
def evaluate_parameter_range(
parameter_name: str,
min_value: Optional[float] = None,
max_value: Optional[float] = None
) -> bool:
"""Check if a parameter value is within the specified range.
Args:
parameter_name: Name of the parameter to check
min_value: Minimum allowed value (inclusive), None for no minimum
max_value: Maximum allowed value (inclusive), None for no maximum
Returns:
True if value is in range, False otherwise
Examples:
>>> evaluate_parameter_range("temperature", min_value=0, max_value=1)
True
>>> evaluate_parameter_range("count", min_value=1)
True
"""
# Implementation
passBuilding a welcoming, inclusive community is core to testmcpy's success.
- Welcoming: We welcome contributors of all skill levels and backgrounds
- Respectful: Treat everyone with respect and professionalism
- Collaborative: Share knowledge, help others learn, and work together
- Inclusive: Use inclusive language and consider diverse perspectives
- Constructive: Give helpful feedback and receive it graciously
- Open: Be transparent about decisions and open to new ideas
This framework supports both free/local and paid API providers:
- Always maintain support for free/local options (Ollama, local models)
- Test changes with multiple providers when possible (Anthropic, OpenAI, Ollama)
- Document provider-specific requirements clearly
- Ensure core functionality works without paid APIs
- Make paid features optional, not required
This ensures testmcpy remains accessible to everyone, regardless of budget.
- Modularity: Keep components loosely coupled and highly cohesive
- Testability: Write code that can be easily tested
- Documentation: Document public APIs and complex logic
- Performance: Consider performance implications, especially for test execution
- Usability: Prioritize user experience in CLI design
- Extensibility: Make it easy for users to add custom evaluators and integrations
- Issues: Use GitHub Issues for bug reports and feature requests
- Discussions: Use GitHub Discussions for questions and community chat
- Pull Requests: Use PRs for code contributions with clear descriptions
- Be patient: Maintainers are often volunteers with limited time
- Be specific: Provide details, examples, and context in issues and PRs
We welcome contributions in many areas. Here are some ideas to get started:
- Evaluators: Add new evaluators for common testing scenarios
- Provider support: Add support for more LLM providers (prioritize open-source/local)
- Documentation: Improve guides, add examples, fix typos
- Examples: Add example test suites for different MCP services
- Bug fixes: Fix reported issues and improve error handling
- Reporting: Enhanced reporting and visualization of test results
- Performance: Optimize test execution and parallel processing
- CLI UX: Improve command-line usability and help text
- Templates: Create test case templates for different domains
- Error messages: Better error messages and debugging tools
Looking for a way to get started? Look for issues labeled good-first-issue:
- Documentation improvements
- Adding new evaluators with examples
- Writing test cases
- Fixing simple bugs
- Improving error messages
- Advanced configuration options
- Integration with CI/CD platforms
- Cost tracking and optimization features
- Performance benchmarking tools
We're here to help you contribute successfully!
- Documentation: Start with README.md
- API Reference: Check docs/EVALUATOR_REFERENCE.md
- Client Guide: See docs/CLIENT_USAGE_GUIDE.md
- Examples: Browse the
tests/directory for examples
- GitHub Discussions: Best place for general questions and discussions
- Issue Comments: Ask questions on specific issues
- Pull Request Reviews: Clarify feedback in PR comments
When reporting bugs:
- Search first: Check if the issue already exists
- Provide details: Include steps to reproduce, expected vs actual behavior
- Include context: OS, Python version, testmcpy version
- Share config: Include relevant configuration (remove API keys!)
- Show errors: Include full error messages and stack traces
When requesting features:
- Describe the problem: What are you trying to accomplish?
- Propose a solution: How might this feature work?
- Consider alternatives: What other approaches have you considered?
- Gauge interest: Would others benefit from this feature?
Before submitting your pull request, ensure:
- Code follows project style guide (Black formatting, type hints)
- All tests pass (
testmcpy run tests/) - Code is properly formatted (
black .) - No linting errors (
flake8 .) - New tests added for new functionality
- Documentation updated if needed
- Commit messages follow conventional commits format
- Branch is up to date with main
- No API keys or credentials in code
- PR description is clear and complete
If you discover a security vulnerability, please report it via GitHub Security Advisories instead of opening a public issue. See SECURITY.md for details.
When contributing:
- Never commit API keys, tokens, or credentials
- Use
.envfiles for local secrets (already in.gitignore) - Validate user input in CLI commands
- Handle errors without exposing sensitive information
- Use HTTPS for all API calls
By contributing, you agree that your contributions will be licensed under the Apache License 2.0.
This means:
- Your code will be open source
- Anyone can use, modify, and distribute it
- You retain copyright to your contributions
- You grant others permission to use your code
We value and recognize all contributors!
- Contributors list: All contributors are listed in release notes
- Significant contributions: Major features may be highlighted in README
- First-time contributors: We celebrate your first contribution
- Documentation: Non-code contributions are equally valued
Your contributions make testmcpy better for everyone. Thank you!
- MCP Documentation: Model Context Protocol
- Anthropic API: Anthropic Docs
- Python Async: Async/Await Guide
- Type Hints: Python Type Hints
- fastmcp: Fast MCP server implementation
- claude-agent-sdk: Claude agent SDK
- MCP servers: Various MCP server implementations
Still have questions? Don't hesitate to ask!
- Open a GitHub Discussion
- Comment on an existing issue
- Reach out in your pull request
We're here to help you succeed. Welcome to the testmcpy community!
Thank you for contributing to testmcpy!