Skip to content

Latest commit

 

History

History
166 lines (128 loc) · 7.75 KB

File metadata and controls

166 lines (128 loc) · 7.75 KB

AGENTS.md (Guidance for AI Assistants)

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.

Project Overview

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.

Project Structure & Module Organization

  • 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 in pytest.ini and tests/conftest.py.
  • website/ - The Next.js site; static assets live in website/public/.
  • flake.nix - Defines the Nix dev shell and build instructions.
  • pyproject.toml - Defines Python packaging and dependencies.
  • dist/, htmlcov/, and result/ are generated artifacts; do not edit by hand.

Key Architecture

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.

Data Sources

  • 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.

Build, Test, and Development Commands

This project uses Nix flakes exclusively for development and building.

With Nix Development Shell (Recommended)

# 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

Python-only Development

# 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

Testing Guidelines

  • Pytest with pytest-asyncio (auto mode enabled, function-scoped event loops); async tests are standard.
  • Mark tests with @pytest.mark.unit or @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).

Running Specific Tests

# 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

Coding Style & Naming Conventions

  • Python 3.11+; 4-space indentation; max line length 120 (ruff enforces).
  • Use snake_case for functions/vars, PascalCase for classes; tests named test_*.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 in pyproject.toml.

Installation & Configuration

As a Nix Package

# 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
  };
}

MCP Client Configuration (Claude Desktop, etc.)

{
  "mcpServers": {
    "nixos": {
      "type": "stdio",
      "command": "nix",
      "args": ["run", "github:utensils/mcp-nixos"]
    }
  }
}

Important Implementation Notes

  1. Channel Resolution: The server dynamically discovers available NixOS channels on startup. "stable" always maps to the current stable release.
  2. Error Handling: All tools return helpful plain text error messages. API failures gracefully degrade.
  3. No Caching: Version 1.0+ removed all caching for simplicity. All queries hit live APIs.
  4. 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.
  5. Plain Text Output: All responses are formatted as human-readable plain text. Never return raw JSON or XML to users.
  6. Environment Variables: ELASTICSEARCH_URL overrides the NixOS search backend for local testing.
  7. Flake Inputs: The flake-inputs action requires nix to be installed locally. It uses nix flake archive --json to discover inputs and their store paths, with security validation to ensure paths stay within /nix/store/.
  8. Binary Cache Status: The cache action 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.
  9. NixHub Source: The nixhub source provides rich package metadata including license, homepage, programs, and store paths via the search.devbox.sh API.

Commit, PR, & Release Guidelines

  • 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 /release skill to automate version releases. This handles version bumps in pyproject.toml, changelog updates in RELEASE_NOTES.md, and Git tagging.
  • Release merges include release: vX.Y.Z in the merge commit message.