Thanks for considering a contribution. This project is small enough that the workflow is short, but specific.
git clone https://github.com/celticht32/cb-analytics-mcp
cd cb-analytics-mcp
make devThat creates a .venv/ and installs everything (runtime + dev) editably.
One command runs every static check plus the full unit test suite:
make scan # or: bash scripts/deep_scan.shPass = your change is ready to push. If any of pyflakes, ruff, mypy (strict), bandit, or pytest fails, the script exits non-zero and tells you which one. Coverage must stay at or above 80 %.
You can run the individual scanners too:
make pyflakes
make ruff
make mypy
make bandit
make test
make coverage # adds HTML report at htmlcov/- Tests for new behaviour. Tools have a paired
_impl()that's easy to unit-test withFakePool— seetests/unit/mcp/test_tool_impls.pyfor the pattern. GUI routes use FastAPI'sTestClient— seetests/unit/gui/test_dashboard.py. make scanclean. No exceptions; if a check is wrong, fix it or configure it, don't silence it.- Type annotations on new functions. mypy is strict; untyped signatures will fail.
- One change per PR. Renames, refactors, and behaviour changes go separately so they review cleanly.
CHANGELOG.mdentry under## [Unreleased]for anything user- facing (new tool, new env var, GUI change, behaviour change).
ruff formatis the source of truth — runruff format src testsbefore committing.- Line length 110 (set in
pyproject.toml). - Prefer small modules over large ones. Each MCP tool group is its own file; new groups should follow the same pattern.
- For new MCP tools, use the
_impl()+register()split. The_implis the testable unit;register()only wraps it withcall_tool_observed. - Secrets go through
pydantic.SecretStrand the redactor sees them. Never log a raw secret.
- Pick the right tool module (or create a new one matching the existing
tools/<group>.pypattern). - Write the
<name>_impl()function — async, takes the pool plus typed args, returns the result offmt_ok(...). - Add a
@mcp.tool()wrapper in the module'sregister()function that callscall_tool_observed(...). - Add unit tests in
tests/unit/mcp/test_tool_impls.py(mock the pool, assert the right client method was called). - Update
docs/tool-reference.mdwith the new tool's signature. - Update the matching skill in
.claude/skills/if behaviour changes. - Add a
CHANGELOG.mdentry.
Open a GitHub issue with:
- What you did (the exact tool call or steps).
- What you expected.
- What happened (with the relevant log line — keep the timestamp, redact secrets if any slipped through).
cb-analytics-mcp --versionand your Python version.
Don't open a public issue for security problems. See
SECURITY.md.
By contributing, you agree your contributions are licensed under the MIT license, the same as the rest of the project.