nixos: register nixos MCP server for Claude Code
Add a module that exposes the pinned mcp-nixos binary and idempotently merges a `nixos` stdio server into the user-scope ~/.claude.json on every switch, giving Claude Code accurate NixOS package/option search. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
58
nixos/claude-mcp.nix
Normal file
58
nixos/claude-mcp.nix
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
makeEnable,
|
||||
...
|
||||
}: let
|
||||
# The MCP-NixOS server (https://mcp-nixos.io) — gives Claude accurate NixOS
|
||||
# package/option/Home-Manager/flake search instead of hallucinated names.
|
||||
# Pinned by Nix from nixpkgs, so no runtime `uvx`/`nix run` fetch is needed.
|
||||
mcpNixosBin = "${pkgs.mcp-nixos}/bin/mcp-nixos";
|
||||
|
||||
# Claude Code reads MCP server *definitions* from the top-level `mcpServers`
|
||||
# key of ~/.claude.json (the user scope). That is the only scope that applies
|
||||
# to every project without an approval prompt while remaining additive:
|
||||
# - settings.json (our nix-managed dotfiles file) cannot define servers,
|
||||
# only filter them (enabled/disabledMcpjsonServers).
|
||||
# - /etc/claude-code/managed-mcp.json would take *exclusive* control and
|
||||
# disable every other server (per-project playwright, future `mcp add`).
|
||||
# So we merge into the user config rather than owning a whole file.
|
||||
serverJson = builtins.toJSON {
|
||||
type = "stdio";
|
||||
command = mcpNixosBin;
|
||||
};
|
||||
in
|
||||
makeEnable config "myModules.claudeMcpNixos" true {
|
||||
# Also expose the pinned binary on PATH for manual `claude mcp` use / Codex.
|
||||
environment.systemPackages = [pkgs.mcp-nixos];
|
||||
|
||||
# Use a module function so `lib` here is home-manager's lib (which carries
|
||||
# `lib.hm.dag`), not the plain NixOS lib.
|
||||
home-manager.users.imalison = {lib, ...}: {
|
||||
# ~/.claude.json is mutable state owned by Claude Code, so it can't be
|
||||
# managed as a whole file. Instead idempotently merge our server into it
|
||||
# on every switch with jq, preserving all other (per-project, user-added)
|
||||
# servers and state. This module is the declarative source of truth:
|
||||
# `claude mcp remove nixos` is re-applied on the next switch.
|
||||
home.activation.registerMcpNixos = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||
config="$HOME/.claude.json"
|
||||
server=${lib.escapeShellArg serverJson}
|
||||
if [ -f "$config" ]; then
|
||||
tmp="$(mktemp)"
|
||||
if ${pkgs.jq}/bin/jq --argjson srv "$server" \
|
||||
'.mcpServers = ((.mcpServers // {}) + {nixos: $srv})' \
|
||||
"$config" > "$tmp"; then
|
||||
mv -f "$tmp" "$config"
|
||||
else
|
||||
rm -f "$tmp"
|
||||
echo "claude-mcp: failed to update $config; left unchanged" >&2
|
||||
fi
|
||||
else
|
||||
${pkgs.jq}/bin/jq -n --argjson srv "$server" \
|
||||
'{mcpServers: {nixos: $srv}}' > "$config"
|
||||
chmod 600 "$config"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
./cache-server.nix
|
||||
./cache.nix
|
||||
./chrome-favicon-dbus.nix
|
||||
./claude-mcp.nix
|
||||
./claude-remote-control.nix
|
||||
./code.nix
|
||||
./cua.nix
|
||||
|
||||
Reference in New Issue
Block a user