mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 02:49:33 +01:00
feat(mcp-sync): sync GitHub Copilot CLI's MCP servers too
Copilot CLI keeps its user MCP list in ~/.copilot/mcp-config.json (COPILOT_HOME moves it) but is not a Codeman run mode, so it has no registry entry. Add the copilot-json dialect (mcpServers, tools ["*"], type local/http/sse, checked against `copilot mcp add` 1.0.94) and declare Copilot as a sync-only target in src/mcp-sync-targets.ts, listed after the registry CLIs. A server switched off with `copilot mcp disable` is recorded in settings.json (disabledMcpServers), not on the entry: sync reads that list so it is not copied, and reports the target unreadable if the file is not valid JSON instead of guessing.
This commit is contained in:
1 parent
3a0cee6b90
commit
57d5c7b1c2
12 files changed
+372
-11
No files matched your search
@@ -2644,17 +2644,17 @@
|
||||
<div class="set-group" id="mcpSyncGroup">
|
||||
<div class="set-group-head"><h4>MCP servers</h4><span class="set-scope">synced</span></div>
|
||||
<div class="set-group-body">
|
||||
<div class="set-row" data-search="mcp server sync enable claude codex gemini opencode antigravity">
|
||||
<div class="set-row" data-search="mcp server sync enable claude codex gemini opencode antigravity copilot github">
|
||||
<div class="set-row-text">
|
||||
<span class="set-row-label">Enable MCP server sync</span>
|
||||
<span class="set-row-desc">Adds a control that copies MCP servers between your enabled CLIs by writing their own config files. Off by default: this changes other tools' configuration, not just Codeman's.</span>
|
||||
<span class="set-row-desc">Adds a control that copies MCP servers between your enabled CLIs, and GitHub Copilot CLI if it is installed, by writing their own config files. Off by default: this changes other tools' configuration, not just Codeman's.</span>
|
||||
</div>
|
||||
<label class="switch switch-sm"><input type="checkbox" id="appSettingsMcpSync" onchange="app.applyMcpSyncVisibility()"><span class="slider"></span></label>
|
||||
</div>
|
||||
<div class="set-row" id="mcpSyncActionRow" style="display:none" data-search="mcp server sync preview">
|
||||
<div class="set-row-text">
|
||||
<span class="set-row-label">Sync MCP servers across CLIs</span>
|
||||
<span class="set-row-desc">Copies each installed, enabled CLI's MCP servers into the others. Only adds missing servers; never edits, removes or copies a server you switched off. Env values and headers are copied too, so a file that receives them is left readable by you only. The previous file is kept as <code>.codeman-bak</code> (overwritten by each sync). A config dir moved by the CLI's own env var (<code>CODEX_HOME</code>, <code>CLAUDE_CONFIG_DIR</code>, <code>XDG_CONFIG_HOME</code>, <code>GEMINI_CLI_HOME</code>) is followed as Codeman's server sees it; a per-session override is not.</span>
|
||||
<span class="set-row-desc">Copies each installed, enabled CLI's MCP servers (and GitHub Copilot CLI's) into the others. Only adds missing servers; never edits, removes or copies a server you switched off. Env values and headers are copied too, so a file that receives them is left readable by you only. The previous file is kept as <code>.codeman-bak</code> (overwritten by each sync). A config dir moved by the CLI's own env var (<code>CODEX_HOME</code>, <code>CLAUDE_CONFIG_DIR</code>, <code>XDG_CONFIG_HOME</code>, <code>GEMINI_CLI_HOME</code>, <code>COPILOT_HOME</code>) is followed as Codeman's server sees it; a per-session override is not.</span>
|
||||
</div>
|
||||
<span>
|
||||
<button class="btn-toolbar btn-sm" id="mcpSyncPreviewBtn" onclick="app.mcpSync(false)">Preview</button>
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
* only, never env values, headers or file content (a parse failure is reported by position).
|
||||
*
|
||||
* A CLI takes part when it is ENABLED in the registry, declares an `mcpConfig`, and is installed
|
||||
* or already has its config file; one that is enabled but absent from the machine is reported
|
||||
* or already has its config file (Copilot CLI, which is not a registry CLI, takes part when installed
|
||||
* or when its config file exists); one that is enabled but absent from the machine is reported
|
||||
* `absent` and never created. Its file is located with this process's env (the env the CLIs
|
||||
* Codeman spawns inherit), so a relocation var such as `CODEX_HOME` is followed.
|
||||
*/
|
||||
@@ -28,6 +29,7 @@ import { isMultiUserMode } from '../../config/multiuser.js';
|
||||
import { enabledClis } from '../../config/cli-registry/registry.js';
|
||||
import { isCliEntryInstalled, probeStockCliAvailability } from '../../utils/cli-installed-probes.js';
|
||||
import { McpSyncBusyError, syncMcpServers, type McpSyncTarget } from '../../mcp-sync.js';
|
||||
import { mcpSyncOnlyTargets } from '../../mcp-sync-targets.js';
|
||||
|
||||
/** Default OFF, same shape as `readCliManagementEnabled`: read fresh so a toggle applies at once. */
|
||||
export async function readMcpSyncEnabled(): Promise<boolean> {
|
||||
@@ -35,9 +37,13 @@ export async function readMcpSyncEnabled(): Promise<boolean> {
|
||||
return settings.mcpSyncEnabled === true;
|
||||
}
|
||||
|
||||
/** Enabled CLIs that declare an MCP config file, in registry order (first definition wins). */
|
||||
/**
|
||||
* Enabled CLIs that declare an MCP config file, in registry order (first definition wins), then the
|
||||
* sync-only tools (src/mcp-sync-targets.ts: Copilot CLI), which come last so a registry CLI's
|
||||
* definition wins a same-name difference.
|
||||
*/
|
||||
export function mcpSyncTargets(availability: Record<string, boolean>): McpSyncTarget[] {
|
||||
return enabledClis()
|
||||
const registry = enabledClis()
|
||||
.filter((e) => e.capabilities.mcpConfig)
|
||||
.sort((a, b) => a.order - b.order)
|
||||
.map((e) => ({
|
||||
@@ -46,6 +52,7 @@ export function mcpSyncTargets(availability: Record<string, boolean>): McpSyncTa
|
||||
...e.capabilities.mcpConfig!,
|
||||
installed: isCliEntryInstalled(e, availability),
|
||||
}));
|
||||
return [...registry, ...mcpSyncOnlyTargets(new Set(registry.map((t) => t.id)))];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user