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-server.nix
|
||||||
./cache.nix
|
./cache.nix
|
||||||
./chrome-favicon-dbus.nix
|
./chrome-favicon-dbus.nix
|
||||||
|
./claude-mcp.nix
|
||||||
./claude-remote-control.nix
|
./claude-remote-control.nix
|
||||||
./code.nix
|
./code.nix
|
||||||
./cua.nix
|
./cua.nix
|
||||||
|
|||||||
Reference in New Issue
Block a user