# Contributing to jumperless-mcp
Thanks for thinking about contributing! This project is small and welcoming.
There's no formal process — issues, PRs, and questions are all good.
## Filing an issue
[github.com/LesbianVelociraptor/jumperless-mcp/issues](https://github.com/LesbianVelociraptor/jumperless-mcp/issues)
Useful info to include for bug reports:
- Output of `jumperless-mcp --version`
- Output of `jumperless-mcp firmware-probe --json`
- Your OS and version
- What you did, what you expected, what happened
- Any error messages or weird behavior
For feature requests: tell us what you're trying to do, not just what
you want added. We might already have a tool that does it, or there
might be a simpler shape we'd land on together.
## Submitting a PR
1. **Fork the repo** on GitHub and clone your fork locally.
2. **Make a branch:** `git checkout -b your-change-name`
3. **Make your changes.** Add tests if you're adding a new tool or
changing behavior. The test pattern is in any of the existing
`mcp/jumperless/src/tools/*.rs` modules — mock the serial port,
feed it canned responses, assert the handler does the right thing.
4. **Run the checks locally** before pushing:
```bash
cargo test --bin jumperless-mcp
cargo fmt --all -- --check
cargo clippy --all-targets -- -D warnings
```
If any of these complain, fix them. The CI workflow runs the same
three commands and will block your PR if they fail.
5. **Push to your fork** and open a PR against `main`.
## Code style
- **Rust:** `cargo fmt` for formatting, `clippy` clean (no warnings).
- **Tool naming:** bare names per the spec (`get_state`, `dac_set`, etc.).
The federation gateway adds the `jumperless.` prefix when needed.
- **Each tool family in its own module:** `src/tools/<family>.rs` with
`descriptors()` + `handle_*` functions. See existing modules for the
pattern.
- **Errors:** use `McpError::Protocol(format!(...))` — propagate, don't swallow.
- **Validation BEFORE device contact:** if an argument is bad, return `Err`
before writing any bytes to the serial port. Tests should assert
`port.write_data.is_empty()` on rejection paths.
## Commit messages
Plain English imperative-mood summaries. Examples:
- `Add wavegen_set_phase tool`
- `Fix is_connected returning string instead of bool`
- `Document the firmware probe subcommand`
You don't need conventional-commits (`feat:` / `fix:` prefixes), but it's
fine if you prefer that style.
## Questions
If you're not sure whether something belongs as an issue, a PR, or just
a question, file it as an issue and we'll figure it out together. There's
no bad question; this is a small project and we want it to be approachable.
## License
By contributing, you agree that your contributions are licensed under
the MIT license (same as the project itself).