Contributing#
Thank you for your interest in contributing to the OpenSWMM MCP Server. This guide covers development setup, coding standards, and the pull request process.
Development Setup#
Clone the repository:
git clone https://github.com/HydroCouple/openswmm.mcp.git cd openswmm.mcp
Create a virtual environment:
python -m venv .venv source .venv/bin/activate # Linux/macOS .venv\Scripts\activate # Windows
Install in editable mode with dev extras:
pip install -e ".[dev,docs]"
Verify the installation:
pytest tests/unit/ -v ruff check src/ tests/ ruff format --check src/ tests/
Project Layout#
src/openswmm_mcp/ # Main package (src layout)
tests/
unit/ # Unit tests (mock engine, no C extensions needed)
integration/ # Integration tests (require compiled openswmm engine)
mocks/ # Mock engine classes
docs/ # Sphinx documentation
Coding Standards#
Style#
Formatter: Ruff (
ruff format).Linter: Ruff (
ruff check) with rules:E,F,I,W,UP.Line length: 100 characters.
Target Python: 3.10+.
Type Annotations#
All public functions and methods should have type annotations.
Use
from __future__ import annotationsfor PEP 604 union syntax (X | Y).Pydantic models define the schema for all tool responses.
Docstrings#
Use NumPy-style docstrings for tool functions (these are rendered by Napoleon in Sphinx and surfaced to MCP clients as tool descriptions).
Module-level docstrings describe the purpose of each file.
Async Conventions#
All tool functions are
async.Engine calls (synchronous Cython bindings) are wrapped in
asyncio.to_thread().Use
asyncio.Lockfor shared state protection inSessionManager.
Adding a New Tool#
Identify the appropriate sub-server module in
src/openswmm_mcp/tools/.Define the tool function with
@sub_mcp.tool()decorator.Add parameter type annotations – FastMCP generates the JSON schema from these.
Use
get_session_manager(ctx)andrequire_state()for session access.Wrap engine calls in
asyncio.to_thread().Return a Pydantic model or dict.
Add a corresponding unit test in
tests/unit/.Update the documentation in
docs/user-guide/tools.md.
Running Tests#
Unit Tests#
Unit tests use mock engine classes and the in-memory MCP client. They do not
require the compiled openswmm engine.
pytest tests/unit/ -v
With Coverage#
pytest tests/unit/ -v --cov=openswmm_mcp --cov-report=term-missing
Integration Tests#
Integration tests require a compiled openswmm engine installation. They
are marked with @pytest.mark.integration and skipped by default.
OPENSWMM_RUN_INTEGRATION=1 pytest tests/integration/ -v
Linting#
ruff check src/ tests/
ruff format --check src/ tests/
To auto-fix:
ruff check --fix src/ tests/
ruff format src/ tests/
Building Documentation#
sphinx-build -W -b html docs docs/_build/html
Open docs/_build/html/index.html in a browser to preview.
Pull Request Process#
Branch from
main: Create a feature branch with a descriptive name (e.g.feature/add-pump-tools,fix/session-cleanup).Write tests first: Ensure new functionality has corresponding unit tests. Aim for 80 %+ coverage on new code.
Run CI checks locally:
ruff check src/ tests/ ruff format --check src/ tests/ pytest tests/unit/ -v --cov=openswmm_mcp sphinx-build -W -b html docs docs/_build/html
Commit with clear messages: Use imperative mood (e.g. “Add pump speed forcing tool”).
Open a pull request: Target
main. Include a summary of changes and a test plan.CI must pass: The GitHub Actions CI workflow runs linting, tests across Python 3.10–3.13 on Ubuntu/macOS/Windows, and the documentation build.
Review: At least one maintainer approval is required before merging.
Reporting Issues#
Open an issue on GitHub with:
A clear description of the problem or feature request.
Steps to reproduce (for bugs).
Python version and operating system.
Relevant logs or error messages.