Перейти к основному содержимому

Worker-поток

mcp.worker.ts — это независимый Worker-поток, предоставляющий мостовой слой для управления MCP-серверами через CLI claude. Он дополняет McpService (подход прямого подключения через SDK), поддерживая чтение записей MCP-серверов из конфигурационных файлов Claude и выполнение операций добавления/удаления/тестирования через CLI.

Путь к файлу: packages/desktop/app/main/workers/mcp.worker.ts

Архитектурная схема

graph LR
subgraph Main["Главный процесс"]
Router["McpRouter / Caller"]
end

subgraph Worker["Worker-поток"]
Port["MessagePort"]
McpWorkerClass["McpWorker"]
end

subgraph External["Внешние"]
ClaudeCLI["claude CLI"]
ConfigFile["~/.claude/config.json"]
end

Router -->|postMessage| Port
Port -->|message event| McpWorkerClass
McpWorkerClass -->|spawn| ClaudeCLI
McpWorkerClass -->|readFile| ConfigFile
McpWorkerClass -->|postMessage| Port
Port -->|result/error| Router

Протокол связи

Формат запроса

type WorkerAction =
| { id: number; action: 'list' }
| { id: number; action: 'add'; payload: McpServerInput }
| { id: number; action: 'addJson'; payload: McpServerJsonInput }
| { id: number; action: 'remove'; payload: McpServerRemoveInput }
| { id: number; action: 'test'; payload: McpServerRemoveInput }
| { id: number; action: 'discover'; payload: McpServerRemoveInput };

Формат ответа

type WorkerResponse =
| { id: number; result: unknown }
| { id: number; error: string };

Каждый запрос сопоставляется с ответом через поле id.

Поддерживаемые операции

ActionМетодКоманда CLIОписание
listlist()Нет (прямое чтение файла)Чтение списка серверов из config.json
addadd()claude mcp addДобавить сервер
addJsonaddJson()claude mcp add-jsonПакетное добавление из JSON
removeremove()claude mcp removeУдалить сервер
testtest()claude mcp testПроверить подключение
discoverdiscover()claude mcp inspectОбнаружить инструменты/ресурсы/промпты

list — Чтение конфигурационного файла

list() не вызывает CLI, а напрямую читает файл ~/.claude/config.json:

private async readClaudeConfig(): Promise<ClaudeConfig | null> {
const configPath = path.join(os.homedir(), '.claude', 'config.json');
const content = await fsp.readFile(configPath, 'utf8');
return JSON.parse(content);
}

Структура конфигурационного файла

interface ClaudeConfig {
mcpServers?: Record<string, McpServerConfig & Record<string, unknown>>;
projects?: Record<string, {
mcpServers?: Record<string, McpServerConfig & Record<string, unknown>>;
}>;
}

Сопоставление записей серверов

Записи, прочитанные из config.json, необходимо преобразовать во внутренний формат:

private toServerRecord(input): McpServerRecord {
// Определение типа транспорта: transport > type > по умолчанию 'stdio'
const transport = config.transport ?? config.type ?? 'stdio';

return {
id: `${scope}:${projectPath ?? 'global'}:${name}`,
name,
scope,
type: transport,
projectPath,
status: 'configured',
config
};
}

Формат ID: {scope}:{projectPath|global}:{name}

Области видимости (Scopes):

  • user — Глобально настроенные серверы (верхний уровень mcpServers)
  • local — Серверы уровня проекта (projects[path].mcpServers)

add — Добавление сервера

Добавление серверов через команду CLI claude mcp add:

Stdio-сервер

claude mcp add --scope user my-server \
-e API_KEY=xxx \
npx -y @example/mcp-server

Построение параметров:

  1. ['mcp', 'add', '--scope', scope, name]
  2. Перебор env, добавление параметров -e KEY=VALUE
  3. Добавление command и args

SSE/HTTP-сервер

claude mcp add --scope user my-server \
--transport sse \
--header "Authorization: Bearer token" \
https://api.example.com/mcp

Построение параметров:

  1. ['mcp', 'add', '--scope', scope, name]
  2. --transport sse|http
  3. URL
  4. Перебор headers, добавление параметров --header "Key: Value"

discover — Обнаружение возможностей

Используйте команду claude mcp inspect для получения инвентаря возможностей в формате JSON:

claude mcp inspect --scope user my-server --format json

Извлечение JSON

Извлечение JSON-объекта из вывода CLI:

private extractJson(output: string) {
const match = /\{[\s\S]*\}/.exec(output);
if (!match) return null;
return JSON.parse(match[0]);
}

Нормализация результата

Списки инструментов/ресурсов/промптов стандартизируются в формат McpToolInfo[]:

private normalizeToolList(value: any): McpToolInfo[] {
// Поддержка массивов строк и массивов объектов
// string → { name: string }
// { name, description } → McpToolInfo
}

Разбор идентификаторов серверов

Идентификаторы серверов в Worker используют формат scope:name (отличается от UUID-формата McpService):

private parseServerIdentifier(id?: string, scope?: string) {
const [prefix, ...rest] = id.split(':');
const name = rest.length ? rest.join(':') : prefix;
const normalizedScope = rest.length
? prefix as 'user' | 'local'
: scope ?? 'user';
return { scope: normalizedScope, name };
}

Примеры:

  • user:my-server{ scope: 'user', name: 'my-server' }
  • local:/path/to/project:db-server{ scope: 'local', name: '/path/to/project:db-server' }
  • my-server (без префикса) → { scope: 'user', name: 'my-server' }

Выполнение CLI

Все CLI-операции выполняются через метод runClaude():

private async runClaude(
args: string[],
options: { cwd?: string } = {}
): Promise<{ success: boolean; stdout: string; stderr: string }>
  • Использует child_process.spawn для запуска процесса claude
  • Собирает stdout и stderr
  • Определяет успех/неудачу по коду завершения процесса
  • Поддерживает указание рабочего каталога (cwd) для операций с локальной областью видимости

Взаимосвязь Worker и McpService

ХарактеристикаMcpService (прямое подключение через SDK)mcp.worker (CLI-мост)
Метод подключенияПрямое использование MCP SDKЧерез CLI claude
Модель процессаВнутри главного процессаНезависимый Worker-поток
Источник конфигурацииElectron Store (mcp-config)~/.claude/config.json
Вызов инструментовПоддерживаетсяНе поддерживается
НазначениеПодключения во время выполнения и вызов инструментовУправление конфигурацией и совместимость с CLI
Режим работыПостоянное подключениеОперации по запросу

Примечание: в текущей версии McpService (прямое подключение через SDK) является основной реализацией во время выполнения. Worker служит дополнением, обеспечивая совместимость конфигураций с Claude CLI. Конфигурации, управляемые ими, независимы (хранятся раздельно в Electron Store и ~/.claude/config.json).

Обработка ошибок

Ошибки в Worker-потоке передаются через протокол сообщений:

port.on('message', async (message: WorkerAction) => {
try {
// Обработка запроса...
port.postMessage({ id: message.id, result: ... });
} catch (error) {
port.postMessage({
id: message.id,
error: error instanceof Error ? error.message : String(error)
});
}
});

Все исключения перехватываются и преобразуются в ответы с ошибкой без завершения работы Worker-потока.

Связанные файлы