Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions hosts/glyph/services/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,16 @@
};

services.basic-memory.enable = true;
services.mcp-nixos.enable = true;
services.mcpjungle = {
enable = true;
servers.basic-memory = {
url = "http://127.0.0.1:8091/mcp";
description = "Knowledge management with markdown files";
};
servers.mcp-nixos = {
url = "http://127.0.0.1:8092/mcp";
description = "NixOS options, packages, and Home Manager search";
};
};
}
3 changes: 3 additions & 0 deletions modules/home/development.nix
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ in {
"Bash(git branch *)"
"Bash(gh api:*)"
"Bash(mkdir *)"
"Bash(journalctl:*)"
"Bash(systemctl list-jobs:*)"
"Bash(systemctl status:*)"
"Bash(* --version)"
"Bash(* --help *)"
"WebFetch(domain:raw.githubusercontent.com)"
Expand Down
1 change: 1 addition & 0 deletions modules/nixos/llm/default.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
imports = [
./basic-memory.nix
./mcp-nixos.nix
./mcpjungle.nix
];
}
81 changes: 81 additions & 0 deletions modules/nixos/llm/mcp-nixos.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
config,
pkgs,
lib,
...
}: let
cfg = config.services.mcp-nixos;

startScript = pkgs.writeShellScript "mcp-nixos-start" ''
exec ${lib.getExe pkgs.uv} run --with mcp-nixos python -c "
from mcp_nixos.server import mcp
mcp.run(transport='streamable-http', port=${toString cfg.port}, host='${cfg.host}')
"
'';
in {
options.services.mcp-nixos = {
enable = lib.mkEnableOption "MCP NixOS server";

port = lib.mkOption {
type = lib.types.port;
default = 8092;
description = "Port for the streamable HTTP transport.";
};

host = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Address to bind the HTTP server to.";
};

openFirewall = lib.mkEnableOption "opening firewall ports for MCP NixOS";
};

config = lib.mkIf cfg.enable {
users.users.mcp-nixos = {
isSystemUser = true;
group = "mcp-nixos";
home = "/var/lib/mcp-nixos";
};
users.groups.mcp-nixos = {};

systemd.services.mcp-nixos = {
description = "MCP NixOS Server";
after = ["network-online.target"];
wants = ["network-online.target"];
wantedBy = ["multi-user.target"];

environment = {
HOME = "/var/lib/mcp-nixos";
UV_CACHE_DIR = "/var/lib/mcp-nixos/.cache/uv";
};

serviceConfig = {
ExecStart = "${startScript}";
User = "mcp-nixos";
Group = "mcp-nixos";
WorkingDirectory = "/var/lib/mcp-nixos";
StateDirectory = "mcp-nixos";
Restart = "on-failure";
RestartSec = 5;

# Hardening
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
ProtectHome = "tmpfs";
BindPaths = ["/var/lib/mcp-nixos"];
ProtectSystem = "strict";
ReadWritePaths = ["/var/lib/mcp-nixos"];
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
RestrictSUIDSGID = true;
};
};

programs.nix-ld.enable = true;

networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [cfg.port];
};
}
23 changes: 22 additions & 1 deletion modules/nixos/llm/mcpjungle.nix
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,33 @@ in {
Type = "oneshot";
RemainAfterExit = true;
};
path = [pkgs.curl];
script = let
registry = "http://127.0.0.1:${toString cfg.port}";
bin = lib.getExe cfg.package;
registrations = lib.concatStringsSep "\n" (lib.mapAttrsToList (name: server: ''
if ! ${bin} list servers --registry ${registry} 2>/dev/null | grep -q '${name}'; then
if ${bin} list servers --registry ${registry} 2>/dev/null | grep -q '${name}'; then
echo "${name} already registered, skipping."
else

# Wait for server to be reachable before registering
ready=false
for i in $(seq 1 30); do
http_code=$(curl -s -o /dev/null -w '%{http_code}' "${server.url}" 2>/dev/null)
if [ "$http_code" != "000" ]; then
ready=true
break
fi
echo "Waiting for ${name} at ${server.url} (attempt $i/30)..."
sleep 2
done

if [ "$ready" = true ]; then
${bin} register --name '${name}' --description '${server.description}' --url '${server.url}' --registry ${registry}
else
echo "WARNING: ${name} at ${server.url} not reachable after 60s, skipping registration."
fi

fi
'')
cfg.servers);
Expand Down