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 +21 -0
- package/README.md +348 -0
- package/dist/backup.d.ts +2 -0
- package/dist/backup.js +45 -0
- package/dist/backup.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +178 -0
- package/dist/cli.js.map +1 -0
- package/dist/env.d.ts +6 -0
- package/dist/env.js +11 -0
- package/dist/env.js.map +1 -0
- package/dist/paths.d.ts +12 -0
- package/dist/paths.js +23 -0
- package/dist/paths.js.map +1 -0
- package/dist/reader.d.ts +7 -0
- package/dist/reader.js +151 -0
- package/dist/reader.js.map +1 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/writers/claude-format.d.ts +10 -0
- package/dist/writers/claude-format.js +73 -0
- package/dist/writers/claude-format.js.map +1 -0
- package/dist/writers/codex.d.ts +7 -0
- package/dist/writers/codex.js +89 -0
- package/dist/writers/codex.js.map +1 -0
- package/dist/writers/cursor.d.ts +5 -0
- package/dist/writers/cursor.js +6 -0
- package/dist/writers/cursor.js.map +1 -0
- package/dist/writers/gemini.d.ts +5 -0
- package/dist/writers/gemini.js +81 -0
- package/dist/writers/gemini.js.map +1 -0
- package/dist/writers/kiro.d.ts +5 -0
- package/dist/writers/kiro.js +6 -0
- package/dist/writers/kiro.js.map +1 -0
- package/dist/writers/opencode.d.ts +5 -0
- package/dist/writers/opencode.js +76 -0
- package/dist/writers/opencode.js.map +1 -0
- package/package.json +64 -0
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
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](package.json)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](https://nodejs.org/)
|
|
7
|
+
[](https://pnpm.io/)
|
|
8
|
+
[](https://vitest.dev/)
|
|
9
|
+
[](https://modelcontextprotocol.io/)
|
|
10
|
+
[](https://prettier.io/)
|
|
11
|
+
[](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
|
+
- 若目標設定目錄不存在,會跳過該目標(不會自動建立目錄)
|
package/dist/backup.d.ts
ADDED
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
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
|
package/dist/cli.js.map
ADDED
|
@@ -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
|
package/dist/env.js.map
ADDED
|
@@ -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"}
|
package/dist/paths.d.ts
ADDED
|
@@ -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
|
+
};
|