mcp-servers-nix

repository·main·Indexed 42 days ago

https://github.com/natsukium/mcp-servers-nix

A Nix-based configuration framework for Model Control Protocol (MCP) servers. It provides reproducible, modular configurations and ready-to-use Nix packages for popular MCP servers, enabling consistent deployment across clients such as Claude Desktop, VS Code, and Zed. Features include the mkConfig function for generating configuration files, support for multiple output flavors (JSON, YAML, TOML), and secure credential management via envFile and passwordCommand.

Tokens
17.8K
Snippets
59
Records
71
Agent score
44%

What's inside mcp-servers-nix

  1. Use passwordCommand to manage secrets

    main

    The passwordCommand option is a secure way to integrate with password managers (like pass or gh auth) to retrieve sensitive credentials at runtime. This is handled via a wrapper regardless of the server's flavor.

    There are two ways to specify it:

    1. As a string: The command must output in KEY=VALUE format. Example: "pass mcp-server" (assuming pass outputs TOKEN=xyz).

    2. As an attribute set: Keys are the target environment variable names, and values are lists of strings representing the command to run to get the value.

    Example (Attribute Set):

    passwordCommand = {
      GITHUB_PERSONAL_ACCESS_TOKEN = [ "gh" "auth" "token" ];
    };
    programs.github.passwordCommand = {
      GITHUB_PERSONAL_ACCESS_TOKEN = [
        "gh"
        "auth"
        "token"
      ];
    };
  2. Retrieve secrets using passwordCommand

    main

    The passwordCommand option allows you to integrate with password managers to securely inject environment variables. It can be specified in two ways:

    1. As a string: The command must output text in the KEY=VALUE format. Each line will be exported as an environment variable. Example: "pass mcp-server" (assuming pass outputs TOKEN=123)

    2. As an attribute set: Keys are the desired environment variable names, and values are lists of strings representing the command to execute to fetch the value. Example: { GITHUB_TOKEN = [ "gh" "auth" "token" ]; }

    passwordCommand is always handled via the wrapper regardless of the selected flavor.

    # Using an attribute set for specific keys
    programs.netdata.passwordCommand = {
      GITHUB_PERSONAL_ACCESS_TOKEN = [
        "gh"
        "auth"
        "token"
      ];
    };
  3. Securely manage environment variables

    main

    When configuring MCP servers via Nix, avoid hardcoding sensitive credentials in the env attribute set. Because files in /nix/store are world-readable, any secrets placed there are exposed.

    Recommended approach: Use the envFile option to point to an absolute path of an .env file containing your secrets.

    Note for VSCode users: When the flavor is set to vscode, the environment file is passed directly as a parameter instead of being wrapped by default.

  4. How the MCP server module system works

    main

    The module system provides a declarative way to configure MCP servers using Nix. The core workflow involves:

    1. mkConfig: Evaluates your module configuration and produces a configuration file in JSON, YAML, or TOML format.
    2. programs.<name>.enable: Activates a pre-configured module for a specific MCP server (e.g., programs.filesystem.enable = true).
    3. flavor: Determines the output key structure to match specific clients (e.g., mcpServers for Claude, mcp.servers for VS Code).
    4. format: Determines the output file format (JSON, YAML, or TOML).

    For detailed option definitions, refer to the Module Options Reference and Configuration Reference.

  5. How to securely manage secrets with passwordCommand

    main

    The passwordCommand option is a secure way to integrate with password managers (like pass or gh auth) to retrieve sensitive environment variables at runtime. This is handled via a wrapper regardless of the server's flavor.

    There are two ways to specify it:

    1. As a string: The command must output in KEY=VALUE format. The output will be exported as environment variables. Example: "pass mcp-server" (assuming the command outputs API_KEY=123).

    2. As an attribute set: Keys are the desired environment variable names, and values are lists of strings representing the command to execute to retrieve the value.

    Example (Attribute Set):

    passwordCommand = {
      GITHUB_PERSONAL_ACCESS_TOKEN = [ "gh" "auth" "token" ];
    };
  6. Configure flake-parts module options

    main

    When using the flakeModule (flake-parts), configuration is managed under perSystem.mcp-servers. This orchestrates multi-flavor configuration and development shells.

    • programs: Base MCP server configuration applied to all enabled flavors.
    • settings: Freeform configuration. Use settings.servers to add custom MCP servers that are not part of the standard program list.
    • addGcRoot: A boolean (default true) that determines if generated config files are added to the garbage collector roots to prevent nix-collect-garbage from deleting them.
    • flavors.<name>: Per-flavor overrides for claude-code and vscode-workspace. You can override enable, programs, and settings specifically for a flavor.

    Read-Only Outputs

    You can consume these generated outputs in your flake:

    • configs: Attribute set of generated configuration files per flavor.
    • packages: List of all enabled MCP server packages.
    • shellHook: A string containing the shell hook to symlink configs.
    • devShell: A package representing the development shell.
    # Example flake-parts configuration
    mcp-servers = {
      programs = {
        playwright.enable = true;
        github.enable = true;
      };
      settings.servers = {
        obsidian = {
          command = "${pkgs.nodejs}/bin/npx";
          args = [ "-y" "mcp-obsidian" "/path/to/vault" ];
        };
      };
      flavors = {
        claude-code = {
          enable = true;
          programs.filesystem.args = [ "../../" ];
        };
        vscode-workspace = {
          enable = true;
          programs.playwright.env.CUSTOM_SETTING = "vscode-value";
        };
      };
    };
    
    # Consuming outputs in devShells
    devShells.default = config.mcp-servers.devShell;
  7. Install an MCP server package

    main

    To make an MCP server package available in your environment, you can install it using either the classic nix-env method or the modern nix profile method if you are using flakes.

    # Without flakes
    nix-env -f https://github.com/natsukium/mcp-servers-nix/archive/main.tar.gz -iA mcp-server-fetch
    
    # Using flakes
    nix profile install github:natsukium/mcp-servers-nix#mcp-server-fetch
  8. Add MCP server packages via Nix overlays

    main

    You can add all available MCP server packages to your nixpkgs instance by adding the provided overlay to your configuration.nix or home.nix. This allows you to manage MCP servers as standard packages through pkgs.

    Classic configuration

    Use builtins.fetchTarball to import the overlay.

    Flake configuration

    Use the overlay path provided by your flake input (e.g., mcp-servers-nix.overlays.default).

    # In your configuration.nix or home.nix
    {
      nixpkgs.overlays = [
        # classic
        (import (builtins.fetchTarball "https://github.com/natsukium/mcp-servers-nix/archive/main.tar.gz")).overlays.default
        # or with flakes
        # mcp-servers-nix.overlays.default
      ];
    
      # Then install packages through pkgs
      environment.systemPackages = with pkgs; [
        mcp-server-fetch
      ];
    }
  9. Generate MCP server configuration files with mkConfig

    main

    To generate a configuration file (like claude_desktop_config.json or .mcp.json) for your MCP clients, use the mkConfig function provided by the framework.

    1. Create a config.nix file that imports the framework and calls mcp-servers-nix.lib.mkConfig.
    2. Define your server configurations under the appropriate attribute set (e.g., programs.filesystem).
    3. Build the configuration using nix-build and inspect the result file.
    # config.nix
    let
      pkgs = import <nixpkgs> { };
      mcp-servers-nix = import (fetchTarball
        "https://github.com/natsukium/mcp-servers-nix/archive/main.tar.gz") { inherit pkgs; };
    in
      mcp-servers-nix.lib.mkConfig pkgs {
        programs.filesystem = {
          enable = true;
          args = [ "/path/to/allowed/directory" ];
        };
      }

    Then run:

    nix-build config.nix && cat result
  10. Configure MCP servers using devenv

    main

    The devenv module integrates with devenv's built-in claude.code.mcpServers option. Instead of generating .mcp.json via a shell hook, it outputs through devenv's native Claude Code support.

    Key features:

    • Declarative interface: Uses the same programs.<name>.enable pattern.
    • Native devenv integration: Outputs through claude.code.mcpServers.
    • Credential wrapping: envFile and passwordCommand work naturally as they produce Nix store paths.

    Example devenv.yaml:

    inputs:
      mcp-servers-nix:
        url: github:natsukium/mcp-servers-nix

    Example devenv.nix:

    { inputs, pkgs, ... }: 
    {
      imports = [ inputs.mcp-servers-nix.devenvModules.default ];
    
      claude.code.enable = true;
    
      mcp-servers.programs = {
        filesystem = {
          enable = true;
          args = [ "." ];
        };
        playwright.enable = true;
        context7.enable = true;
      };
    }
    # devenv.nix
    { inputs, pkgs, ... }: 
    {
      imports = [ inputs.mcp-servers-nix.devenvModules.default ];
    
      claude.code.enable = true;
    
      mcp-servers.programs = {
        filesystem = {
          enable = true;
          args = [ "." ];
        };
        playwright.enable = true;
        context7.enable = true;
      };
    }
  11. Configure MCP servers using Nix Flakes

    main

    For Flake-based setups, define your inputs in flake.nix and use mcp-servers-nix.lib.mkConfig within your outputs. This allows you to pin specific versions of nixpkgs and mcp-servers-nix.

    Example flake.nix:

    # flake.nix
    {
      inputs = {
        nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
        mcp-servers-nix.url = "github:natsukium/mcp-servers-nix";
      };
    
      outputs = 
        {
          self,
          nixpkgs,
          mcp-servers-nix,
        }: 
        {
          packages.x86_64-linux.default = 
            let
              pkgs = import nixpkgs { system = "x86_64-linux"; };
            in
            mcp-servers-nix.lib.mkConfig pkgs {
              programs = {
                filesystem = {
                  enable = true;
                  args = [ "/path/to/allowed/directory" ];
                };
                fetch.enable = true;
              };
            };
        };
    }

    Build the configuration using:

    nix build