claude-code: add enableMcpIntegration
Add `enableMcpIntegration` option to merge MCP servers from `programs.mcp.servers` into Claude Code configuration. Claude Code servers take precedence over general MCP servers when both define the same server name.
This commit is contained in:
parent
1c27557d99
commit
83bcb17377
4 changed files with 106 additions and 5 deletions
|
|
@ -7,6 +7,17 @@
|
|||
let
|
||||
cfg = config.programs.claude-code;
|
||||
jsonFormat = pkgs.formats.json { };
|
||||
transformedMcpServers = lib.optionalAttrs (cfg.enableMcpIntegration && config.programs.mcp.enable) (
|
||||
lib.mapAttrs (
|
||||
name: server:
|
||||
(removeAttrs server [ "disabled" ])
|
||||
// (lib.optionalAttrs (server ? url) { type = "http"; })
|
||||
// (lib.optionalAttrs (server ? command) { type = "stdio"; })
|
||||
// {
|
||||
enabled = !(server.disabled or false);
|
||||
}
|
||||
) config.programs.mcp.servers
|
||||
);
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.khaneliman ];
|
||||
|
|
@ -23,6 +34,20 @@ in
|
|||
description = "Resulting customized claude-code package.";
|
||||
};
|
||||
|
||||
enableMcpIntegration = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to integrate the MCP servers config from
|
||||
{option}`programs.mcp.servers` into
|
||||
{option}`programs.opencode.settings.mcp`.
|
||||
|
||||
Note: Settings defined in {option}`programs.mcp.servers` are merged
|
||||
with {option}`programs.claude-code.mcpServers`, with Claude Code servers
|
||||
taking precedence.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
inherit (jsonFormat) type;
|
||||
default = { };
|
||||
|
|
@ -359,8 +384,8 @@ in
|
|||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.mcpServers == { } || cfg.package != null;
|
||||
message = "`programs.claude-code.package` cannot be null when `mcpServers` is configured";
|
||||
assertion = (cfg.mcpServers == { } && !cfg.enableMcpIntegration) || cfg.package != null;
|
||||
message = "`programs.claude-code.package` cannot be null when `mcpServers` or `enableMcpIntegration` is configured";
|
||||
}
|
||||
{
|
||||
assertion = !(cfg.memory.text != null && cfg.memory.source != null);
|
||||
|
|
@ -390,11 +415,14 @@ in
|
|||
|
||||
programs.claude-code.finalPackage =
|
||||
let
|
||||
mergedMcpServers = transformedMcpServers // cfg.mcpServers;
|
||||
makeWrapperArgs = lib.flatten (
|
||||
lib.filter (x: x != [ ]) [
|
||||
(lib.optional (cfg.mcpServers != { }) [
|
||||
(lib.optional (cfg.mcpServers != { } || transformedMcpServers != { }) [
|
||||
"--append-flags"
|
||||
"--mcp-config ${jsonFormat.generate "claude-code-mcp-config.json" { inherit (cfg) mcpServers; }}"
|
||||
"--mcp-config ${
|
||||
jsonFormat.generate "claude-code-mcp-config.json" { mcpServers = mergedMcpServers; }
|
||||
}"
|
||||
])
|
||||
]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
};
|
||||
|
||||
test.asserts.assertions.expected = [
|
||||
"`programs.claude-code.package` cannot be null when `mcpServers` is configured"
|
||||
"`programs.claude-code.package` cannot be null when `mcpServers` or `enableMcpIntegration` is configured"
|
||||
"Cannot specify both `programs.claude-code.memory.text` and `programs.claude-code.memory.source`"
|
||||
"Cannot specify both `programs.claude-code.agents` and `programs.claude-code.agentsDir`"
|
||||
"Cannot specify both `programs.claude-code.commands` and `programs.claude-code.commandsDir`"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
claude-code-basic = ./basic.nix;
|
||||
claude-code-full-config = ./full-config.nix;
|
||||
claude-code-mcp = ./mcp.nix;
|
||||
claude-code-mcp-integration = ./mcp-integration.nix;
|
||||
claude-code-assertion = ./assertion.nix;
|
||||
claude-code-memory-management = ./memory-management.nix;
|
||||
claude-code-memory-from-source = ./memory-from-source.nix;
|
||||
|
|
|
|||
72
tests/modules/programs/claude-code/mcp-integration.nix
Normal file
72
tests/modules/programs/claude-code/mcp-integration.nix
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
{ config, ... }:
|
||||
|
||||
{
|
||||
programs = {
|
||||
claude-code = {
|
||||
package = config.lib.test.mkStubPackage {
|
||||
name = "claude-code";
|
||||
buildScript = ''
|
||||
mkdir -p $out/bin
|
||||
touch $out/bin/claude
|
||||
chmod 755 $out/bin/claude
|
||||
'';
|
||||
};
|
||||
enable = true;
|
||||
|
||||
enableMcpIntagretion = true;
|
||||
|
||||
mcpServers = {
|
||||
github = {
|
||||
type = "http";
|
||||
url = "https://api.githubcopilot.com/mcp/";
|
||||
};
|
||||
filesystem = {
|
||||
type = "stdio";
|
||||
command = "npx";
|
||||
args = [
|
||||
"-y"
|
||||
"@modelcontextprotocol/server-filesystem"
|
||||
"/tmp"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
mcp = {
|
||||
enable = true;
|
||||
servers = {
|
||||
filesystem = {
|
||||
type = "stdio";
|
||||
command = "npx";
|
||||
args = [
|
||||
"-y"
|
||||
"@modelcontextprotocol/server-filesystem"
|
||||
"/other-tmp"
|
||||
];
|
||||
};
|
||||
database = {
|
||||
command = "npx";
|
||||
args = [
|
||||
"-y"
|
||||
"@bytebase/dbhub"
|
||||
"--dsn"
|
||||
"postgresql://user:pass@localhost:5432/db"
|
||||
];
|
||||
env = {
|
||||
DATABASE_URL = "postgresql://user:pass@localhost:5432/db";
|
||||
};
|
||||
};
|
||||
customTransport = {
|
||||
type = "websocket";
|
||||
url = "wss://example.com/mcp";
|
||||
customOption = "value";
|
||||
timeout = 5000;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
normalizedWrapper=$(normalizeStorePaths home-path/bin/claude)
|
||||
assertFileContent $normalizedWrapper ${./expected-mcp-wrapper}
|
||||
'';
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue