Contributing to Kitsune MCP¶
Thank you for helping make Kitsune better! This guide gets you to a working dev setup in under 5 minutes.
Questions or ideas? Open an issue.
Quick Setup¶
git clone https://github.com/kaiser-data/kitsune-mcp
cd kitsune-mcp
make dev # install kitsune-mcp, dev deps and docs deps (uv)
make test # run all tests
make lint # ruff check + format check
make format # auto-format with ruff
make docs # preview the docs site at http://127.0.0.1:8000
Running pytest directly? The test config in
pyproject.toml(addopts) requirespytest-timeout, which is a dev dependency. A bareuv run pytestfails to start withunrecognized arguments: --timeout. Usemake test, or include the dev extra:uv run --extra dev pytest tests/.
Tool Patterns¶
Tools live in kitsune_mcp/tools/ and follow this pattern:
@mcp.tool()
async def my_tool(param: str, optional: int = 5) -> str:
"""One-line description. param: what it does."""
# ... implementation
return _truncate(result)
Rules:
- Return str always — FastMCP serializes everything
- Use _truncate() on any response that could be large
- Use _clean_response() on raw external content
- Update session["stats"] for call counts
- Add the tool name to _BASE_TOOL_NAMES in kitsune_mcp/tools/_state.py,
and to _LEAN_TOOL_NAMES only if it belongs in the default profile
Transport Patterns¶
Adding a new transport? Subclass BaseTransport in kitsune_mcp/transport.py:
class MyTransport(BaseTransport):
async def execute(self, tool: str, args: dict, config: dict) -> str:
# connect, call, return str
...
Add a test in tests/test_transports.py with a respx or subprocess mock.
Commit Style¶
feat: add PersistentStdioTransport for hardware servers
fix: handle timeout in StdioTransport._read_response
docs: add hardware.md connect/release guide
test: add test_connect_returns_tool_list
PR Checklist¶
- [ ]
make testpasses - [ ]
make lintpasses (zero ruff errors) - [ ] New tools are in
_BASE_TOOL_NAMES(and_LEAN_TOOL_NAMESif lean) - [ ] New tools are documented in
docs/tools.md;make docsrenders it - [ ] Tests cover the happy path + at least one error case
Adding a New Server Integration¶
If you found a server that works well with Kitsune, open a "New Server" issue:
- Server ID (e.g. @modelcontextprotocol/server-filesystem)
- Transport type: http or stdio
- Any error from call() or shapeshift() you hit
Project Structure¶
server.py # entry point: loads .env, registers tools, prunes to the profile
server_forge.py # kitsune-forge entry point (all tools)
kitsune_mcp/
app.py # the shared FastMCP instance
tools/ # the MCP tools (discovery, exec, shapeshift, onboarding)
_state.py # tool-name sets for the lean and full profiles
transport.py # stdio, HTTP/SSE, WebSocket, persistent and Docker transports
registry.py # registry clients (official, MCP Registry, Glama, npm, PyPI, Smithery)
shapeshift.py # mounting proxied tools, resources and prompts
credentials.py # .env handling and credential checks
guard.py, pins.py # action guard and version pins
tests/ # pytest suite
docs/ # the docs site (MkDocs Material, see mkdocs.yml)
examples/ # demo servers and scenarios