@fractalizer/mcp-cli 0.3.18 → 1.0.1
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/README.md +158 -266
- package/dist/commands/connect.command.d.ts +18 -15
- package/dist/commands/connect.command.d.ts.map +1 -1
- package/dist/commands/connect.command.js +66 -40
- package/dist/commands/connect.command.js.map +1 -1
- package/dist/commands/disconnect.command.d.ts +5 -17
- package/dist/commands/disconnect.command.d.ts.map +1 -1
- package/dist/commands/disconnect.command.js +4 -15
- package/dist/commands/disconnect.command.js.map +1 -1
- package/dist/commands/doctor.command.d.ts +34 -0
- package/dist/commands/doctor.command.d.ts.map +1 -0
- package/dist/commands/doctor.command.js +321 -0
- package/dist/commands/doctor.command.js.map +1 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/list.command.d.ts +4 -9
- package/dist/commands/list.command.d.ts.map +1 -1
- package/dist/commands/list.command.js +1 -5
- package/dist/commands/list.command.js.map +1 -1
- package/dist/commands/status.command.d.ts +6 -13
- package/dist/commands/status.command.d.ts.map +1 -1
- package/dist/commands/status.command.js +18 -12
- package/dist/commands/status.command.js.map +1 -1
- package/dist/commands/validate.command.d.ts +6 -11
- package/dist/commands/validate.command.d.ts.map +1 -1
- package/dist/commands/validate.command.js +15 -19
- package/dist/commands/validate.command.js.map +1 -1
- package/dist/connectors/base/base-connector.d.ts +31 -55
- package/dist/connectors/base/base-connector.d.ts.map +1 -1
- package/dist/connectors/base/base-connector.js +71 -57
- package/dist/connectors/base/base-connector.js.map +1 -1
- package/dist/connectors/base/configurable-connector.d.ts +89 -24
- package/dist/connectors/base/configurable-connector.d.ts.map +1 -1
- package/dist/connectors/base/configurable-connector.js +266 -23
- package/dist/connectors/base/configurable-connector.js.map +1 -1
- package/dist/connectors/base/connector.interface.d.ts +29 -20
- package/dist/connectors/base/connector.interface.d.ts.map +1 -1
- package/dist/connectors/base/index.d.ts +0 -1
- package/dist/connectors/base/index.d.ts.map +1 -1
- package/dist/connectors/base/index.js +0 -1
- package/dist/connectors/base/index.js.map +1 -1
- package/dist/connectors/claude-code/claude-code.connector.d.ts +171 -21
- package/dist/connectors/claude-code/claude-code.connector.d.ts.map +1 -1
- package/dist/connectors/claude-code/claude-code.connector.js +368 -43
- package/dist/connectors/claude-code/claude-code.connector.js.map +1 -1
- package/dist/connectors/connector-factory.d.ts +15 -15
- package/dist/connectors/connector-factory.d.ts.map +1 -1
- package/dist/connectors/connector-factory.js +61 -18
- package/dist/connectors/connector-factory.js.map +1 -1
- package/dist/connectors/index.d.ts +0 -4
- package/dist/connectors/index.d.ts.map +1 -1
- package/dist/connectors/index.js +2 -8
- package/dist/connectors/index.js.map +1 -1
- package/dist/connectors/registry.d.ts +20 -27
- package/dist/connectors/registry.d.ts.map +1 -1
- package/dist/connectors/registry.js +34 -34
- package/dist/connectors/registry.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/{base.types.d.ts → client.types.d.ts} +37 -30
- package/dist/types/client.types.d.ts.map +1 -0
- package/dist/types/client.types.js +6 -0
- package/dist/types/client.types.js.map +1 -0
- package/dist/types/doctor.types.d.ts +91 -0
- package/dist/types/doctor.types.d.ts.map +1 -0
- package/dist/types/doctor.types.js +12 -0
- package/dist/types/doctor.types.js.map +1 -0
- package/dist/types/launch.types.d.ts +59 -0
- package/dist/types/launch.types.d.ts.map +1 -0
- package/dist/types/launch.types.js +6 -0
- package/dist/types/launch.types.js.map +1 -0
- package/dist/types.d.ts +23 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +9 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/command-executor.d.ts +39 -3
- package/dist/utils/command-executor.d.ts.map +1 -1
- package/dist/utils/command-executor.js +95 -8
- package/dist/utils/command-executor.js.map +1 -1
- package/dist/utils/config-manager.d.ts +25 -42
- package/dist/utils/config-manager.d.ts.map +1 -1
- package/dist/utils/config-manager.js +21 -49
- package/dist/utils/config-manager.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/interactive-prompter.d.ts +16 -64
- package/dist/utils/interactive-prompter.d.ts.map +1 -1
- package/dist/utils/interactive-prompter.js +12 -65
- package/dist/utils/interactive-prompter.js.map +1 -1
- package/dist/utils/launch-spec-helpers.d.ts +38 -0
- package/dist/utils/launch-spec-helpers.d.ts.map +1 -0
- package/dist/utils/launch-spec-helpers.js +131 -0
- package/dist/utils/launch-spec-helpers.js.map +1 -0
- package/package.json +2 -2
- package/dist/connectors/base/file-based-connector.d.ts +0 -97
- package/dist/connectors/base/file-based-connector.d.ts.map +0 -1
- package/dist/connectors/base/file-based-connector.js +0 -185
- package/dist/connectors/base/file-based-connector.js.map +0 -1
- package/dist/connectors/claude-desktop/claude-desktop.connector.d.ts +0 -38
- package/dist/connectors/claude-desktop/claude-desktop.connector.d.ts.map +0 -1
- package/dist/connectors/claude-desktop/claude-desktop.connector.js +0 -68
- package/dist/connectors/claude-desktop/claude-desktop.connector.js.map +0 -1
- package/dist/connectors/codex/codex.connector.d.ts +0 -51
- package/dist/connectors/codex/codex.connector.d.ts.map +0 -1
- package/dist/connectors/codex/codex.connector.js +0 -76
- package/dist/connectors/codex/codex.connector.js.map +0 -1
- package/dist/connectors/gemini/gemini.connector.d.ts +0 -41
- package/dist/connectors/gemini/gemini.connector.d.ts.map +0 -1
- package/dist/connectors/gemini/gemini.connector.js +0 -61
- package/dist/connectors/gemini/gemini.connector.js.map +0 -1
- package/dist/connectors/qwen/qwen.connector.d.ts +0 -41
- package/dist/connectors/qwen/qwen.connector.d.ts.map +0 -1
- package/dist/connectors/qwen/qwen.connector.js +0 -61
- package/dist/connectors/qwen/qwen.connector.js.map +0 -1
- package/dist/types/base.types.d.ts.map +0 -1
- package/dist/types/base.types.js +0 -6
- 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
|
-
- **Поддержка
|
|
11
|
-
- **Типобезопасность** — TypeScript
|
|
12
|
-
- **Декларативные промпты** —
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
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
|
-
|
|
36
|
+
connectCommand,
|
|
37
|
+
ConnectorRegistry,
|
|
38
|
+
ConfigManager,
|
|
39
|
+
createConnector,
|
|
36
40
|
ClaudeCodeConnector,
|
|
37
|
-
} from '@fractalizer/mcp-cli
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
|
47
|
-
registry.register(
|
|
48
|
-
registry.register(
|
|
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
|
-
|
|
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
|
-
###
|
|
107
|
+
### ServerLaunchSpec
|
|
93
108
|
|
|
94
|
-
|
|
109
|
+
Спецификация запуска MCP сервера — готовая «команда + аргументы + env»,
|
|
110
|
+
записываемая в конфиг клиента:
|
|
95
111
|
|
|
96
112
|
```typescript
|
|
97
|
-
interface
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
env
|
|
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
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
`ConnectorRegistry` управляет коллекцией коннекторов:
|
|
133
|
+
**Контракт `MCPConnector`:**
|
|
148
134
|
|
|
149
135
|
```typescript
|
|
150
|
-
|
|
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
|
|
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
|
-
###
|
|
160
|
+
### ConfigManager
|
|
167
161
|
|
|
168
|
-
|
|
162
|
+
Хранит **доменную** конфигурацию в `~/.{projectName}/config.json`:
|
|
169
163
|
|
|
170
164
|
```typescript
|
|
171
|
-
const
|
|
165
|
+
const cm = new ConfigManager<MyConfig>({
|
|
172
166
|
projectName: 'my-server',
|
|
173
|
-
|
|
167
|
+
// По умолчанию сохраняется весь объект как есть.
|
|
168
|
+
// Чтобы исключить секреты — задайте serialize:
|
|
169
|
+
serialize: (cfg) => ({ orgId: cfg.orgId, apiBase: cfg.apiBase }),
|
|
174
170
|
});
|
|
175
171
|
|
|
176
|
-
|
|
177
|
-
await
|
|
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
|
-
|
|
176
|
+
Права файла — `0o600`. Для фильтрации полей при сохранении используйте
|
|
177
|
+
`serialize`-хук (единственный механизм).
|
|
186
178
|
|
|
187
|
-
###
|
|
188
|
-
|
|
189
|
-
`ConfigPromptDefinition` определяет, как собирать конфигурацию:
|
|
179
|
+
### Интерактивные промпты
|
|
190
180
|
|
|
191
181
|
```typescript
|
|
192
|
-
const prompts: ConfigPromptDefinition<
|
|
193
|
-
{
|
|
194
|
-
|
|
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<
|
|
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
|
-
|
|
209
|
+
Поток:
|
|
237
210
|
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
255
|
+
import { CommandExecutor } from '@fractalizer/mcp-cli';
|
|
330
256
|
|
|
331
|
-
//
|
|
332
|
-
const
|
|
257
|
+
// Простое выполнение
|
|
258
|
+
const out = CommandExecutor.exec('node --version');
|
|
333
259
|
|
|
334
|
-
//
|
|
335
|
-
|
|
260
|
+
// С таймаутом — при превышении бросает Error('Timeout: ...').
|
|
261
|
+
const list = CommandExecutor.exec('claude mcp list', { timeout: 5000 });
|
|
336
262
|
|
|
337
|
-
//
|
|
338
|
-
|
|
263
|
+
// Интерактивно (наследует stdio)
|
|
264
|
+
await CommandExecutor.execInteractive('claude', ['mcp', 'add', '...']);
|
|
339
265
|
|
|
340
|
-
//
|
|
341
|
-
|
|
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
|
|
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.
|
|
354
|
-
Logger.
|
|
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
|
-
Если нужно
|
|
288
|
+
Если нужно поддержать клиент, не входящий в `KnownClient`:
|
|
366
289
|
|
|
367
290
|
```typescript
|
|
368
|
-
import { BaseConnector } from '@fractalizer/mcp-cli
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
432
|
-
|
|
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 {
|
|
5
|
+
import type { ConnectCommandOptions } from '../types.js';
|
|
6
6
|
/**
|
|
7
|
-
* Команда
|
|
7
|
+
* Команда подключения MCP сервера к выбранному клиенту.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
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<
|
|
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,
|
|
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"}
|