Contributing
Setup
git clone https://github.com/mcp-hangar/mcp-hangar.git
cd mcp-hangar
# Install with dev dependencies
pip install -e ".[dev]"
# Or use root Makefile
make setup
Repository Structure
MCP Hangar is multi-repo, not a monorepo (see ADR-009 for the release topology this implies). The org has separate repos per shippable artifact:
mcp-hangar/mcp-hangar-- Python core (PyPI:mcp-hangar). This is the repo you cloned in Setup above, and what the rest of this guide describes.mcp-hangar/mcp-hangar-operator-- Kubernetes operator (Go).mcp-hangar/helm-charts-- themcp-hangarandmcp-hangar-operatorHelm charts.mcp-hangar/docs-- this documentation site.mcp-hangar/mcp-hangar-website-- the marketing site.mcp-hangar/terraform-provider-- Terraform provider.
Each has its own CONTRIBUTING guide, CI, and (per ADR-009) its own release
lane. This document only covers mcp-hangar/mcp-hangar.
Top-level layout of this repo:
mcp-hangar/
├── src/mcp_hangar/ # Python package (PyPI: mcp-hangar) -- MIT
│ ├── auth/ # RBAC, API key, JWT/OIDC
│ ├── approvals/ # Human-in-the-loop approval gate for tool calls
│ ├── bootstrap/ # DI composition root, module loading
│ ├── compliance/ # SIEM export (CEF, LEEF, JSON-lines)
│ ├── integrations/ # Partner integrations (Langfuse adapter)
│ ├── domain/ # DDD domain layer (see below)
│ ├── application/ # Application layer (see below)
│ ├── infrastructure/ # Infrastructure adapters (see below)
│ ├── observability/ # Tracing, metrics, health (see below)
│ ├── server/ # MCP server module (see below)
│ └── fastmcp_server/ # MCP-over-HTTP server (FastMCP-based)
├── tests/ # Python tests
├── packages/
│ └── core/ # vestigial pre-v0.13 package location; real source
│ # is src/mcp_hangar/, tracked for removal
├── docs/ # internal architecture/design docs (not this docs
│ # site -- that's the separate docs repo)
├── examples/ # Quick starts, OTEL recipes
├── monitoring/ # Grafana, Prometheus configs
├── docker/ # Per-example-server Dockerfiles
├── security/ # Seccomp profiles, network policies
├── scripts/ # Dev/release tooling
└── Makefile # Root orchestration
There is no packages/operator/, packages/ui/, or packages/helm-charts/
in this repo -- those live in the separate repos listed above.
Python Core Structure
src/mcp_hangar/
├── domain/ # DDD domain layer
│ ├── model/ # Aggregates, entities
│ ├── services/ # Domain services
│ ├── events.py # Domain events
│ ├── contracts/ # Interfaces consumed by src/mcp_hangar/
│ └── exceptions.py
├── application/ # Application layer
│ ├── commands/ # CQRS commands
│ ├── queries/ # CQRS queries
│ ├── ports/ # Port interfaces consumed by src/mcp_hangar/
│ └── sagas/
├── infrastructure/ # Infrastructure adapters
│ └── observability/ # OTLPAuditExporter
├── observability/ # Conventions, tracing, metrics, health
├── server/ # MCP server module
│ ├── bootstrap/ # DI composition root
│ ├── config.py # Configuration loading
│ ├── state.py # Global state management
│ └── tools/ # MCP tool implementations
├── stdio_client.py # JSON-RPC client
└── gc.py # Background workers
Licensing
- All code -- MIT. See LICENSE.
- Core and former enterprise code live in
src/mcp_hangar/; imports stay within package boundaries.
Code Style
ruff check src tests --fix
ruff format src tests
mypy src/mcp_hangar
Conventions
| Item | Style |
|---|---|
| Classes | PascalCase |
| Functions | snake_case |
| Constants | UPPER_SNAKE_CASE |
| Events | PascalCase + past tense (McpServerStarted) |
Type Hints
Required for all new code. Use Python 3.11+ built-in generics:
def invoke_tool(
self,
tool_name: str,
arguments: dict[str, Any],
timeout: float = 30.0,
) -> dict[str, Any]:
...
Testing
pytest -v -m "not slow"
pytest --cov=mcp_hangar --cov-report=html
# Or from root
make test
Target: >80% coverage on new code.
Writing Tests
def test_tool_invocation():
# Arrange
mcp_server = McpServer(mcp_server_id="test", mode="subprocess", command=[...])
# Act
result = mcp_server.invoke_tool("add", {"a": 1, "b": 2})
# Assert
assert result["result"] == 3
Pull Requests
See Git Flow for branching conventions, merge strategy, and commit scopes.
-
Create feature branch
-
Make changes following style guidelines
-
Add tests
-
Run checks:
pre-commit install --hook-type pre-commit pytest -v pre-commit run --all-files -
Update docs if needed
PR Template
PRs must follow the template in .github/PULL_REQUEST_TEMPLATE.md. Required sections are enforced by the pr-body / validate CI check.
Architecture Guidelines
Value Objects:
mcp_server_id = ProviderId("my-mcp-server") # Validated
Events:
mcp_server.ensure_ready()
for event in mcp_server.collect_events():
event_bus.publish(event)
Exceptions:
# Basic usage
raise McpServerStartError(
mcp_server_id="my-mcp-server",
reason="Connection refused"
)
# With diagnostics (preferred)
raise McpServerStartError(
mcp_server_id="my-mcp-server",
reason="MCP initialization failed: process crashed",
stderr="ModuleNotFoundError: No module named 'requests'",
exit_code=1,
suggestion="Install missing Python dependencies."
)
# Get user-friendly message
try:
mcp_server.ensure_ready()
except McpServerStartError as e:
print(e.get_user_message())
Logging:
logger.info("mcp_server_started: %s, mode=%s", mcp_server_id, mode)
Releasing
Release Process Overview
MCP Hangar uses automated CI/CD for releases. The process ensures quality through:
- Version Validation — Tag must match
pyproject.tomlversion - Full Test Suite — All tests across Python 3.11-3.14
- Security Scanning — Dependency audit and container scanning
- Artifact Publishing — PyPI package and Docker images
Creating a Release
Releases are automated via release-please. When Conventional Commit PRs merge to main, release-please maintains a long-running Release PR that bumps the version and updates the changelog. Merging that PR creates the version tag, which release.yml consumes to publish to PyPI and GHCR.
See RELEASE.md for the full operational runbook.
Pre-release Versions
Pre-releases are automatically published to TestPyPI:
# Tag patterns for pre-releases
v1.0.0-alpha.1 # Alpha release
v1.0.0-beta.1 # Beta release
v1.0.0-rc.1 # Release candidate
Install pre-release:
pip install --index-url https://test.pypi.org/simple/ mcp-hangar==1.0.0rc1
Release Checklist
Before releasing, ensure:
- All tests pass locally:
pytest -v - Linting passes:
pre-commit run --all-files - CHANGELOG.md is updated with all notable changes
- Documentation is updated for new features
- Breaking changes are clearly documented
- Version follows Semantic Versioning
Versioning Guidelines
We follow Semantic Versioning (SemVer):
| Change Type | Version Bump | Example |
|---|---|---|
| Bug fixes, patches | PATCH | 1.0.0 → 1.0.1 |
| New features (backward-compatible) | MINOR | 1.0.1 → 1.1.0 |
| Breaking changes | MAJOR | 1.1.0 → 2.0.0 |
Release Artifacts
Each release produces:
| Artifact | Location | Tags |
|---|---|---|
| Python Package | PyPI | Version number |
| Docker Image | GHCR | latest, X.Y.Z, X.Y, X |
| GitHub Release | Repository Releases | Changelog, install instructions |
Hotfix Process
For urgent fixes on released versions, follow the HOTFIX_RUNBOOK.md.
Licensing Model
MCP Hangar is licensed under the MIT License:
| Directory | License |
|---|---|
src/mcp_hangar/ | MIT |
tests/, docs/, examples/, monitoring/ | MIT |
Code of Conduct
Please read our Code of Conduct before contributing.
First Contribution?
Look for issues labeled good first issue.
Questions? Open a Discussion.