Skip to content

Commit 016f4f7

Browse files
committed
feat: setup mcp-nixos
1 parent 9105955 commit 016f4f7

5 files changed

Lines changed: 112 additions & 1 deletion

File tree

‎hosts/glyph/services/default.nix‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,16 @@
6161
};
6262

6363
services.basic-memory.enable = true;
64+
services.mcp-nixos.enable = true;
6465
services.mcpjungle = {
6566
enable = true;
6667
servers.basic-memory = {
6768
url = "http://127.0.0.1:8091/mcp";
6869
description = "Knowledge management with markdown files";
6970
};
71+
servers.mcp-nixos = {
72+
url = "http://127.0.0.1:8092/mcp";
73+
description = "NixOS options, packages, and Home Manager search";
74+
};
7075
};
7176
}

‎modules/home/development.nix‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ in {
5858
"Bash(git branch *)"
5959
"Bash(gh api:*)"
6060
"Bash(mkdir *)"
61+
"Bash(journalctl:*)"
62+
"Bash(systemctl list-jobs:*)"
63+
"Bash(systemctl status:*)"
6164
"Bash(* --version)"
6265
"Bash(* --help *)"
6366
"WebFetch(domain:raw.githubusercontent.com)"

‎modules/nixos/llm/default.nix‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
imports = [
33
./basic-memory.nix
4+
./mcp-nixos.nix
45
./mcpjungle.nix
56
];
67
}

‎modules/nixos/llm/mcp-nixos.nix‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
config,
3+
pkgs,
4+
lib,
5+
...
6+
}: let
7+
cfg = config.services.mcp-nixos;
8+
9+
startScript = pkgs.writeShellScript "mcp-nixos-start" ''
10+
exec ${lib.getExe pkgs.uv} run --with mcp-nixos python -c "
11+
from mcp_nixos.server import mcp
12+
mcp.run(transport='streamable-http', port=${toString cfg.port}, host='${cfg.host}')
13+
"
14+
'';
15+
in {
16+
options.services.mcp-nixos = {
17+
enable = lib.mkEnableOption "MCP NixOS server";
18+
19+
port = lib.mkOption {
20+
type = lib.types.port;
21+
default = 8092;
22+
description = "Port for the streamable HTTP transport.";
23+
};
24+
25+
host = lib.mkOption {
26+
type = lib.types.str;
27+
default = "127.0.0.1";
28+
description = "Address to bind the HTTP server to.";
29+
};
30+
31+
openFirewall = lib.mkEnableOption "opening firewall ports for MCP NixOS";
32+
};
33+
34+
config = lib.mkIf cfg.enable {
35+
users.users.mcp-nixos = {
36+
isSystemUser = true;
37+
group = "mcp-nixos";
38+
home = "/var/lib/mcp-nixos";
39+
};
40+
users.groups.mcp-nixos = {};
41+
42+
systemd.services.mcp-nixos = {
43+
description = "MCP NixOS Server";
44+
after = ["network-online.target"];
45+
wants = ["network-online.target"];
46+
wantedBy = ["multi-user.target"];
47+
48+
environment = {
49+
HOME = "/var/lib/mcp-nixos";
50+
UV_CACHE_DIR = "/var/lib/mcp-nixos/.cache/uv";
51+
};
52+
53+
serviceConfig = {
54+
ExecStart = "${startScript}";
55+
User = "mcp-nixos";
56+
Group = "mcp-nixos";
57+
WorkingDirectory = "/var/lib/mcp-nixos";
58+
StateDirectory = "mcp-nixos";
59+
Restart = "on-failure";
60+
RestartSec = 5;
61+
62+
# Hardening
63+
NoNewPrivileges = true;
64+
PrivateDevices = true;
65+
PrivateTmp = true;
66+
ProtectHome = "tmpfs";
67+
BindPaths = ["/var/lib/mcp-nixos"];
68+
ProtectSystem = "strict";
69+
ReadWritePaths = ["/var/lib/mcp-nixos"];
70+
ProtectKernelTunables = true;
71+
ProtectKernelModules = true;
72+
ProtectControlGroups = true;
73+
RestrictSUIDSGID = true;
74+
};
75+
};
76+
77+
programs.nix-ld.enable = true;
78+
79+
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [cfg.port];
80+
};
81+
}

‎modules/nixos/llm/mcpjungle.nix‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,33 @@ in {
8282
Type = "oneshot";
8383
RemainAfterExit = true;
8484
};
85+
path = [pkgs.curl];
8586
script = let
8687
registry = "http://127.0.0.1:${toString cfg.port}";
8788
bin = lib.getExe cfg.package;
8889
registrations = lib.concatStringsSep "\n" (lib.mapAttrsToList (name: server: ''
89-
if ! ${bin} list servers --registry ${registry} 2>/dev/null | grep -q '${name}'; then
90+
if ${bin} list servers --registry ${registry} 2>/dev/null | grep -q '${name}'; then
91+
echo "${name} already registered, skipping."
92+
else
93+
94+
# Wait for server to be reachable before registering
95+
ready=false
96+
for i in $(seq 1 30); do
97+
http_code=$(curl -s -o /dev/null -w '%{http_code}' "${server.url}" 2>/dev/null)
98+
if [ "$http_code" != "000" ]; then
99+
ready=true
100+
break
101+
fi
102+
echo "Waiting for ${name} at ${server.url} (attempt $i/30)..."
103+
sleep 2
104+
done
105+
106+
if [ "$ready" = true ]; then
90107
${bin} register --name '${name}' --description '${server.description}' --url '${server.url}' --registry ${registry}
108+
else
109+
echo "WARNING: ${name} at ${server.url} not reachable after 60s, skipping registration."
110+
fi
111+
91112
fi
92113
'')
93114
cfg.servers);

0 commit comments

Comments
 (0)