@fractalizer/mcp-cli 0.3.18 → 1.0.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.
Files changed (120) hide show
  1. package/README.md +158 -266
  2. package/dist/commands/connect.command.d.ts +18 -15
  3. package/dist/commands/connect.command.d.ts.map +1 -1
  4. package/dist/commands/connect.command.js +66 -40
  5. package/dist/commands/connect.command.js.map +1 -1
  6. package/dist/commands/disconnect.command.d.ts +5 -17
  7. package/dist/commands/disconnect.command.d.ts.map +1 -1
  8. package/dist/commands/disconnect.command.js +4 -15
  9. package/dist/commands/disconnect.command.js.map +1 -1
  10. package/dist/commands/doctor.command.d.ts +34 -0
  11. package/dist/commands/doctor.command.d.ts.map +1 -0
  12. package/dist/commands/doctor.command.js +321 -0
  13. package/dist/commands/doctor.command.js.map +1 -0
  14. package/dist/commands/index.d.ts +1 -0
  15. package/dist/commands/index.d.ts.map +1 -1
  16. package/dist/commands/index.js +2 -0
  17. package/dist/commands/index.js.map +1 -1
  18. package/dist/commands/list.command.d.ts +4 -9
  19. package/dist/commands/list.command.d.ts.map +1 -1
  20. package/dist/commands/list.command.js +1 -5
  21. package/dist/commands/list.command.js.map +1 -1
  22. package/dist/commands/status.command.d.ts +6 -13
  23. package/dist/commands/status.command.d.ts.map +1 -1
  24. package/dist/commands/status.command.js +15 -12
  25. package/dist/commands/status.command.js.map +1 -1
  26. package/dist/commands/validate.command.d.ts +6 -11
  27. package/dist/commands/validate.command.d.ts.map +1 -1
  28. package/dist/commands/validate.command.js +15 -19
  29. package/dist/commands/validate.command.js.map +1 -1
  30. package/dist/connectors/base/base-connector.d.ts +31 -55
  31. package/dist/connectors/base/base-connector.d.ts.map +1 -1
  32. package/dist/connectors/base/base-connector.js +71 -57
  33. package/dist/connectors/base/base-connector.js.map +1 -1
  34. package/dist/connectors/base/configurable-connector.d.ts +89 -24
  35. package/dist/connectors/base/configurable-connector.d.ts.map +1 -1
  36. package/dist/connectors/base/configurable-connector.js +266 -23
  37. package/dist/connectors/base/configurable-connector.js.map +1 -1
  38. package/dist/connectors/base/connector.interface.d.ts +29 -20
  39. package/dist/connectors/base/connector.interface.d.ts.map +1 -1
  40. package/dist/connectors/base/index.d.ts +0 -1
  41. package/dist/connectors/base/index.d.ts.map +1 -1
  42. package/dist/connectors/base/index.js +0 -1
  43. package/dist/connectors/base/index.js.map +1 -1
  44. package/dist/connectors/claude-code/claude-code.connector.d.ts +100 -21
  45. package/dist/connectors/claude-code/claude-code.connector.d.ts.map +1 -1
  46. package/dist/connectors/claude-code/claude-code.connector.js +221 -40
  47. package/dist/connectors/claude-code/claude-code.connector.js.map +1 -1
  48. package/dist/connectors/connector-factory.d.ts +15 -15
  49. package/dist/connectors/connector-factory.d.ts.map +1 -1
  50. package/dist/connectors/connector-factory.js +61 -18
  51. package/dist/connectors/connector-factory.js.map +1 -1
  52. package/dist/connectors/index.d.ts +0 -4
  53. package/dist/connectors/index.d.ts.map +1 -1
  54. package/dist/connectors/index.js +2 -8
  55. package/dist/connectors/index.js.map +1 -1
  56. package/dist/connectors/registry.d.ts +20 -27
  57. package/dist/connectors/registry.d.ts.map +1 -1
  58. package/dist/connectors/registry.js +34 -34
  59. package/dist/connectors/registry.js.map +1 -1
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/dist/types/{base.types.d.ts → client.types.d.ts} +30 -30
  62. package/dist/types/client.types.d.ts.map +1 -0
  63. package/dist/types/client.types.js +6 -0
  64. package/dist/types/client.types.js.map +1 -0
  65. package/dist/types/doctor.types.d.ts +91 -0
  66. package/dist/types/doctor.types.d.ts.map +1 -0
  67. package/dist/types/doctor.types.js +12 -0
  68. package/dist/types/doctor.types.js.map +1 -0
  69. package/dist/types/launch.types.d.ts +59 -0
  70. package/dist/types/launch.types.d.ts.map +1 -0
  71. package/dist/types/launch.types.js +6 -0
  72. package/dist/types/launch.types.js.map +1 -0
  73. package/dist/types.d.ts +23 -14
  74. package/dist/types.d.ts.map +1 -1
  75. package/dist/types.js +9 -2
  76. package/dist/types.js.map +1 -1
  77. package/dist/utils/command-executor.d.ts +39 -3
  78. package/dist/utils/command-executor.d.ts.map +1 -1
  79. package/dist/utils/command-executor.js +95 -8
  80. package/dist/utils/command-executor.js.map +1 -1
  81. package/dist/utils/config-manager.d.ts +25 -42
  82. package/dist/utils/config-manager.d.ts.map +1 -1
  83. package/dist/utils/config-manager.js +21 -49
  84. package/dist/utils/config-manager.js.map +1 -1
  85. package/dist/utils/index.d.ts +1 -0
  86. package/dist/utils/index.d.ts.map +1 -1
  87. package/dist/utils/index.js +1 -0
  88. package/dist/utils/index.js.map +1 -1
  89. package/dist/utils/interactive-prompter.d.ts +16 -64
  90. package/dist/utils/interactive-prompter.d.ts.map +1 -1
  91. package/dist/utils/interactive-prompter.js +12 -65
  92. package/dist/utils/interactive-prompter.js.map +1 -1
  93. package/dist/utils/launch-spec-helpers.d.ts +38 -0
  94. package/dist/utils/launch-spec-helpers.d.ts.map +1 -0
  95. package/dist/utils/launch-spec-helpers.js +131 -0
  96. package/dist/utils/launch-spec-helpers.js.map +1 -0
  97. package/package.json +2 -2
  98. package/dist/connectors/base/file-based-connector.d.ts +0 -97
  99. package/dist/connectors/base/file-based-connector.d.ts.map +0 -1
  100. package/dist/connectors/base/file-based-connector.js +0 -185
  101. package/dist/connectors/base/file-based-connector.js.map +0 -1
  102. package/dist/connectors/claude-desktop/claude-desktop.connector.d.ts +0 -38
  103. package/dist/connectors/claude-desktop/claude-desktop.connector.d.ts.map +0 -1
  104. package/dist/connectors/claude-desktop/claude-desktop.connector.js +0 -68
  105. package/dist/connectors/claude-desktop/claude-desktop.connector.js.map +0 -1
  106. package/dist/connectors/codex/codex.connector.d.ts +0 -51
  107. package/dist/connectors/codex/codex.connector.d.ts.map +0 -1
  108. package/dist/connectors/codex/codex.connector.js +0 -76
  109. package/dist/connectors/codex/codex.connector.js.map +0 -1
  110. package/dist/connectors/gemini/gemini.connector.d.ts +0 -41
  111. package/dist/connectors/gemini/gemini.connector.d.ts.map +0 -1
  112. package/dist/connectors/gemini/gemini.connector.js +0 -61
  113. package/dist/connectors/gemini/gemini.connector.js.map +0 -1
  114. package/dist/connectors/qwen/qwen.connector.d.ts +0 -41
  115. package/dist/connectors/qwen/qwen.connector.d.ts.map +0 -1
  116. package/dist/connectors/qwen/qwen.connector.js +0 -61
  117. package/dist/connectors/qwen/qwen.connector.js.map +0 -1
  118. package/dist/types/base.types.d.ts.map +0 -1
  119. package/dist/types/base.types.js +0 -6
  120. package/dist/types/base.types.js.map +0 -1
package/README.md CHANGED
@@ -2,21 +2,26 @@
2
2
 
3
3
  **Generic CLI фреймворк для управления подключениями MCP серверов к различным клиентам.**
4
4
 
5
+ Framework полностью **агностичен к доменной модели сервера**: оперирует двумя
6
+ абстракциями — `TDomainConfig` (произвольный объект, opaque для framework) и
7
+ `ServerLaunchSpec` (`{ command, args, env }` — готовая спецификация запуска).
8
+ Маппинг доменных полей в spec выполняет вызывающий код (адаптер домена).
9
+
5
10
  ---
6
11
 
7
- ## 🎯 Возможности
12
+ ## Возможности
8
13
 
9
14
  - **Универсальный** — подходит для любого MCP сервера
10
- - **Поддержка множества клиентов** — Claude Desktop, Claude Code, Codex, Gemini, Qwen
11
- - **Типобезопасность** — TypeScript generics для конфигурации
12
- - **Декларативные промпты** — простая настройка через `ConfigPromptDefinition`
13
- - **Безопасное хранение**секреты не сохраняются, только безопасные поля
14
- - **Расширяемость** легко добавить новый клиент или кастомизировать промпты
15
- - **Интерактивность**удобный CLI с выбором из списка, валидацией, спиннерами
15
+ - **Поддержка клиентов** — Claude Desktop, Claude Code, Codex, Gemini, Qwen (через `createConnector`)
16
+ - **Типобезопасность** — TypeScript generic-параметры с `extends object`
17
+ - **Декларативные промпты** — `ConfigPromptDefinition<T>`
18
+ - **Структурный парсинг статуса Claude Code** `✓ Connected`/`✗ Failed`/`! Needs authentication`
19
+ - **Параллельный сбор статусов** `Promise.allSettled` для всех клиентов сразу
20
+ - **Самодиагностика**`connector.getLaunchSpec()` для проверки актуальности записей в конфигах
16
21
 
17
22
  ---
18
23
 
19
- ## 📦 Установка
24
+ ## Установка
20
25
 
21
26
  ```bash
22
27
  npm install @fractalizer/mcp-cli
@@ -24,36 +29,41 @@ npm install @fractalizer/mcp-cli
24
29
 
25
30
  ---
26
31
 
27
- ## 🚀 Быстрый старт
28
-
29
- ### Минимальный пример
32
+ ## Быстрый старт
30
33
 
31
34
  ```typescript
32
- import { connectCommand, ConnectorRegistry, ConfigManager } from '@fractalizer/mcp-cli';
33
- import type { BaseMCPServerConfig, ConfigPromptDefinition } from '@fractalizer/mcp-cli';
34
35
  import {
35
- ClaudeDesktopConnector,
36
+ connectCommand,
37
+ ConnectorRegistry,
38
+ ConfigManager,
39
+ createConnector,
36
40
  ClaudeCodeConnector,
37
- } from '@fractalizer/mcp-cli/connectors';
38
-
39
- // 1. Определяем конфигурацию вашего MCP сервера
40
- interface MyServerConfig extends BaseMCPServerConfig {
41
- apiToken: string; // Секрет
42
- orgId: string; // Безопасное поле
41
+ } from '@fractalizer/mcp-cli';
42
+ import type {
43
+ ConfigPromptDefinition,
44
+ ServerLaunchSpec,
45
+ } from '@fractalizer/mcp-cli';
46
+
47
+ // 1. Доменная конфигурация (произвольный объект)
48
+ interface MyServerConfig {
49
+ apiToken: string;
50
+ orgId: string;
43
51
  }
44
52
 
45
- // 2. Создаем реестр и регистрируем коннекторы
46
- const registry = new ConnectorRegistry<MyServerConfig>();
47
- registry.register(new ClaudeDesktopConnector('my-server', 'dist/index.js'));
48
- registry.register(new ClaudeCodeConnector('my-server', 'dist/index.js'));
53
+ // 2. Реестр коннекторов
54
+ const registry = new ConnectorRegistry();
55
+ registry.register(createConnector('claude-desktop', 'my-server'));
56
+ registry.register(createConnector('gemini', 'my-server'));
57
+ registry.register(new ClaudeCodeConnector('my-server'));
49
58
 
50
- // 3. Создаем менеджер конфигурации
59
+ // 3. ConfigManager (опционально, для сохранения)
51
60
  const configManager = new ConfigManager<MyServerConfig>({
52
61
  projectName: 'my-mcp-server',
53
- safeFields: ['orgId', 'logLevel', 'projectPath'], // БЕЗ apiToken!
62
+ // serialize-хук позволяет исключать секреты при сохранении
63
+ serialize: (cfg) => ({ orgId: cfg.orgId }),
54
64
  });
55
65
 
56
- // 4. Определяем промпты для сбора конфигурации
66
+ // 4. Промпты для сбора доменной конфигурации
57
67
  const configPrompts: ConfigPromptDefinition<MyServerConfig>[] = [
58
68
  {
59
69
  name: 'apiToken',
@@ -65,143 +75,113 @@ const configPrompts: ConfigPromptDefinition<MyServerConfig>[] = [
65
75
  name: 'orgId',
66
76
  type: 'input',
67
77
  message: 'ID организации:',
68
- default: (saved) => saved?.orgId, // Используем сохраненное значение
78
+ default: (saved) => saved?.orgId,
69
79
  },
70
80
  ];
71
81
 
72
- // 5. Запускаем команду подключения
82
+ // 5. Адаптер: доменная конфигурация → spec
83
+ function buildServerLaunch(cfg: MyServerConfig): ServerLaunchSpec {
84
+ return {
85
+ command: 'node',
86
+ args: ['/abs/path/to/server.bundle.cjs'],
87
+ env: {
88
+ API_TOKEN: cfg.apiToken,
89
+ ORG_ID: cfg.orgId,
90
+ },
91
+ };
92
+ }
93
+
94
+ // 6. Запускаем команду подключения
73
95
  await connectCommand({
74
96
  registry,
75
97
  configManager,
76
98
  configPrompts,
99
+ buildServerLaunch,
77
100
  });
78
101
  ```
79
102
 
80
- **Что произойдет:**
81
- 1. CLI найдет установленные MCP клиенты
82
- 2. Предложит выбрать клиент из списка
83
- 3. Соберет конфигурацию через интерактивные промпты
84
- 4. Провалидирует конфигурацию
85
- 5. Подключит MCP сервер к выбранному клиенту
86
- 6. Сохранит безопасные поля (без секретов)
87
-
88
103
  ---
89
104
 
90
- ## 📚 Основные концепции
105
+ ## Основные концепции
91
106
 
92
- ### 1. Конфигурация MCP сервера
107
+ ### ServerLaunchSpec
93
108
 
94
- Все MCP серверы должны расширять `BaseMCPServerConfig`:
109
+ Спецификация запуска MCP сервера готовая «команда + аргументы + env»,
110
+ записываемая в конфиг клиента:
95
111
 
96
112
  ```typescript
97
- interface BaseMCPServerConfig {
98
- projectPath: string; // Путь к проекту
99
- logLevel?: 'debug' | 'info' | 'warn' | 'error';
100
- env?: Record<string, string>; // Переменные окружения
101
- }
102
-
103
- // Расширяем для своего сервера
104
- interface YandexTrackerConfig extends BaseMCPServerConfig {
105
- token: string; // Секрет - НЕ сохраняется
106
- orgId: string; // Безопасно - сохраняется
107
- apiBase?: string; // Безопасно - сохраняется
113
+ interface ServerLaunchSpec {
114
+ command: string;
115
+ args: string[];
116
+ env: Record<string, string>;
108
117
  }
109
118
  ```
110
119
 
111
- ### 2. Коннекторы
112
-
113
- **Коннектор** — адаптер для конкретного MCP клиента (Claude Desktop, Claude Code и т.д.).
120
+ ### Коннекторы
114
121
 
115
- **Встроенные коннекторы:**
116
- - `ClaudeDesktopConnector` — Claude Desktop (macOS/Windows)
117
- - `ClaudeCodeConnector` — Claude Code (VSCode extension)
118
- - `CodexConnector` — Codex IDE
119
- - `GeminiConnector` — Google Gemini
120
- - `QwenConnector` — Alibaba Qwen
122
+ **Два типа коннекторов:**
121
123
 
122
- **Использование:**
124
+ 1. **`ConfigurableConnector`** — файл-ориентированные клиенты (Claude Desktop,
125
+ Gemini, Qwen, Codex). Создаётся через фабрику `createConnector(client, serverName)`.
126
+ 2. **`ClaudeCodeConnector`** — Claude Code CLI (управляется командами `claude mcp add/remove/list/get`).
123
127
 
124
128
  ```typescript
125
- import { ClaudeDesktopConnector } from '@fractalizer/mcp-cli/connectors';
126
-
127
- const connector = new ClaudeDesktopConnector(
128
- 'my-server', // Имя сервера в конфиге клиента
129
- 'dist/index.js' // Путь к entry point вашего MCP сервера
130
- );
131
-
132
- // Проверить установку
133
- const isInstalled = await connector.isInstalled();
134
-
135
- // Подключить
136
- await connector.connect(config);
137
-
138
- // Отключить
139
- await connector.disconnect();
140
-
141
- // Проверить статус
142
- const status = await connector.getStatus();
129
+ const desktop = createConnector('claude-desktop', 'my-server');
130
+ const claudeCode = new ClaudeCodeConnector('my-server');
143
131
  ```
144
132
 
145
- ### 3. Реестр коннекторов
146
-
147
- `ConnectorRegistry` управляет коллекцией коннекторов:
133
+ **Контракт `MCPConnector`:**
148
134
 
149
135
  ```typescript
150
- const registry = new ConnectorRegistry<MyServerConfig>();
136
+ interface MCPConnector {
137
+ getClientInfo(): MCPClientInfo;
138
+ isInstalled(): Promise<boolean>;
139
+ getStatus(): Promise<ConnectionStatus>;
140
+ connect(spec: ServerLaunchSpec): Promise<void>;
141
+ disconnect(): Promise<void>;
142
+ validateLaunchSpec(spec: ServerLaunchSpec): Promise<string[]>;
143
+ getLaunchSpec(): Promise<ServerLaunchSpec | null>;
144
+ }
145
+ ```
151
146
 
152
- // Регистрация
153
- registry.register(new ClaudeDesktopConnector('my-server', 'dist/index.js'));
154
- registry.register(new ClaudeCodeConnector('my-server', 'dist/index.js'));
147
+ ### ConnectorRegistry
155
148
 
156
- // Получение
157
- const connector = registry.get('claude-desktop');
149
+ ```typescript
150
+ const registry = new ConnectorRegistry();
151
+ registry.register(createConnector('gemini', 'my-server'));
158
152
 
159
- // Поиск установленных
153
+ // Установленные клиенты (проверка параллельная)
160
154
  const installed = await registry.findInstalled();
161
155
 
162
- // Проверка статусов всех
156
+ // Все статусы параллельно через Promise.allSettled
163
157
  const statuses = await registry.checkAllStatuses();
164
158
  ```
165
159
 
166
- ### 4. Менеджер конфигурации
160
+ ### ConfigManager
167
161
 
168
- `ConfigManager` сохраняет и загружает конфигурацию (только безопасные поля):
162
+ Хранит **доменную** конфигурацию в `~/.{projectName}/config.json`:
169
163
 
170
164
  ```typescript
171
- const configManager = new ConfigManager<MyServerConfig>({
165
+ const cm = new ConfigManager<MyConfig>({
172
166
  projectName: 'my-server',
173
- safeFields: ['orgId', 'apiBase', 'logLevel'], // БЕЗ token!
167
+ // По умолчанию сохраняется весь объект как есть.
168
+ // Чтобы исключить секреты — задайте serialize:
169
+ serialize: (cfg) => ({ orgId: cfg.orgId, apiBase: cfg.apiBase }),
174
170
  });
175
171
 
176
- // Сохранить (только safeFields будут записаны)
177
- await configManager.save(config);
178
-
179
- // Загрузить
180
- const saved = await configManager.load();
181
- // saved = { orgId: '...', apiBase: '...', logLevel: 'info' }
182
- // token НЕ сохранен!
172
+ await cm.save(config); // ~/.my-server/config.json
173
+ const saved = await cm.load();
183
174
  ```
184
175
 
185
- **Путь к файлу:** `~/.{projectName}/config.json`
176
+ Права файла `0o600`. Для фильтрации полей при сохранении используйте
177
+ `serialize`-хук (единственный механизм).
186
178
 
187
- ### 5. Интерактивные промпты
188
-
189
- `ConfigPromptDefinition` определяет, как собирать конфигурацию:
179
+ ### Интерактивные промпты
190
180
 
191
181
  ```typescript
192
- const prompts: ConfigPromptDefinition<MyServerConfig>[] = [
193
- {
194
- name: 'token',
195
- type: 'password',
196
- message: 'OAuth токен:',
197
- validate: (value) => value ? true : 'Токен обязателен',
198
- },
199
- {
200
- name: 'orgId',
201
- type: 'input',
202
- message: 'ID организации:',
203
- default: (saved) => saved?.orgId, // Используем сохраненное
204
- },
182
+ const prompts: ConfigPromptDefinition<MyConfig>[] = [
183
+ { name: 'token', type: 'password', message: 'OAuth токен:' },
184
+ { name: 'orgId', type: 'input', message: 'ID организации:' },
205
185
  {
206
186
  name: 'logLevel',
207
187
  type: 'select',
@@ -209,173 +189,109 @@ const prompts: ConfigPromptDefinition<MyServerConfig>[] = [
209
189
  choices: [
210
190
  { name: 'Debug', value: 'debug' },
211
191
  { name: 'Info', value: 'info' },
212
- { name: 'Warn', value: 'warn' },
213
- { name: 'Error', value: 'error' },
214
192
  ],
215
193
  default: 'info',
216
194
  },
217
195
  ];
218
196
 
219
- const prompter = new InteractivePrompter<MyServerConfig>(prompts);
197
+ const prompter = new InteractivePrompter<MyConfig>(prompts);
220
198
  const config = await prompter.promptServerConfig(savedConfig);
221
199
  ```
222
200
 
223
- **Типы промптов:**
224
- - `input` — текстовый ввод
225
- - `password` — скрытый ввод (для секретов)
226
- - `select` — выбор из списка
227
- - `confirm` — да/нет
228
- - `number` — числовой ввод
201
+ **Типы промптов:** `input`, `password`, `select`, `confirm`, `number`.
229
202
 
230
203
  ---
231
204
 
232
- ## 🎨 Команды
205
+ ## Команды
233
206
 
234
207
  ### connectCommand
235
208
 
236
- Подключает MCP сервер к выбранному клиенту.
209
+ Поток:
237
210
 
238
- ```typescript
239
- import { connectCommand } from '@fractalizer/mcp-cli/commands';
211
+ 1. Найти установленные клиенты.
212
+ 2. Выбрать клиент (через `--client` или интерактивно).
213
+ 3. Загрузить сохранённую доменную конфигурацию.
214
+ 4. Собрать новую конфигурацию через промпты.
215
+ 5. `buildServerLaunch(domainConfig)` → `ServerLaunchSpec`.
216
+ 6. `connector.validateLaunchSpec(spec)`. При ошибках — abort.
217
+ 7. `connector.connect(spec)`. При исключении управление прерывается до save.
218
+ 8. `connector.getStatus()` (информационный).
219
+ 9. **После успешного connect** — `configManager.save(domainConfig)` и warning про
220
+ plaintext-хранение токена в конфиге клиента.
240
221
 
222
+ ```typescript
241
223
  await connectCommand({
242
224
  registry,
243
225
  configManager,
244
226
  configPrompts,
245
- cliOptions: {
246
- client: 'claude-desktop', // Опционально: пропустить выбор клиента
247
- },
248
- buildConfig: (serverConfig) => ({
249
- ...serverConfig,
250
- projectPath: process.cwd(),
227
+ buildServerLaunch: (cfg) => ({
228
+ command: 'node',
229
+ args: ['/abs/path/server.bundle.cjs'],
230
+ env: { API_TOKEN: cfg.token, ORG_ID: cfg.orgId },
251
231
  }),
232
+ cliOptions: { client: 'claude-desktop' },
252
233
  });
253
234
  ```
254
235
 
255
- ### disconnectCommand
256
-
257
- Отключает MCP сервер от клиента.
258
-
259
- ```typescript
260
- import { disconnectCommand } from '@fractalizer/mcp-cli/commands';
261
-
262
- await disconnectCommand({
263
- registry,
264
- cliOptions: {
265
- client: 'claude-desktop',
266
- },
267
- });
268
- ```
269
-
270
- ### statusCommand
271
-
272
- Показывает статус подключений для всех клиентов.
236
+ ### disconnectCommand / statusCommand / listCommand / validateCommand
273
237
 
274
238
  ```typescript
275
- import { statusCommand } from '@fractalizer/mcp-cli/commands';
276
-
239
+ await disconnectCommand({ registry, cliOptions: { client: 'claude-desktop' } });
277
240
  await statusCommand({ registry });
278
- ```
279
-
280
- ### listCommand
281
-
282
- Показывает список всех доступных MCP клиентов.
283
-
284
- ```typescript
285
- import { listCommand } from '@fractalizer/mcp-cli/commands';
286
-
287
241
  await listCommand({ registry });
242
+ await validateCommand({ registry });
288
243
  ```
289
244
 
290
- ### validateCommand
291
-
292
- Валидирует текущую конфигурацию для выбранного клиента.
293
-
294
- ```typescript
295
- import { validateCommand } from '@fractalizer/mcp-cli/commands';
296
-
297
- await validateCommand({
298
- registry,
299
- configManager,
300
- configPrompts,
301
- cliOptions: {
302
- client: 'claude-desktop',
303
- },
304
- });
305
- ```
245
+ `statusCommand` и `validateCommand` собирают статусы параллельно через
246
+ `Promise.allSettled`, рендерят результат в детерминированном порядке регистрации.
306
247
 
307
248
  ---
308
249
 
309
- ## 🛠️ Утилиты
250
+ ## Утилиты
310
251
 
311
252
  ### CommandExecutor
312
253
 
313
- Выполнение shell команд:
314
-
315
- ```typescript
316
- import { CommandExecutor } from '@fractalizer/mcp-cli/utils';
317
-
318
- const result = await CommandExecutor.execute('ls -la');
319
- if (result.success) {
320
- console.log(result.stdout);
321
- }
322
- ```
323
-
324
- ### FileManager
325
-
326
- Работа с файлами:
327
-
328
254
  ```typescript
329
- import { FileManager } from '@fractalizer/mcp-cli/utils';
255
+ import { CommandExecutor } from '@fractalizer/mcp-cli';
330
256
 
331
- // Чтение JSON
332
- const data = await FileManager.readJSON('/path/to/config.json');
257
+ // Простое выполнение
258
+ const out = CommandExecutor.exec('node --version');
333
259
 
334
- // Запись JSON
335
- await FileManager.writeJSON('/path/to/config.json', data);
260
+ // С таймаутом — при превышении бросает Error('Timeout: ...').
261
+ const list = CommandExecutor.exec('claude mcp list', { timeout: 5000 });
336
262
 
337
- // Проверка существования
338
- const exists = await FileManager.exists('/path/to/file');
263
+ // Интерактивно (наследует stdio)
264
+ await CommandExecutor.execInteractive('claude', ['mcp', 'add', '...']);
339
265
 
340
- // Создание директории
341
- await FileManager.ensureDir('/path/to/dir');
266
+ // Проверка наличия в PATH
267
+ if (CommandExecutor.isCommandAvailable('claude')) { /* ... */ }
342
268
  ```
343
269
 
344
- ### Logger
345
-
346
- CLI логирование:
270
+ ### FileManager / Logger
347
271
 
348
272
  ```typescript
349
- import { Logger } from '@fractalizer/mcp-cli/utils';
273
+ import { FileManager, Logger } from '@fractalizer/mcp-cli';
274
+
275
+ const data = await FileManager.readJSON('/path/to/config.json');
276
+ await FileManager.writeJSON('/path/to/config.json', data);
350
277
 
351
278
  Logger.info('Информация');
352
279
  Logger.success('Успех!');
353
- Logger.error('Ошибка!');
354
- Logger.warn('Предупреждение');
355
-
356
- const spinner = Logger.spinner('Загрузка...');
357
- // ... выполнение операции ...
358
- spinner.succeed('Готово!');
280
+ Logger.warn('Внимание');
281
+ Logger.error('Ошибка');
359
282
  ```
360
283
 
361
284
  ---
362
285
 
363
- ## 🏗️ Создание кастомного коннектора
286
+ ## Кастомный коннектор
364
287
 
365
- Если нужно добавить новый MCP клиент:
288
+ Если нужно поддержать клиент, не входящий в `KnownClient`:
366
289
 
367
290
  ```typescript
368
- import { BaseConnector } from '@fractalizer/mcp-cli/connectors';
369
- import type { MCPClientInfo, ConnectionStatus } from '@fractalizer/mcp-cli';
370
-
371
- class MyCustomConnector<TConfig extends BaseMCPServerConfig> extends BaseConnector<TConfig> {
372
- constructor(
373
- private serverName: string,
374
- private serverPath: string
375
- ) {
376
- super();
377
- }
291
+ import { BaseConnector } from '@fractalizer/mcp-cli';
292
+ import type { MCPClientInfo, ConnectionStatus, ServerLaunchSpec } from '@fractalizer/mcp-cli';
378
293
 
294
+ class MyCustomConnector extends BaseConnector {
379
295
  getClientInfo(): MCPClientInfo {
380
296
  return {
381
297
  name: 'my-client',
@@ -386,53 +302,29 @@ class MyCustomConnector<TConfig extends BaseMCPServerConfig> extends BaseConnect
386
302
  };
387
303
  }
388
304
 
389
- async isInstalled(): Promise<boolean> {
390
- // Проверка установки клиента
391
- return true;
392
- }
305
+ async isInstalled(): Promise<boolean> { /* ... */ return true; }
393
306
 
394
- async getStatus(): Promise<ConnectionStatus> {
395
- // Проверка статуса подключения
396
- return { connected: true };
397
- }
307
+ async getStatus(): Promise<ConnectionStatus> { /* ... */ return { connected: true }; }
398
308
 
399
- async connect(config: TConfig): Promise<void> {
400
- // Логика подключения
401
- }
309
+ async connect(spec: ServerLaunchSpec): Promise<void> { /* запись spec */ }
402
310
 
403
- async disconnect(): Promise<void> {
404
- // Логика отключения
405
- }
311
+ async disconnect(): Promise<void> { /* удаление записи */ }
406
312
 
407
- async validateConfig(config: TConfig): Promise<string[]> {
408
- const errors = await super.validateConfig(config);
409
- // Добавить свои проверки
410
- return errors;
411
- }
313
+ async getLaunchSpec(): Promise<ServerLaunchSpec | null> { /* чтение записи */ return null; }
412
314
  }
413
-
414
- // Использование
415
- const connector = new MyCustomConnector('my-server', 'dist/index.js');
416
- registry.register(connector);
417
315
  ```
418
316
 
419
- ---
420
-
421
- ## 📖 Примеры использования
422
-
423
- ### Реальный пример: Yandex Tracker MCP
424
-
425
- См. реализацию в [`packages/servers/yandex-tracker/src/cli/`](../../servers/yandex-tracker/src/cli/).
426
-
427
- ---
428
-
429
- ## 🔗 См. также
317
+ `BaseConnector.validateLaunchSpec` уже проверяет:
318
+ - `spec.command` непустой;
319
+ - абсолютный путь команды существует на диске;
320
+ - для `command === 'node'` — первый абсолютный путь в `spec.args` существует;
321
+ - значения `spec.env` строки.
430
322
 
431
- - **[Полный API Reference](./API.md)** — детальная документация всех типов и методов
432
- - **[@fractalizer/mcp-infrastructure](../infrastructure/README.md)** — инфраструктурные утилиты
323
+ Наследник может переопределить, вызвав `super.validateLaunchSpec(spec)` для
324
+ сохранения базовых проверок.
433
325
 
434
326
  ---
435
327
 
436
- ## 📝 Лицензия
328
+ ## Лицензия
437
329
 
438
330
  PolyForm Shield License 1.0.0
@@ -2,31 +2,34 @@
2
2
  * Connect команда для подключения MCP сервера к клиенту
3
3
  * @packageDocumentation
4
4
  */
5
- import type { BaseMCPServerConfig, ConnectCommandOptions } from '../types.js';
5
+ import type { ConnectCommandOptions } from '../types.js';
6
6
  /**
7
- * Команда для подключения MCP сервера к выбранному клиенту
7
+ * Команда подключения MCP сервера к выбранному клиенту.
8
8
  *
9
- * @param options - Опции команды
9
+ * Поток:
10
+ * 1. Найти установленные клиенты (`registry.findInstalled`).
11
+ * 2. Выбрать клиент (через CLI флаг `--client` или интерактивно).
12
+ * 3. Загрузить сохранённую доменную конфигурацию (`configManager.load`).
13
+ * 4. Собрать новую доменную конфигурацию через промпты.
14
+ * 5. Адаптер `buildServerLaunch(config)` → {@link ServerLaunchSpec}.
15
+ * 6. `connector.validateLaunchSpec(spec)`; при ошибках — abort (без `connect`/`save`).
16
+ * 7. `connector.connect(spec)`. При исключении управление прерывается, `save` не достигается.
17
+ * 8. Информационный `getStatus()`.
18
+ * 9. После успешного connect — `configManager.save(domainConfig)` и warning про plaintext-токен.
10
19
  *
11
20
  * @example
12
21
  * ```typescript
13
- * const registry = new ConnectorRegistry<YourConfig>();
14
- * const configManager = new ConfigManager<YourConfig>({
15
- * projectName: 'your-server',
16
- * safeFields: ['orgId', 'apiBase'],
17
- * });
18
- *
19
- * const configPrompts = [
20
- * { name: 'token', type: 'password', message: 'OAuth токен:' },
21
- * { name: 'orgId', type: 'input', message: 'ID организации:' },
22
- * ];
23
- *
24
22
  * await connectCommand({
25
23
  * registry,
26
24
  * configManager,
27
25
  * configPrompts,
26
+ * buildServerLaunch: (cfg) => ({
27
+ * command: 'node',
28
+ * args: ['/abs/path/server.bundle.cjs'],
29
+ * env: { API_TOKEN: cfg.token, ORG_ID: cfg.orgId },
30
+ * }),
28
31
  * });
29
32
  * ```
30
33
  */
31
- export declare function connectCommand<TConfig extends BaseMCPServerConfig>(options: ConnectCommandOptions<TConfig>): Promise<void>;
34
+ export declare function connectCommand<TDomainConfig extends object>(options: ConnectCommandOptions<TDomainConfig>): Promise<void>;
32
35
  //# sourceMappingURL=connect.command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connect.command.d.ts","sourceRoot":"","sources":["../../src/commands/connect.command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAI9E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,cAAc,CAAC,OAAO,SAAS,mBAAmB,EACtE,OAAO,EAAE,qBAAqB,CAAC,OAAO,CAAC,GACtC,OAAO,CAAC,IAAI,CAAC,CAiHf"}
1
+ {"version":3,"file":"connect.command.d.ts","sourceRoot":"","sources":["../../src/commands/connect.command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAIzD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,cAAc,CAAC,aAAa,SAAS,MAAM,EAC/D,OAAO,EAAE,qBAAqB,CAAC,aAAa,CAAC,GAC5C,OAAO,CAAC,IAAI,CAAC,CAoIf"}