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 setupMonorepo Structure
MCP Hangar is a monorepo:
mcp-hangar/
├── src/mcp_hangar/ # Python package (PyPI: mcp-hangar) -- MIT
├── enterprise/ # BSL 1.1 licensed features
│ ├── auth/ # RBAC, API key, JWT/OIDC
│ ├── behavioral/ # Network profiling, deviation detection
│ ├── identity/ # Caller identity propagation, audit
│ ├── compliance/ # SIEM export (CEF, LEEF, JSON-lines)
│ ├── persistence/ # SQLite/Postgres event stores
│ ├── semantic/ # Pattern engine, detection rules
│ └── integrations/ # Langfuse adapter
├── tests/ # Python tests
├── packages/
│ ├── operator/ # Kubernetes operator (Go)
│ │ ├── api/ # CRD definitions
│ │ ├── cmd/ # Main entrypoints
│ │ ├── internal/ # Controller logic
│ │ └── go.mod # Go module config
│ ├── ui/ # React dashboard
│ └── helm-charts/ # Helm charts
│ ├── mcp-hangar/ # Core Helm chart
│ └── mcp-hangar-operator/ # Operator Helm chart
├── docs/ # MkDocs documentation
├── examples/ # Quick starts, OTEL recipes
├── monitoring/ # Grafana, Prometheus configs
└── Makefile # Root orchestrationPython Core Structure
src/mcp_hangar/
├── domain/ # DDD domain layer
│ ├── model/ # Aggregates, entities
│ ├── services/ # Domain services
│ ├── events.py # Domain events
│ ├── contracts/ # Interfaces consumed by enterprise/
│ └── exceptions.py
├── application/ # Application layer
│ ├── commands/ # CQRS commands
│ ├── queries/ # CQRS queries
│ ├── ports/ # Port interfaces consumed by enterprise/
│ └── 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 workersLicensing
- Core (
src/) -- MIT. No CLA required. - Enterprise (
enterprise/) -- BSL 1.1. CLA required for contributions. See CLA.md. - Core must never import from
enterprise/. CI enforces this boundary.
Code Style
ruff check src tests --fix
ruff format src tests
mypy src/mcp_hangarConventions
| Item | Style |
|---|---|
| Classes | PascalCase |
| Functions | snake_case |
| Constants | UPPER_SNAKE_CASE |
| Events | PascalCase + past tense (ProviderStarted) |
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 testTarget: >80% coverage on new code.
Writing Tests
def test_tool_invocation():
# Arrange
provider = Provider(provider_id="test", mode="subprocess", command=[...])
# Act
result = provider.invoke_tool("add", {"a": 1, "b": 2})
# Assert
assert result["result"] == 3Pull Requests
Create feature branch
Make changes following style guidelines
Add tests
Run checks:
bashpytest -v -m "not slow" pre-commit run --all-filesUpdate docs if needed
PR Template
## Description
Brief description.
## Type
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
## Testing
- [ ] Unit tests added
- [ ] All tests passArchitecture Guidelines
Value Objects:
provider_id = ProviderId("my-provider") # ValidatedEvents:
provider.ensure_ready()
for event in provider.collect_events():
event_bus.publish(event)Exceptions:
# Basic usage
raise ProviderStartError(
provider_id="my-provider",
reason="Connection refused"
)
# With diagnostics (preferred)
raise ProviderStartError(
provider_id="my-provider",
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:
provider.ensure_ready()
except ProviderStartError as e:
print(e.get_user_message())Logging:
logger.info("provider_started: %s, mode=%s", provider_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
Option 1: Automated (Recommended)
Use the GitHub Actions workflow:
- Go to Actions → Version Bump
- Click Run workflow
- Select bump type:
patch,minor, ormajor - Optionally select pre-release suffix (
alpha.1,beta.1,rc.1) - Run (or use dry run to preview)
The workflow will:
- Update version in
pyproject.toml - Update
CHANGELOG.mdwith release date - Create and push the version tag
- Trigger the release pipeline automatically
Option 2: Manual
# 1. Update version in pyproject.toml
sed -i '' 's/version = ".*"/version = "1.2.0"/' pyproject.toml
# 2. Update CHANGELOG.md - move Unreleased items to new version section
# 3. Commit changes
git add pyproject.toml CHANGELOG.md
git commit -m "chore: bump version to 1.2.0"
# 4. Create annotated tag
git tag -a v1.2.0 -m "Release v1.2.0"
# 5. Push
git push origin main
git push origin v1.2.0Pre-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 candidateInstall pre-release:
pip install --index-url https://test.pypi.org/simple/ mcp-hangar==1.0.0rc1Release 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:
# 1. Create hotfix branch from tag
git checkout -b hotfix/1.0.1 v1.0.0
# 2. Apply fix, add tests
# 3. Update version and changelog
# 4. Tag and push
git tag -a v1.0.1 -m "Hotfix: description"
git push origin v1.0.1
# 5. Cherry-pick to main if applicable
git checkout main
git cherry-pick <commit-hash>Licensing Model
MCP Hangar uses a dual-license model:
| Directory | License | CLA Required |
|---|---|---|
src/mcp_hangar/ | MIT | No |
tests/, docs/, examples/, monitoring/ | MIT | No |
enterprise/ | BSL 1.1 | Yes |
Contributing to enterprise/
Contributions to enterprise/ require agreeing to the Contributor License Agreement. Include this statement in your PR description:
I have read and agree to the MCP Hangar Contributor License Agreement (CLA.md). My contribution to enterprise/ is my original work and I grant the rights described therein.
See CLA.md for full terms. Core (MIT) contributions do not require a CLA.
Code of Conduct
Please read our Code of Conduct before contributing.
First Contribution?
Look for issues labeled good first issue.
Questions? Open a Discussion.