Contributing to frisian-mcp
Category: guide
Slug: contributing
Audience: Developers contributing to the frisian-mcp package
Overview
frisian-mcp welcomes contributions. This guide covers the fork-based workflow, code quality standards, and the PR process. Following these steps keeps the review cycle short and the history clean.
Fork Workflow
1. Fork the repository
Fork Frisian-MCP/frisian-mcp on GitHub. Clone your fork locally:
git clone https://github.com/<your-username>/frisian-mcp.git
cd frisian-mcp
Add the upstream remote so you can pull in future changes:
git remote add upstream https://github.com/Frisian-MCP/frisian-mcp.git
2. Create a feature branch
Never commit directly to main. Create a branch from the latest upstream main:
git fetch upstream
git checkout -b feat/your-feature-name upstream/main
Branch naming conventions:
| Prefix | Use case |
|---|---|
feat/ |
New feature or capability |
fix/ |
Bug fix |
docs/ |
Documentation only |
refactor/ |
Code restructure, no behavior change |
chore/ |
Tooling, deps, CI |
3. Make your changes
Keep commits small and focused. Each commit should represent one logical change. Write commit messages in the imperative mood: Add dispatcher caching layer, not Added or Adds.
4. Sync with upstream before submitting
Before opening a PR, rebase onto the latest upstream main to reduce merge conflicts for reviewers:
git fetch upstream
git rebase upstream/main
Resolve any conflicts, then push:
git push origin feat/your-feature-name
5. Open a pull request
Open the PR against Frisian-MCP/frisian-mcp main. Fill in the PR template (see PR Checklist below).
Development Setup
Install with dev dependencies
pip install -e ".[dev]"
This installs the package in editable mode along with all linting and testing dependencies.
Pre-commit hooks
frisian-mcp uses pre-commit to run linting checks automatically before every commit.
Install the hooks once after cloning:
pip install pre-commit
pre-commit install
Run all hooks manually against the full codebase:
pre-commit run --all-files
The hooks run mypy and pylint on every staged Python file. A commit is rejected if either tool reports errors. Fix all errors before committing — do not use --no-verify.
Linting Standards
mypy — static type checking
frisian-mcp enforces strict type annotations throughout the codebase. All public functions and methods require type annotations. The mypy configuration is in pyproject.toml under [tool.mypy].
Run mypy directly:
mypy frisian_mcp/
Key rules:
- All function parameters and return values must be annotated
Anyis permitted only where a third-party library forces it — document the reason with a commentOptional[X]is equivalent toX | None; prefer the union syntax on Python 3.10+- Use
TYPE_CHECKINGguards for imports that are only needed for annotations
Common fixes:
# Wrong — missing return type
def get_tool_list(self):
...
# Correct
def get_tool_list(self) -> list[ToolDefinition]:
...
# Wrong — implicit Any via untyped dict
def build_response(data):
...
# Correct
def build_response(data: dict[str, object]) -> MCPResponse:
...
pylint — code quality
pylint is configured in pyproject.toml under [tool.pylint]. The project targets a minimum score of 9.0/10.
Run pylint directly:
pylint frisian_mcp/
Enforced rules include:
- No unused imports or variables
- No shadowed builtins
- Maximum function length: 50 lines (refactor into helpers beyond this)
- Maximum file length: 400 lines
- Docstrings required on all public classes and functions (one-line summaries are fine)
- No broad
except Exceptionwithout re-raising or logging
Disable a rule inline only when the library genuinely requires it, and always include the reason:
# pylint: disable=protected-access # testing internal cache eviction
result = dispatcher._cache._store
Pre-commit Hook Configuration
The .pre-commit-config.yaml at the repo root configures all hooks. The relevant hooks in order:
- trailing-whitespace — removes trailing whitespace
- end-of-file-fixer — ensures files end with a newline
- check-yaml — validates YAML syntax
- mypy — type checking via
mypy frisian_mcp/ - pylint — code quality via
pylint frisian_mcp/
All hooks must pass before the commit is accepted. If a hook auto-fixes a file (trailing whitespace, newlines), stage the fix and commit again:
git add -u
git commit
Testing
Run the test suite before opening a PR:
pytest
New features require accompanying tests. Bug fixes require a regression test that would have caught the bug. Tests live under tests/ and mirror the package structure.
Coverage is measured but not gated at a hard threshold. Aim to keep coverage above 85% on changed files.
PR Checklist
Before requesting review, verify:
- Branch is rebased onto the latest
upstream/main -
pre-commit run --all-filespasses with zero errors -
mypy frisian_mcp/reports no new errors -
pylint frisian_mcp/score is 9.0/10 or higher -
pytestpasses with no failures - New public functions/classes have docstrings
- New features have tests; bug fixes have a regression test
- CHANGELOG entry added under
[Unreleased]if the change is user-facing - PR description explains why the change is needed, not just what it does
Code of Conduct
This project follows the Contributor Covenant Code of Conduct. Be direct, constructive, and professional in all interactions.
Document maintained alongside the frisian-mcp source.