Skip to main content
Glama

mcp-nixos

by utensils
flake.nix22.6 kB
{ description = "MCP-NixOS - Model Context Protocol server for NixOS and Home Manager resources"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; devshell.url = "github:numtide/devshell"; }; outputs = { self, nixpkgs, flake-utils, devshell, }: flake-utils.lib.eachDefaultSystem ( system: let pkgs = import nixpkgs { inherit system; overlays = [ devshell.overlays.default ]; }; pythonVersion = "312"; python = pkgs."python${pythonVersion}"; ps = pkgs."python${pythonVersion}Packages"; # Use a single Python instance with proper library support pythonWithLibs = python.buildEnv.override { extraLibs = [ ps.cffi ps.wheel ps.setuptools ps.pip ]; ignoreCollisions = true; }; setupVenvScript = pkgs.writeShellScriptBin "setup-venv" '' set -e echo "--- Setting up Python virtual environment ---" # Check for pyproject.toml or setup.py if [ ! -f "pyproject.toml" ] && [ ! -f "setup.py" ]; then echo "Error: Neither pyproject.toml nor setup.py found. Cannot install dependencies." exit 1 fi if [ ! -d ".venv" ]; then echo "Creating Python virtual environment in ./.venv ..." ${pythonWithLibs}/bin/python -m venv .venv else echo "Virtual environment ./.venv already exists." fi source .venv/bin/activate echo "Upgrading pip, setuptools, wheel in venv..." if command -v uv >/dev/null 2>&1; then uv pip install --upgrade pip setuptools wheel else python -m pip install --upgrade pip setuptools wheel fi echo "Installing dependencies from pyproject.toml..." if command -v uv >/dev/null 2>&1; then echo "(Using uv)" # Install with all optional dependencies for development uv pip install ".[dev]" else echo "(Using pip)" python -m pip install ".[dev]" fi if [ -f "setup.py" ] || [ -f "pyproject.toml" ]; then echo "Installing project in editable mode..." if command -v uv >/dev/null 2>&1; then uv pip install -e . else python -m pip install -e . fi else echo "No setup.py or pyproject.toml found, skipping editable install." fi # List installed packages for verification echo "Installed dependencies:" pip list | grep -E "requests|fastmcp|beautifulsoup4" echo "✓ Python environment setup complete in ./.venv" echo "---------------------------------------------" ''; # Setup for Python package - using Python 3.12 which has fastmcp in nixpkgs pythonPackage = let pyproject = nixpkgs.lib.importTOML ./pyproject.toml; in pkgs.python312Packages.buildPythonApplication { pname = pyproject.project.name; inherit (pyproject.project) version; meta.mainProgram = pyproject.project.name; src = ./.; format = "pyproject"; nativeBuildInputs = with pkgs.python312Packages; [ hatchling ]; propagatedBuildInputs = with pkgs.python312Packages; [ # Use fastmcp from nixpkgs fastmcp requests beautifulsoup4 ]; # Disable runtime dependency checks since the available versions in nixpkgs # may not match exactly what's specified in pyproject.toml pythonImportsCheck = [ ]; doCheck = false; dontCheckRuntimeDeps = true; }; in { # Packages packages = { default = pythonPackage; mcp-nixos = pythonPackage; }; # Add apps for direct execution with nix run apps = { default = flake-utils.lib.mkApp { drv = pythonPackage; name = "mcp-nixos"; }; mcp-nixos = flake-utils.lib.mkApp { drv = pythonPackage; name = "mcp-nixos"; }; }; # Create a separate shell for website development devShells.web = pkgs.devshell.mkShell { name = "mcp-nixos-web"; packages = with pkgs; [ nodejs_20 ]; commands = [ { name = "install"; category = "website"; help = "Install website dependencies"; command = "cd website && npm install"; } { name = "dev"; category = "website"; help = "Start the development server"; command = "cd website && npm run dev"; } { name = "build"; category = "website"; help = "Build the static website for production"; command = "cd website && npm run build"; } { name = "lint"; category = "website"; help = "Lint the website code"; command = "cd website && npm run lint"; } ]; devshell.startup.initMessage.text = '' echo "Entering MCP-NixOS Website Dev Environment..." echo "" echo "Available commands:" echo " install - Install dependencies" echo " dev - Start development server" echo " build - Build for production" echo " lint - Lint code" echo "" menu ''; }; devShells.default = pkgs.devshell.mkShell { name = "mcp-nixos"; motd = '' Entering MCP-NixOS Dev Environment... Python: ${python.version} Nix: ${pkgs.nix}/bin/nix --version ''; env = [ { name = "PYTHONPATH"; value = "$PWD"; } { name = "MCP_NIXOS_ENV"; value = "development"; } { name = "LIBFFI_INCLUDE_DIR"; value = "${pkgs.libffi.dev}/include"; } # Add .dev # Make sure Python can find _ctypes with correct linking flags { name = "NIX_LDFLAGS"; value = "-L${pkgs.libffi}/lib -L${pkgs.libffi.out}/lib"; } { name = "NIX_CFLAGS_COMPILE"; value = "-I${pkgs.libffi.dev}/include"; } # For macOS specifically { name = "DYLD_LIBRARY_PATH"; value = "${pkgs.libffi}/lib:${pkgs.libffi.out}/lib"; } # Add SDK path for macOS if needed { name = "SDKROOT"; value = "${pkgs.darwin.apple_sdk.frameworks.CoreServices}"; } ]; packages = with pkgs; [ # Python with build dependencies pythonWithLibs uv # Faster pip alternative ps.build ps.twine # Required for building C extensions libffi pkg-config # Build tools needed for extension compilation binutils stdenv.cc.cc # Modern linting and formatting tools ps.ruff # Replaces black, flake8, isort, and more ps.mypy # Type checker # Type stubs for dependencies ps.types-requests ps.types-beautifulsoup4 # Testing ps.pytest ps."pytest-cov" ps."pytest-asyncio" # Nix & Git nix nixos-option git # GitHub CLI for repository management gh # Remove Node.js from main dev shell to avoid conflicts ]; commands = [ { name = "setup"; category = "environment"; help = "Set up/update Python virtual environment (.venv) and install dependencies"; command = "rm -rf .venv && ${setupVenvScript}/bin/setup-venv"; } { name = "run"; category = "server"; help = "Run the MCP-NixOS server"; command = '' if [ -z "$VIRTUAL_ENV" ]; then source .venv/bin/activate; fi if ! python -c "import mcp_nixos" &>/dev/null; then echo "Editable install 'mcp_nixos' not found. Running setup..." ${setupVenvScript}/bin/setup-venv source .venv/bin/activate fi echo "Starting MCP-NixOS server with enhanced termination handling..." # Use the wrapper script for improved signal handling python -m mcp_nixos.run ''; } { name = "run-tests"; category = "testing"; help = "Run tests with pytest [--unit|--integration]"; command = '' if [ -z "$VIRTUAL_ENV" ]; then echo "Activating venv..." source .venv/bin/activate fi # Verify key dependencies echo "Verifying dependencies before running tests..." if ! python -c "import requests" &>/dev/null; then echo "ERROR: 'requests' package not found. Installing explicitly..." if command -v uv >/dev/null 2>&1; then uv pip install requests>=2.32.3 else python -m pip install requests>=2.32.3 fi fi # Set up parameters based on arguments TEST_ARGS="" # Handle the unit/integration flags # These arguments get passed directly to pytest if [[ $# -gt 0 && "$1" == "--unit" ]]; then echo "Running unit tests only..." TEST_ARGS="--unit" shift elif [[ $# -gt 0 && "$1" == "--integration" ]]; then echo "Running integration tests only..." TEST_ARGS="--integration" shift else echo "Running all tests..." # Set environment variable to indicate all tests are running # This helps certain tests that need to run in isolation skip when run in a full suite export RUNNING_ALL_TESTS=1 fi # Check if running in CI environment COVERAGE_ARGS="" JUNIT_ARGS="" if [ "$(printenv CI 2>/dev/null)" != "" ] || [ "$(printenv GITHUB_ACTIONS 2>/dev/null)" != "" ]; then # In CI, use coverage and generate JUnit XML for Codecov Test Analytics COVERAGE_ARGS="--cov=mcp_nixos --cov-report=term --cov-report=html --cov-report=xml" JUNIT_ARGS="--junitxml=junit.xml -o junit_family=legacy" echo "Using coverage and JUnit XML (CI environment)" fi # Run all tests if [ -n "$TEST_ARGS" ]; then echo "Running: pytest tests/ -v $TEST_ARGS $COVERAGE_ARGS $JUNIT_ARGS $@" eval "pytest tests/ -v $TEST_ARGS $COVERAGE_ARGS $JUNIT_ARGS $@" else echo "Running: pytest tests/ -v $COVERAGE_ARGS $JUNIT_ARGS $@" echo "Note: Running all tests including eval tests. In CI, eval tests are skipped for external contributors." pytest tests/ -v $COVERAGE_ARGS $JUNIT_ARGS "$@" fi # Show coverage report message if applicable if [ -n "$COVERAGE_ARGS" ]; then echo "✅ Coverage report generated. HTML report available in htmlcov/" fi ''; } { name = "loc"; category = "development"; help = "Count lines of code in the project"; command = '' echo "=== MCP-NixOS Lines of Code Statistics ===" SRC_LINES=$(find ./mcp_nixos -name '*.py' -type f | xargs wc -l | tail -n 1 | awk '{print $1}') TEST_LINES=$(find ./tests -name '*.py' -type f | xargs wc -l | tail -n 1 | awk '{print $1}') # Corrected path pruning for loc command CONFIG_LINES=$(find . -path './.venv' -prune -o -path './.mypy_cache' -prune -o -path './htmlcov' -prune -o -path './.direnv' -prune -o -path './result' -prune -o -path './.git' -prune -o -type f \( -name '*.json' -o -name '*.toml' -o -name '*.ini' -o -name '*.yml' -o -name '*.yaml' -o -name '*.nix' -o -name '*.lock' -o -name '*.md' -o -name '*.rules' -o -name '*.hints' -o -name '*.in' \) -print | xargs wc -l | tail -n 1 | awk '{print $1}') TOTAL_PYTHON=$((SRC_LINES + TEST_LINES)) echo "Source code (mcp_nixos directory): $SRC_LINES lines" echo "Test code (tests directory): $TEST_LINES lines" echo "Configuration files: $CONFIG_LINES lines" echo "Total Python code: $TOTAL_PYTHON lines" if [ "$SRC_LINES" -gt 0 ]; then RATIO=$(echo "scale=2; $TEST_LINES / $SRC_LINES" | bc) echo "Test to code ratio: $RATIO:1" fi ''; } { name = "lint"; category = "development"; help = "Lint code with ruff (checks only in CI)"; command = '' # Check if running in CI environment if [ "$(printenv CI 2>/dev/null)" != "" ] || [ "$(printenv GITHUB_ACTIONS 2>/dev/null)" != "" ]; then echo "--- CI detected: Checking with ruff ---" ruff check mcp_nixos/ tests/ else echo "--- Linting code with ruff ---" ruff check mcp_nixos/ tests/ fi ''; } { name = "typecheck"; category = "development"; help = "Run mypy type checker"; command = '' echo "--- Running mypy type checker ---" if [ -z "$VIRTUAL_ENV" ]; then source .venv/bin/activate; fi mypy mcp_nixos/ ''; } { name = "check-ruff"; category = "development"; help = "Run ruff linter with detailed output"; command = '' echo "--- Running ruff check ---" ruff check mcp_nixos/ tests/ --show-fixes echo "✅ Ruff check complete" ''; } { name = "format"; category = "development"; help = "Format code with ruff"; command = '' echo "--- Formatting code with ruff ---" ruff format mcp_nixos/ tests/ echo "✅ Code formatted" ''; } { name = "build"; category = "distribution"; help = "Build package distributions (sdist and wheel)"; command = '' echo "--- Building package ---" rm -rf dist/ build/ *.egg-info python -m build echo "✅ Build complete in dist/" ''; } { name = "publish"; category = "distribution"; help = "Upload package distribution to PyPI (requires ~/.pypirc)"; command = '' if [ ! -d "dist" ] || [ -z "$(ls -A dist)" ]; then echo "Run 'build' first."; exit 1; fi if [ ! -f "$HOME/.pypirc" ]; then echo "Warning: ~/.pypirc not found."; fi echo "--- Uploading to PyPI ---" twine upload dist/* echo "✅ Upload command executed." ''; } { name = "web-dev"; category = "website"; help = "Launch Node.js shell for website development"; command = '' echo "--- Launching Node.js shell for website development ---" nix develop .#web ''; } { name = "complexity"; category = "development"; help = "Run wily to analyze code complexity (requires command argument: build|report|graph|rank|diff)"; command = '' if [ -z "$VIRTUAL_ENV" ]; then source .venv/bin/activate; fi # Check if wily is installed if ! command -v wily >/dev/null 2>&1; then echo "Installing wily..." if command -v uv >/dev/null 2>&1; then uv pip install wily else python -m pip install wily fi fi # Check if argument is provided if [ $# -eq 0 ]; then echo "=== Wily Code Complexity Analysis ===" echo "Error: Missing required command argument" echo "" echo "Usage: complexity <command> [args]" echo "" echo "Commands:" echo " build - Build the wily cache (run this first)" echo " report <file> <metric> - Show metrics for a file" echo " graph <file> <metric> - Generate graph visualization" echo " rank [path] [metric] - Rank files by complexity" echo " diff [git_ref] - Show complexity changes (default: HEAD^1)" echo " list-metrics - List available metrics" echo "" echo "Examples:" echo " complexity build" echo " complexity report mcp_nixos/server.py mi" echo " complexity diff origin/main" exit 1 fi # Subcommands case "$1" in build) echo "--- Building wily cache ---" wily build mcp_nixos tests ;; report) echo "--- Generating wily report ---" if [ -z "$2" ]; then echo "Usage: complexity report <file_path> <metric>" echo "Available metrics: mi (maintainability index), raw.loc (lines of code), etc." echo "Run 'wily list-metrics' for a complete list" exit 1 fi if [ -z "$3" ]; then wily report "$2" "mi" else wily report "$2" "$3" fi ;; graph) echo "--- Generating wily graph ---" if [ -z "$2" ]; then echo "Usage: complexity graph <file_path> <metric>" echo "Available metrics: mi (maintainability index), raw.loc (lines of code), etc." echo "Run 'wily list-metrics' for a complete list" exit 1 fi if [ -z "$3" ]; then wily graph "$2" "mi" else wily graph "$2" "$3" fi ;; rank) echo "--- Ranking files by complexity ---" if [ -z "$2" ]; then PATH_ARG="." else PATH_ARG="$2" fi if [ -z "$3" ]; then wily rank "$PATH_ARG" "mi" else wily rank "$PATH_ARG" "$3" fi ;; diff) echo "--- Comparing complexity changes ---" if [ -z "$2" ]; then wily diff mcp_nixos tests -r "HEAD^1" else wily diff mcp_nixos tests -r "$2" fi ;; list-metrics) wily list-metrics ;; *) echo "=== Wily Code Complexity Analysis ===" echo "Error: Missing required command argument" echo "" echo "Usage: complexity <command> [args]" echo "" echo "Commands:" echo " build - Build the wily cache (run this first)" echo " report <file> <metric> - Show metrics for a file" echo " graph <file> <metric> - Generate graph visualization" echo " rank [path] [metric] - Rank files by complexity" echo " diff [git_ref] - Show complexity changes (default: HEAD^1)" echo " list-metrics - List available metrics" echo "" echo "Examples:" echo " complexity build" echo " complexity report mcp_nixos/server.py mi" echo " complexity diff origin/main" exit 1 ;; esac ''; } ]; devshell.startup.venvActivate.text = '' echo "Ensuring Python virtual environment is set up..." ${setupVenvScript}/bin/setup-venv echo "Activating virtual environment..." source .venv/bin/activate echo "" echo "✅ MCP-NixOS Dev Environment Activated." echo " Virtual env ./.venv is active." echo "" menu ''; }; } ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/utensils/mcp-nixos'

If you have feedback or need assistance with the MCP directory API, please join our Discord server