This file provides guidance to Claude Code (claude.ai/code) and other AI agents when working with code in this repository. It combines general repository guidelines with specific implementation details for the MCP server.
MCP-NixOS is a Model Context Protocol (MCP) server that provides accurate, real-time information about NixOS packages, configuration options, Home Manager, nix-darwin, and flakes. It prevents AI assistants from hallucinating about NixOS package names and configurations by querying official APIs and documentation.
mcp_nixos/- Contains the MCP server implementation.mcp_nixos/server.py- MCP tools, tool routing, and main entry point.mcp_nixos/config.py- Configuration constants (API URLs, auth, limits).mcp_nixos/caches.py- Cache implementations (channels, nixvim, noogle, nix.dev).mcp_nixos/utils.py- Shared utility functions (HTML parsing, formatting, file I/O).mcp_nixos/sources/- Data source implementations (one module per source):base.py- Channel helpers, Elasticsearch queries, browsing utilities.nixos.py- NixOS packages/options search, info, stats.home_manager.py- Home Manager options.darwin.py- nix-darwin options.flakes.py- Flake search from search.nixos.org.flakehub.py- FlakeHub API (Determinate Systems).wiki.py- NixOS Wiki search.nixdev.py- nix.dev documentation.nixvim.py- Nixvim options.noogle.py- Noogle function search.nixhub.py- NixHub API + binary cache status.flake_inputs.py- Local flake inputs via nix store.
tests/- Holds pytest unit and integration tests; markers live inpytest.iniandtests/conftest.py.website/- The Next.js site; static assets live inwebsite/public/.flake.nix- Defines the Nix dev shell and build instructions.pyproject.toml- Defines Python packaging and dependencies.dist/,htmlcov/, andresult/are generated artifacts; do not edit by hand.
The project is a FastMCP 2.x server (async) with a modular structure (Python 3.11+). The server is organized into focused modules: server.py handles MCP tools and routing, sources/ contains per-source implementations, config.py defines constants, caches.py manages cached data, and utils.py provides shared utilities.
Only 2 MCP tools are exposed (consolidated from 17 in v1.0):
nix- Unified query tool for search/info/stats/options/channels/flake-inputs across all sources.nix_versions- Package version history from NixHub.io.
- NixOS packages/options: Elasticsearch API at search.nixos.org
- Home Manager options: HTML parsing from official docs
- nix-darwin options: HTML parsing from official docs
- Package versions: NixHub.io API (search.devbox.sh)
- Package metadata: NixHub.io API for license, homepage, store paths
- Binary cache status: cache.nixos.org narinfo queries
- Flakes: search.nixos.org flake index
- Local flake inputs: Direct access to /nix/store via
nix flake archive
All responses are formatted as plain text for optimal LLM consumption.
This project uses Nix flakes exclusively for development and building.
# Enter dev shell (auto-activates Python venv)
nix develop
# Core commands (available via menu):
run # Start the MCP server
run-tests # Run all tests (with coverage in CI)
lint # Check code with ruff
format # Format code with ruff
typecheck # Run mypy type checker
build # Build the package/distributions# Install with development dependencies
uv pip install -e ".[dev]" # or pip install -e ".[dev]"
# Run server
uv run mcp-nixos # or python -m mcp_nixos.server- Pytest with
pytest-asyncio(auto mode enabled, function-scoped event loops); async tests are standard. - Mark tests with
@pytest.mark.unitor@pytest.mark.integration. - Integration tests hit real APIs (no mocks).
- Coverage is enabled by default (
--cov=mcp_nixos). - For flaky integration tests, use
@pytest.mark.flaky(reruns=3). - Tests ensure plain text output (no XML/JSON leakage).
# Run a single test file
pytest tests/test_server.py
# Run a single test function
pytest tests/test_server.py::test_nixos_search -v
# Run tests matching a pattern
pytest tests/ -k "nixos" -v- Python 3.11+; 4-space indentation; max line length 120 (ruff enforces).
- Use
snake_casefor functions/vars,PascalCasefor classes; tests namedtest_*.py. - Keep MCP responses plain text (no raw JSON) to match server behavior.
- Never bypass linting: Do not use
# noqa,# type: ignore,# pylint: disable, or similar comments to suppress linter/type checker warnings. Fix the underlying issue instead. If a lint rule is genuinely wrong for the project, update the ruff/mypy configuration inpyproject.toml.
# In your flake.nix
{
inputs.mcp-nixos.url = "github:utensils/mcp-nixos";
outputs = { nixpkgs, mcp-nixos, ... }: {
# Use the overlay to add pkgs.mcp-nixos
nixpkgs.overlays = [ mcp-nixos.overlays.default ];
# Then use in your config:
# environment.systemPackages = [ pkgs.mcp-nixos ]; # NixOS
# home.packages = [ pkgs.mcp-nixos ]; # Home Manager
};
}{
"mcpServers": {
"nixos": {
"type": "stdio",
"command": "nix",
"args": ["run", "github:utensils/mcp-nixos"]
}
}
}- Channel Resolution: The server dynamically discovers available NixOS channels on startup. "stable" always maps to the current stable release.
- Error Handling: All tools return helpful plain text error messages. API failures gracefully degrade.
- No Caching: Version 1.0+ removed all caching for simplicity. All queries hit live APIs.
- Async Everything: Version 1.0.1 migrated to FastMCP 2.x. All tools are async functions. All blocking HTTP calls and file I/O are wrapped in
asyncio.to_thread()to prevent blocking the event loop. - Plain Text Output: All responses are formatted as human-readable plain text. Never return raw JSON or XML to users.
- Environment Variables:
ELASTICSEARCH_URLoverrides the NixOS search backend for local testing. - Flake Inputs: The
flake-inputsaction requires nix to be installed locally. It usesnix flake archive --jsonto discover inputs and their store paths, with security validation to ensure paths stay within/nix/store/. - Binary Cache Status: The
cacheaction queries cache.nixos.org to check if packages have pre-built binaries. It uses NixHub to resolve package versions to store paths, then checks narinfo availability. - NixHub Source: The
nixhubsource provides rich package metadata including license, homepage, programs, and store paths via the search.devbox.sh API.
- Commit messages follow
type: summary(e.g.,feat:,fix:,docs:,refactor:,test:,chore:). - CI: Runs on all PRs - flake check, Nix build, Python distribution build, package validation (twine), linting, type checking, tests.
- Publish: Automated PyPI releases on version tags (v*), multi-arch Docker images to GHCR and Docker Hub.
- Release Process: Use the
/releaseskill to automate version releases. This handles version bumps inpyproject.toml, changelog updates inRELEASE_NOTES.md, and Git tagging. - Release merges include
release: vX.Y.Zin the merge commit message.