diff --git a/modules/programs/mcp.nix b/modules/programs/mcp.nix new file mode 100644 index 000000000..9fedbdf2e --- /dev/null +++ b/modules/programs/mcp.nix @@ -0,0 +1,64 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (lib) + literalExpression + mkEnableOption + mkIf + mkOption + ; + + cfg = config.programs.mcp; + + jsonFormat = pkgs.formats.json { }; +in +{ + meta.maintainers = with lib.maintainers; [ delafthi ]; + + options.programs.mcp = { + enable = mkEnableOption "mcp"; + + servers = mkOption { + inherit (jsonFormat) type; + default = { }; + example = literalExpression '' + { + everything = { + command = "npx"; + args = [ + "-y" + "@modelcontextprotocol/server-everything" + ]; + }; + context7 = { + url = "https://mcp.context7.com/mcp"; + headers = { + CONTEXT7_API_KEY = "{env:CONTEXT7_API_KEY}"; + }; + }; + } + ''; + description = '' + MCP server configurations written to + {file}`XDG_CONFIG_HOME/.config/mcp/mcp.json` + ''; + }; + }; + + config = mkIf cfg.enable { + xdg.configFile = mkIf (cfg.servers != { }) ( + let + mcp-config = { + mcpServers = cfg.servers; + }; + in + { + "mcp/mcp.json".source = jsonFormat.generate "mcp.json" mcp-config; + } + ); + }; +} diff --git a/tests/modules/programs/mcp/default.nix b/tests/modules/programs/mcp/default.nix new file mode 100644 index 000000000..2a10a18b8 --- /dev/null +++ b/tests/modules/programs/mcp/default.nix @@ -0,0 +1,4 @@ +{ + mcp-servers = ./servers.nix; + mcp-empty-servers = ./empty-servers.nix; +} diff --git a/tests/modules/programs/mcp/empty-servers.nix b/tests/modules/programs/mcp/empty-servers.nix new file mode 100644 index 000000000..63c72c5c0 --- /dev/null +++ b/tests/modules/programs/mcp/empty-servers.nix @@ -0,0 +1,9 @@ +{ + programs.mcp = { + enable = true; + servers = { }; + }; + nmt.script = '' + assertPathNotExists home-files/.config/mcp/mcp.json + ''; +} diff --git a/tests/modules/programs/mcp/mcp.json b/tests/modules/programs/mcp/mcp.json new file mode 100644 index 000000000..9e2571d5e --- /dev/null +++ b/tests/modules/programs/mcp/mcp.json @@ -0,0 +1,17 @@ +{ + "mcpServers": { + "context7": { + "headers": { + "CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}" + }, + "serverUrl": "https://mcp.context7.com/mcp" + }, + "everything": { + "args": [ + "-y", + "@modelcontextprotocol/server-everything" + ], + "command": "npx" + } + } +} diff --git a/tests/modules/programs/mcp/servers.nix b/tests/modules/programs/mcp/servers.nix new file mode 100644 index 000000000..a63e0f4ae --- /dev/null +++ b/tests/modules/programs/mcp/servers.nix @@ -0,0 +1,25 @@ +{ + programs.mcp = { + enable = true; + servers = { + everything = { + command = "npx"; + args = [ + "-y" + "@modelcontextprotocol/server-everything" + ]; + }; + context7 = { + serverUrl = "https://mcp.context7.com/mcp"; + headers = { + CONTEXT7_API_KEY = "{env:CONTEXT7_API_KEY}"; + }; + }; + }; + }; + nmt.script = '' + assertFileExists home-files/.config/mcp/mcp.json + assertFileContent home-files/.config/mcp/mcp.json \ + ${./mcp.json} + ''; +}