sync-agents-settings 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Leoyang183
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,348 @@
1
+ # sync-agents-settings
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
4
+ [![version](https://img.shields.io/badge/version-0.1.0-blue)](package.json)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue?logo=typescript)](https://www.typescriptlang.org/)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green?logo=node.js)](https://nodejs.org/)
7
+ [![pnpm](https://img.shields.io/badge/pnpm-%3E%3D9-orange?logo=pnpm)](https://pnpm.io/)
8
+ [![Vitest](https://img.shields.io/badge/Vitest-4.1-green?logo=vitest)](https://vitest.dev/)
9
+ [![MCP](https://img.shields.io/badge/MCP-compatible-8A2BE2)](https://modelcontextprotocol.io/)
10
+ [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?logo=prettier)](https://prettier.io/)
11
+ [![CI](https://github.com/Leoyang183/sync-agents-settings/actions/workflows/ci.yml/badge.svg)](https://github.com/Leoyang183/sync-agents-settings/actions/workflows/ci.yml)
12
+
13
+ Sync MCP server configurations from **Claude Code** to **Gemini CLI**, **Codex CLI**, **OpenCode**, **Kiro CLI**, and **Cursor**.
14
+
15
+ [中文說明](#中文說明)
16
+
17
+ ## Why
18
+
19
+ If you use Claude Code as your primary AI coding agent but also switch between other agents (Gemini CLI, Codex CLI, OpenCode, Kiro, Cursor) to take advantage of their free tiers or different models, you know the pain — every tool has its own MCP config format, and setting them up one by one is tedious.
20
+
21
+ This tool lets you configure MCP servers once in Claude Code, then sync everywhere with a single command.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pnpm install
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ```bash
32
+ # List all MCP servers detected from Claude Code
33
+ npx tsx src/cli.ts list
34
+
35
+ # Preview sync (no files modified)
36
+ npx tsx src/cli.ts sync --dry-run
37
+
38
+ # Sync to all targets (with automatic backup)
39
+ npx tsx src/cli.ts sync
40
+
41
+ # Sync to a specific target
42
+ npx tsx src/cli.ts sync --target gemini
43
+ npx tsx src/cli.ts sync --target codex
44
+ npx tsx src/cli.ts sync --target opencode
45
+ npx tsx src/cli.ts sync --target kiro
46
+ npx tsx src/cli.ts sync --target cursor
47
+
48
+ # Sync to Codex project-level config
49
+ npx tsx src/cli.ts sync --target codex --codex-home ./my-project/.codex
50
+
51
+ # Compare differences
52
+ npx tsx src/cli.ts diff
53
+
54
+ # Skip OAuth-only servers (e.g. Slack)
55
+ npx tsx src/cli.ts sync --skip-oauth
56
+
57
+ # Skip backup
58
+ npx tsx src/cli.ts sync --no-backup
59
+
60
+ # Verbose output
61
+ npx tsx src/cli.ts sync -v
62
+ ```
63
+
64
+ ## How It Works
65
+
66
+ **Claude Code is the single source of truth** for MCP settings, synced to all supported targets.
67
+
68
+ ```
69
+ ┌─→ Gemini Writer ─→ ~/.gemini/settings.json
70
+ ├─→ Codex Writer ─→ ~/.codex/config.toml
71
+ ~/.claude.json ─────┐ │
72
+ ├─→ Reader ─→ UnifiedMcpServer[] ─┼─→ OpenCode Writer ─→ ~/.config/opencode/opencode.json
73
+ ~/.claude/plugins/ ──┘ │
74
+ ├─→ Kiro Writer ─→ ~/.kiro/settings/mcp.json
75
+ └─→ Cursor Writer ─→ ~/.cursor/mcp.json
76
+ ```
77
+
78
+ | Stage | Description |
79
+ |-------|-------------|
80
+ | **Reader** | Reads from `~/.claude.json` and enabled plugin `.mcp.json` files, merges into a unified format |
81
+ | **Gemini Writer** | JSON → JSON, `type: "http"` → `httpUrl`, `${VAR}` → `$VAR` |
82
+ | **Codex Writer** | JSON → TOML, `${VAR:-default}` → expanded to actual value (env value or fallback) |
83
+ | **OpenCode Writer** | JSON → JSON, `command`+`args` → merged `command` array, `env` → `environment`, `type: "local"`/`"remote"` |
84
+ | **Kiro Writer** | Same format as Claude, `${VAR:-default}` → expanded |
85
+ | **Cursor Writer** | Same format as Claude, `${VAR:-default}` → expanded |
86
+
87
+ **Safety mechanisms:**
88
+ - Existing servers are never overwritten (idempotent, safe to re-run)
89
+ - Automatic backup to `~/.sync-agents-backup/` by default (`--no-backup` to skip)
90
+ - `--dry-run` previews changes without writing any files
91
+
92
+ ### Source: Claude Code
93
+
94
+ Reads MCP servers from two sources:
95
+
96
+ 1. **`~/.claude.json`** → `mcpServers` object (user-configured servers)
97
+ 2. **`~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/.mcp.json`** → enabled plugin MCP servers (matched against `~/.claude/settings.json` `enabledPlugins`)
98
+
99
+ Claude Code has two `.mcp.json` formats:
100
+
101
+ ```jsonc
102
+ // Format 1: Flat (e.g. context7, firebase)
103
+ { "context7": { "command": "npx", "args": ["-y", "@upstash/context7-mcp"] } }
104
+
105
+ // Format 2: Nested under mcpServers (e.g. sentry, stripe)
106
+ { "mcpServers": { "sentry": { "type": "http", "url": "https://mcp.sentry.dev/mcp" } } }
107
+ ```
108
+
109
+ ### Target: Gemini CLI
110
+
111
+ Writes to **`~/.gemini/settings.json`** → `mcpServers` object.
112
+
113
+ Key format differences from Claude:
114
+ - Claude `type: "http"` → Gemini `httpUrl`
115
+ - Claude `type: "sse"` → Gemini `url`
116
+ - Claude `command` (stdio) → Gemini `command` (same)
117
+ - Env var syntax: Claude `${VAR}` → Gemini `$VAR` (auto-converted)
118
+
119
+ ```jsonc
120
+ // Gemini settings.json
121
+ {
122
+ "theme": "Dracula", // existing settings preserved
123
+ "mcpServers": {
124
+ "context7": { // stdio server
125
+ "command": "npx",
126
+ "args": ["-y", "@upstash/context7-mcp"]
127
+ },
128
+ "sentry": { // http server
129
+ "httpUrl": "https://mcp.sentry.dev/mcp"
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ ### Target: Codex CLI
136
+
137
+ Writes to **`~/.codex/config.toml`** (global) by default. Use `--codex-home <path>` to write to a project-level `.codex/config.toml` instead.
138
+
139
+ > **Note:** Codex CLI does NOT merge global and project configs. When a project has `.codex/`, Codex only reads that directory. Global `~/.codex/` is ignored entirely.
140
+
141
+ Key format differences:
142
+ - Uses TOML instead of JSON
143
+ - `command`/`args` for stdio (same concept)
144
+ - `url` for HTTP servers (no type field needed)
145
+ - `env` is a TOML sub-table `[mcp_servers.<name>.env]`
146
+
147
+ ```toml
148
+ [mcp_servers.context7]
149
+ command = "npx"
150
+ args = ["-y", "@upstash/context7-mcp"]
151
+
152
+ [mcp_servers.sentry]
153
+ url = "https://mcp.sentry.dev/mcp"
154
+
155
+ [mcp_servers.n8n-mcp]
156
+ command = "npx"
157
+ args = ["n8n-mcp"]
158
+
159
+ [mcp_servers.n8n-mcp.env]
160
+ N8N_API_KEY = "your-key"
161
+ N8N_API_URL = "https://your-n8n.example.com"
162
+ ```
163
+
164
+ ### Target: OpenCode
165
+
166
+ Writes to **`~/.config/opencode/opencode.json`** → `mcp` object.
167
+
168
+ Key format differences:
169
+ - Root key is `mcp` (not `mcpServers`)
170
+ - stdio servers use `type: "local"` with a merged `command` array (command + args combined)
171
+ - HTTP/SSE servers use `type: "remote"`
172
+ - Environment variables use `environment` field (not `env`)
173
+
174
+ ```jsonc
175
+ // opencode.json
176
+ {
177
+ "model": "anthropic/claude-sonnet-4-5", // existing settings preserved
178
+ "mcp": {
179
+ "context7": { // stdio → local
180
+ "type": "local",
181
+ "command": ["npx", "-y", "@upstash/context7-mcp"]
182
+ },
183
+ "sentry": { // http → remote
184
+ "type": "remote",
185
+ "url": "https://mcp.sentry.dev/mcp"
186
+ },
187
+ "n8n-mcp": { // env → environment
188
+ "type": "local",
189
+ "command": ["npx", "n8n-mcp"],
190
+ "environment": {
191
+ "N8N_API_KEY": "your-key"
192
+ }
193
+ }
194
+ }
195
+ }
196
+ ```
197
+
198
+ ### Target: Kiro CLI
199
+
200
+ Writes to **`~/.kiro/settings/mcp.json`** → `mcpServers` object.
201
+
202
+ Same format as Claude Code. `${VAR:-default}` syntax in URLs is auto-expanded during sync.
203
+
204
+ ### Target: Cursor
205
+
206
+ Writes to **`~/.cursor/mcp.json`** → `mcpServers` object.
207
+
208
+ Same format as Claude Code. `${VAR:-default}` syntax in URLs is auto-expanded during sync.
209
+
210
+ ## Transport Type Mapping
211
+
212
+ | Claude Code | Gemini CLI | Codex CLI | OpenCode | Kiro CLI | Cursor |
213
+ |------------|-----------|----------|----------|----------|--------|
214
+ | `command` + `args` (stdio) | `command` + `args` | `command` + `args` | `type: "local"`, `command: [cmd, ...args]` | same as Claude | same as Claude |
215
+ | `type: "http"` + `url` | `httpUrl` | `url` | `type: "remote"`, `url` | same as Claude | same as Claude |
216
+ | `type: "sse"` + `url` | `url` | `url` | `type: "remote"`, `url` | same as Claude | same as Claude |
217
+ | `env` | `env` | `env` | `environment` | `env` | `env` |
218
+ | `oauth` | skipped | skipped | skipped | skipped | skipped |
219
+
220
+ ## Backup
221
+
222
+ Every sync automatically backs up all affected config files to `~/.sync-agents-backup/<timestamp>/` before writing, preserving the original directory structure relative to `~`:
223
+
224
+ ```
225
+ ~/.sync-agents-backup/2026-03-20T00-06-08-042Z/
226
+ ├── .claude.json # ← ~/.claude.json
227
+ ├── .claude/
228
+ │ └── settings.json # ← ~/.claude/settings.json
229
+ ├── .gemini/
230
+ │ └── settings.json # ← ~/.gemini/settings.json
231
+ ├── .codex/
232
+ │ └── config.toml # ← ~/.codex/config.toml
233
+ ├── .config/
234
+ │ └── opencode/
235
+ │ └── opencode.json # ← ~/.config/opencode/opencode.json
236
+ ├── .kiro/
237
+ │ └── settings/
238
+ │ └── mcp.json # ← ~/.kiro/settings/mcp.json
239
+ └── .cursor/
240
+ └── mcp.json # ← ~/.cursor/mcp.json
241
+ ```
242
+
243
+ Use `--no-backup` to skip. Target directories that don't exist (CLI not installed) will be skipped with a warning, not created.
244
+
245
+ ## Config File Locations
246
+
247
+ | Tool | Config Path | Format |
248
+ |------|-----------|--------|
249
+ | Claude Code (user MCP) | `~/.claude.json` | JSON |
250
+ | Claude Code (settings) | `~/.claude/settings.json` | JSON |
251
+ | Claude Code (plugin MCP) | `~/.claude/plugins/cache/.../.mcp.json` | JSON |
252
+ | Gemini CLI | `~/.gemini/settings.json` | JSON |
253
+ | Codex CLI (global) | `~/.codex/config.toml` | TOML |
254
+ | Codex CLI (project) | `.codex/config.toml` (use `--codex-home`) | TOML |
255
+ | OpenCode (global) | `~/.config/opencode/opencode.json` | JSON |
256
+ | OpenCode (project) | `opencode.json` in project root | JSON |
257
+ | Kiro CLI (global) | `~/.kiro/settings/mcp.json` | JSON |
258
+ | Kiro CLI (project) | `.kiro/settings/mcp.json` in project root | JSON |
259
+ | Cursor (global) | `~/.cursor/mcp.json` | JSON |
260
+ | Cursor (project) | `.cursor/mcp.json` in project root | JSON |
261
+
262
+ ## Limitations
263
+
264
+ - **OAuth servers** (e.g. Slack with `oauth.clientId`) are synced as URL-only — you'll need to authenticate manually in each CLI
265
+ - **`${CLAUDE_PLUGIN_ROOT}`** env vars won't resolve in other CLIs
266
+ - Codex CLI doesn't support `${VAR:-default}` syntax in URLs — these are auto-expanded during sync (env value if set, otherwise the default)
267
+ - Re-running sync will **not overwrite** existing entries (safe to run multiple times)
268
+ - Codex CLI does NOT merge global and project configs — when `.codex/` exists in a project, global `~/.codex/` is ignored
269
+ - If target config directories don't exist, sync will skip that target (won't create directories)
270
+
271
+ ## License
272
+
273
+ MIT
274
+
275
+ ---
276
+
277
+ ## 中文說明
278
+
279
+ 將 **Claude Code** 的 MCP server 設定同步到 **Gemini CLI**、**Codex CLI**、**OpenCode**、**Kiro CLI** 和 **Cursor**。
280
+
281
+ ### 為什麼需要這個工具
282
+
283
+ 如果你主要用 Claude Code 開發,但也會切換其他 AI agent(Gemini CLI、Codex CLI、OpenCode、Kiro、Cursor)來善用各家的免費額度或不同模型,你一定知道這個痛點 — 每個工具的 MCP 設定格式都不一樣,一個一個設定實在太累。
284
+
285
+ 這個工具讓你只在 Claude Code 設定一次 MCP servers,一行指令同步到所有目標。
286
+
287
+ ### 安裝
288
+
289
+ ```bash
290
+ pnpm install
291
+ ```
292
+
293
+ ### 使用方式
294
+
295
+ ```bash
296
+ # 列出所有 Claude Code 的 MCP servers
297
+ npx tsx src/cli.ts list
298
+
299
+ # 預覽同步(不修改任何檔案)
300
+ npx tsx src/cli.ts sync --dry-run
301
+
302
+ # 同步到所有目標(自動備份)
303
+ npx tsx src/cli.ts sync
304
+
305
+ # 同步到特定目標
306
+ npx tsx src/cli.ts sync --target gemini
307
+ npx tsx src/cli.ts sync --target codex
308
+ npx tsx src/cli.ts sync --target opencode
309
+ npx tsx src/cli.ts sync --target kiro
310
+ npx tsx src/cli.ts sync --target cursor
311
+ ```
312
+
313
+ ### 運作原理
314
+
315
+ **Claude Code 是 MCP 設定的 single source of truth**,同步到所有支援的目標。
316
+
317
+ ```
318
+ ┌─→ Gemini Writer ─→ ~/.gemini/settings.json
319
+ ├─→ Codex Writer ─→ ~/.codex/config.toml
320
+ ~/.claude.json ─────┐ │
321
+ ├─→ Reader ─→ UnifiedMcpServer[] ─┼─→ OpenCode Writer ─→ ~/.config/opencode/opencode.json
322
+ ~/.claude/plugins/ ──┘ │
323
+ ├─→ Kiro Writer ─→ ~/.kiro/settings/mcp.json
324
+ └─→ Cursor Writer ─→ ~/.cursor/mcp.json
325
+ ```
326
+
327
+ | 階段 | 說明 |
328
+ |------|------|
329
+ | **Reader** | 從 `~/.claude.json` 和已啟用 plugin 的 `.mcp.json` 讀取,合併為統一格式 |
330
+ | **Gemini Writer** | JSON → JSON,`type: "http"` → `httpUrl`,`${VAR}` → `$VAR` |
331
+ | **Codex Writer** | JSON → TOML,`${VAR:-default}` → 展開為實際值 |
332
+ | **OpenCode Writer** | JSON → JSON,`command`+`args` → 合併為 `command` 陣列,`env` → `environment`,`type: "local"`/`"remote"` |
333
+ | **Kiro Writer** | 與 Claude 相同格式,`${VAR:-default}` → 展開 |
334
+ | **Cursor Writer** | 與 Claude 相同格式,`${VAR:-default}` → 展開 |
335
+
336
+ ### 安全機制
337
+
338
+ - 已存在的 server 不會覆蓋(idempotent,可重複執行)
339
+ - 預設自動備份到 `~/.sync-agents-backup/`(`--no-backup` 跳過)
340
+ - `--dry-run` 預覽變更,不寫入任何檔案
341
+
342
+ ### 限制
343
+
344
+ - **OAuth servers**(如 Slack)只會同步 URL,需要在各 CLI 手動認證
345
+ - **`${CLAUDE_PLUGIN_ROOT}`** 環境變數在其他 CLI 中無法解析
346
+ - Codex CLI 不支援 URL 中的 `${VAR:-default}` 語法,同步時會自動展開
347
+ - 重複執行不會覆蓋已存在的設定(安全可重複)
348
+ - 若目標設定目錄不存在,會跳過該目標(不會自動建立目錄)
@@ -0,0 +1,2 @@
1
+ export declare function createBackup(filePaths: string[]): string;
2
+ export declare function getFilesToBackup(targets: string[], codexConfigPath?: string): string[];
package/dist/backup.js ADDED
@@ -0,0 +1,45 @@
1
+ import { existsSync, mkdirSync, copyFileSync } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { PATHS } from "./paths.js";
5
+ export function createBackup(filePaths) {
6
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
7
+ const backupDir = join(PATHS.backupDir, timestamp);
8
+ const home = homedir();
9
+ let backedUp = 0;
10
+ for (const filePath of filePaths) {
11
+ if (existsSync(filePath)) {
12
+ // Preserve original path structure relative to home
13
+ const relativePath = filePath.startsWith(home) ? filePath.slice(home.length + 1) : filePath;
14
+ const dest = join(backupDir, relativePath);
15
+ mkdirSync(dirname(dest), { recursive: true });
16
+ copyFileSync(filePath, dest);
17
+ backedUp++;
18
+ console.log(` Backed up: ${filePath}`);
19
+ }
20
+ }
21
+ if (backedUp === 0) {
22
+ console.log(" No files to back up");
23
+ }
24
+ return backupDir;
25
+ }
26
+ export function getFilesToBackup(targets, codexConfigPath) {
27
+ const files = [PATHS.claudeJson, PATHS.claudeSettings];
28
+ if (targets.includes("gemini")) {
29
+ files.push(PATHS.geminiSettings);
30
+ }
31
+ if (targets.includes("codex")) {
32
+ files.push(codexConfigPath ?? PATHS.codexConfig);
33
+ }
34
+ if (targets.includes("opencode")) {
35
+ files.push(PATHS.openCodeConfig);
36
+ }
37
+ if (targets.includes("kiro")) {
38
+ files.push(PATHS.kiroMcpConfig);
39
+ }
40
+ if (targets.includes("cursor")) {
41
+ files.push(PATHS.cursorMcpConfig);
42
+ }
43
+ return files;
44
+ }
45
+ //# sourceMappingURL=backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.js","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,MAAM,UAAU,YAAY,CAAC,SAAmB;IAC9C,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,oDAAoD;YACpD,MAAM,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC5F,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;YAC3C,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC7B,QAAQ,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,EAAE,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAiB,EAAE,eAAwB;IAC1E,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAEvD,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAClC,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, existsSync } from "node:fs";
3
+ import { Command } from "commander";
4
+ import { readClaudeMcpServers } from "./reader.js";
5
+ import { writeToGemini } from "./writers/gemini.js";
6
+ import { writeToCodex, resolveCodexConfigPath } from "./writers/codex.js";
7
+ import { writeToOpenCode } from "./writers/opencode.js";
8
+ import { writeToKiro } from "./writers/kiro.js";
9
+ import { writeToCursor } from "./writers/cursor.js";
10
+ import { createBackup, getFilesToBackup } from "./backup.js";
11
+ import { PATHS } from "./paths.js";
12
+ const program = new Command();
13
+ program
14
+ .name("sync-agents")
15
+ .description("Sync Claude Code MCP settings to Gemini CLI / Codex CLI / OpenCode / Kiro CLI")
16
+ .version("0.1.0");
17
+ program
18
+ .command("sync")
19
+ .description("Sync MCP settings from Claude Code to other CLIs")
20
+ .option("-t, --target <targets...>", "sync targets (gemini, codex, opencode, kiro, cursor)", [
21
+ "gemini",
22
+ "codex",
23
+ "opencode",
24
+ "kiro",
25
+ "cursor",
26
+ ])
27
+ .option("--dry-run", "preview mode, no files will be written", false)
28
+ .option("--no-backup", "skip backup")
29
+ .option("--skip-oauth", "skip MCP servers that require OAuth", false)
30
+ .option("--codex-home <path>", "Codex config directory (default: ~/.codex, or specify project-level .codex/)")
31
+ .option("-v, --verbose", "show detailed output", false)
32
+ .action(async (opts) => {
33
+ const targets = opts.target;
34
+ const dryRun = opts.dryRun;
35
+ const skipBackup = !opts.backup;
36
+ const verbose = opts.verbose;
37
+ const skipOAuth = opts.skipOauth;
38
+ const codexHome = opts.codexHome;
39
+ if (dryRun) {
40
+ console.log("🔍 Dry-run mode — no files will be written\n");
41
+ }
42
+ // 1. Read Claude MCP servers
43
+ console.log("📖 Reading Claude Code MCP settings...");
44
+ let servers = readClaudeMcpServers();
45
+ if (skipOAuth) {
46
+ servers = servers.filter((s) => !s.oauth);
47
+ }
48
+ console.log(` Found ${servers.length} MCP server(s)\n`);
49
+ if (verbose) {
50
+ printServers(servers);
51
+ }
52
+ if (servers.length === 0) {
53
+ console.log("No MCP servers found, exiting.");
54
+ return;
55
+ }
56
+ // 2. Backup
57
+ const codexConfigPath = resolveCodexConfigPath(codexHome);
58
+ if (!skipBackup && !dryRun) {
59
+ console.log("💾 Backing up config files...");
60
+ const backupDir = createBackup(getFilesToBackup(targets, codexConfigPath));
61
+ console.log(` Backup directory: ${backupDir}\n`);
62
+ }
63
+ // 3. Sync to targets
64
+ for (const target of targets) {
65
+ console.log(`🔄 Syncing to ${target.toUpperCase()}...`);
66
+ if (target === "gemini") {
67
+ const result = writeToGemini(servers, dryRun);
68
+ printResult(result.added, result.skipped);
69
+ }
70
+ else if (target === "codex") {
71
+ const result = writeToCodex(servers, dryRun, codexHome);
72
+ console.log(` Target: ${result.configPath}`);
73
+ printResult(result.added, result.skipped);
74
+ }
75
+ else if (target === "opencode") {
76
+ const result = writeToOpenCode(servers, dryRun);
77
+ printResult(result.added, result.skipped);
78
+ }
79
+ else if (target === "kiro") {
80
+ const result = writeToKiro(servers, dryRun);
81
+ printResult(result.added, result.skipped);
82
+ }
83
+ else if (target === "cursor") {
84
+ const result = writeToCursor(servers, dryRun);
85
+ printResult(result.added, result.skipped);
86
+ }
87
+ console.log();
88
+ }
89
+ console.log("✅ Sync complete!");
90
+ });
91
+ program
92
+ .command("list")
93
+ .description("List all MCP servers from Claude Code")
94
+ .action(() => {
95
+ console.log("📖 Reading Claude Code MCP settings...\n");
96
+ const servers = readClaudeMcpServers();
97
+ printServers(servers);
98
+ console.log(`\nTotal: ${servers.length} MCP server(s)`);
99
+ });
100
+ program
101
+ .command("diff")
102
+ .description("Compare MCP settings between Claude Code and other CLIs")
103
+ .option("-t, --target <targets...>", "comparison targets (gemini, codex, opencode, kiro, cursor)", ["gemini", "codex", "opencode", "kiro", "cursor"])
104
+ .action((opts) => {
105
+ const targets = opts.target;
106
+ const servers = readClaudeMcpServers();
107
+ const claudeNames = new Set(servers.map((s) => s.name));
108
+ console.log(`Claude Code: ${servers.length} MCP server(s)\n`);
109
+ const diffConfigs = {
110
+ gemini: { path: PATHS.geminiSettings },
111
+ opencode: { path: PATHS.openCodeConfig, key: "mcp" },
112
+ kiro: { path: PATHS.kiroMcpConfig },
113
+ cursor: { path: PATHS.cursorMcpConfig },
114
+ };
115
+ for (const target of targets) {
116
+ if (target === "codex") {
117
+ console.log(` Codex: use 'codex mcp list' to view`);
118
+ }
119
+ else if (target in diffConfigs) {
120
+ const { path, key } = diffConfigs[target];
121
+ const names = readExistingServerNames(path, key);
122
+ printDiff(target.charAt(0).toUpperCase() + target.slice(1), claudeNames, names);
123
+ }
124
+ }
125
+ });
126
+ function readExistingServerNames(configPath, key = "mcpServers") {
127
+ try {
128
+ if (!existsSync(configPath)) {
129
+ return new Set();
130
+ }
131
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
132
+ return new Set(Object.keys(config[key] ?? {}));
133
+ }
134
+ catch {
135
+ return new Set();
136
+ }
137
+ }
138
+ function printDiff(targetName, claudeNames, targetNames) {
139
+ const onlyInClaude = [...claudeNames].filter((n) => !targetNames.has(n));
140
+ const onlyInTarget = [...targetNames].filter((n) => !claudeNames.has(n));
141
+ const shared = [...claudeNames].filter((n) => targetNames.has(n));
142
+ console.log(`--- ${targetName} comparison ---`);
143
+ if (shared.length > 0) {
144
+ console.log(` Shared: ${shared.join(", ")}`);
145
+ }
146
+ if (onlyInClaude.length > 0) {
147
+ console.log(` Only in Claude: ${onlyInClaude.join(", ")}`);
148
+ }
149
+ if (onlyInTarget.length > 0) {
150
+ console.log(` Only in ${targetName}: ${onlyInTarget.join(", ")}`);
151
+ }
152
+ console.log();
153
+ }
154
+ function printServers(servers) {
155
+ for (const s of servers) {
156
+ const transport = s.transport.toUpperCase().padEnd(5);
157
+ const source = s.source === "claude-plugin" ? "plugin" : "config";
158
+ const endpoint = s.transport === "stdio" ? `${s.command} ${(s.args ?? []).join(" ")}` : (s.url ?? "?");
159
+ console.log(` [${transport}] ${s.name} (${source})`);
160
+ console.log(` ${endpoint}`);
161
+ if (s.oauth) {
162
+ console.log(` ⚠ Requires OAuth`);
163
+ }
164
+ }
165
+ }
166
+ function printResult(added, skipped) {
167
+ if (added.length > 0) {
168
+ console.log(` ✅ Added: ${added.join(", ")}`);
169
+ }
170
+ if (skipped.length > 0) {
171
+ console.log(` ⏭ Skipped: ${skipped.join(", ")}`);
172
+ }
173
+ if (added.length === 0 && skipped.length === 0) {
174
+ console.log(" No servers to sync");
175
+ }
176
+ }
177
+ program.parse();
178
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Expand shell-style env var syntax that some CLIs don't support.
3
+ * - `${VAR:-default}` → resolved env value, or `default` if unset
4
+ * - `${VAR}` → resolved env value, or empty string if unset
5
+ */
6
+ export declare function expandEnvVars(value: string): string;
package/dist/env.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Expand shell-style env var syntax that some CLIs don't support.
3
+ * - `${VAR:-default}` → resolved env value, or `default` if unset
4
+ * - `${VAR}` → resolved env value, or empty string if unset
5
+ */
6
+ export function expandEnvVars(value) {
7
+ return value.replace(/\$\{(\w+)(?::-([^}]*))?\}/g, (_match, name, fallback) => {
8
+ return process.env[name] ?? fallback ?? "";
9
+ });
10
+ }
11
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,KAAK,CAAC,OAAO,CAAC,4BAA4B,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAC5E,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,IAAI,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,12 @@
1
+ export declare const PATHS: {
2
+ readonly claudeJson: string;
3
+ readonly claudeSettings: string;
4
+ readonly claudePluginCache: string;
5
+ readonly geminiSettings: string;
6
+ readonly codexDir: string;
7
+ readonly codexConfig: string;
8
+ readonly openCodeConfig: string;
9
+ readonly kiroMcpConfig: string;
10
+ readonly cursorMcpConfig: string;
11
+ readonly backupDir: string;
12
+ };