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

Расширение MCP

На этой странице представлены два руководства: первое — по добавлению новых типов транспорта MCP в Elftia, второе — по написанию пользовательских MCP-серверов, совместимых с Elftia.

Руководство 1: Добавление новых типов транспорта

Если вам нужна поддержка методов передачи данных, отличных от Stdio/SSE/HTTP (например, WebSocket, gRPC и т. д.), необходимо изменить следующие файлы.

Чек-лист изменений

ШагФайлИзменения
1packages/desktop/app/shared/contracts/mcp-types.tsРасширить тип McpServerTransport
2packages/desktop/app/main/services/capabilities/tools/mcp-users/McpService.tsДобавить новую ветку в createTransport()
3packages/desktop/app/main/services/routers/McpRouter.tsРасширить перечисление типов в mcpAddSchema
4packages/renderer/src/features/settings/components/tabs/tools-tab/types.tsОбновить типы фронтенда
5packages/renderer/src/features/settings/components/tabs/tools-tab/McpServerForm.tsxДобавить параметры формы
6Файлы i18nДобавить отображаемые имена для нового типа транспорта

Шаг 1: Расширение типов

Добавить новое значение типа транспорта в mcp-types.ts:

export type McpServerTransport = 'stdio' | 'http' | 'sse' | 'websocket';

Также проверить, требуются ли новые поля в McpServerConfig:

export type McpServerConfig = {
command?: string;
args?: string[];
env?: Record<string, string>;
url?: string;
headers?: Record<string, string>;
transport?: string;
// Добавить новые поля при необходимости
wsProtocol?: string;
};

Шаг 2: Реализация транспортного уровня

Добавить новую ветку case в метод createTransport() в McpService.ts:

private async createTransport(server: McpServerRecord) {
switch (server.type) {
case 'stdio':
// ...
case 'sse':
// ...
case 'http':
// ...
case 'websocket':
if (!server.config.url) {
throw new Error('WebSocket server requires url');
}
// Use your WebSocket transport implementation
return new WebSocketClientTransport(
new URL(server.config.url),
{ headers: server.config.headers || {} }
);
default:
throw new Error(`Unsupported transport type: ${server.type}`);
}
}

Требование: реализация транспорта должна соответствовать интерфейсу Transport из MCP SDK и быть совместима с Client.connect().

Шаг 3: Обновление IPC-валидации

Расширить Zod-схему в McpRouter.ts:

const mcpAddSchema = z.object({
// ...
type: z.enum(['stdio', 'http', 'sse', 'websocket']),
// ...
});

Шаги 4–5: Обновление фронтенда

Добавить параметры в селектор типа транспорта в McpServerForm.tsx:

options={[
{ value: 'stdio', label: t('...stdio') },
{ value: 'sse', label: t('...sse') },
{ value: 'http', label: t('...http') },
{ value: 'websocket', label: t('...websocket') },
]}

В зависимости от требований нового типа транспорта добавьте соответствующие поля конфигурационной формы (URL, выбор протокола и т. д.).

Шаг 6: Интернационализация

Добавить отображаемые имена для нового типа транспорта в locales/{en,zh,ja}/settings/tools.json.

Руководство 2: Написание пользовательских MCP-серверов

Написание MCP-сервера, совместимого с Elftia, требует соблюдения спецификации протокола MCP.

Минимальный Stdio-сервер (Node.js)

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const server = new Server(
{ name: 'my-custom-server', version: '1.0.0' },
{
capabilities: {
tools: {}
}
}
);

// Register tool list
server.setRequestHandler('tools/list', async () => ({
tools: [
{
name: 'hello',
description: 'Return a greeting',
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: 'Name to greet' }
},
required: ['name']
}
}
]
}));

// Handle tool calls
server.setRequestHandler('tools/call', async (request) => {
if (request.params.name === 'hello') {
const name = request.params.arguments?.name ?? 'World';
return {
content: [
{ type: 'text', text: `Hello, ${name}!` }
]
};
}
return {
content: [{ type: 'text', text: 'Unknown tool' }],
isError: true
};
});

// Start
const transport = new StdioServerTransport();
await server.connect(transport);

Использование в Elftia

Сохраните приведённый выше сервер как my-server.js и добавьте Stdio-сервер в Elftia:

ПолеЗначение
Имяmy-custom-server
Тип транспортаStdio
Командаnode
Аргументы/path/to/my-server.js

Спецификация определения инструментов

Elftia предъявляет следующие требования к инструментам MCP:

ТребованиеОписание
ИмяОбязательно; используется для генерации ID инструмента (mcp__server__name)
ОписаниеНастоятельно рекомендуется; LLM опирается на описание, чтобы решить, когда вызвать инструмент
inputSchemaДолжна быть валидной JSON Schema с type: 'object'
Формат возвратаМассив content, каждый элемент содержит type и соответствующие данные

Типы возвращаемого содержимого

// Текстовый возврат
{ type: 'text', text: 'Result text' }

// Возврат изображения
{ type: 'image', mimeType: 'image/png', data: '<base64-encoded>' }

// Аудиовозврат
{ type: 'audio', mimeType: 'audio/wav', data: '<base64-encoded>' }

Примечание: McpToolAdapter в Elftia преобразует изображения и аудио в текст-заглушку ([Image: mime]), а фактические бинарные данные отображает компонент ToolCallDisplay.

Учёт тайм-аутов

Elftia устанавливает тайм-аут 120 секунд для вызовов инструментов MCP. Если ваш инструмент может выполнять длительные операции, рекомендуется:

  • Реализовать асинхронную обработку: сначала вернуть ID задачи, а затем предоставить интерфейс для опроса
  • Указать возможное время ожидания в описании инструмента
  • Рассмотреть использование потоковых ответов (если транспортный уровень поддерживает)

Публикация пакета npm

Если вы хотите опубликовать MCP-сервер как npm-пакет (с поддержкой запуска одной командой через npx):

  1. Задайте поле bin в package.json:

    {
    "name": "@yourorg/mcp-server-example",
    "bin": {
    "mcp-server-example": "./dist/index.js"
    }
    }
  2. Убедитесь, что входной файл содержит shebang:

    #!/usr/bin/env node
  3. Пользователь настраивает в Elftia следующим образом:

    ПолеЗначение
    Командаnpx
    Аргументы-y , @yourorg/mcp-server-example

Добавление в официальные пресеты

Если вы хотите, чтобы ваш MCP-сервер появился в официальном списке пресетов Elftia, добавьте конфигурацию в packages/desktop/app/shared/mcp-presets.ts:

export const OFFICIAL_MCP_PRESETS: OfficialMcpPreset[] = [
// Existing presets...
{
id: 'your-server-id',
name: 'Your Server Name',
provider: 'your-org',
category: 'general', // search | vision | web-reading | code-repo | general
description: 'Server feature description',
tools: ['tool1', 'tool2'],
command: 'npx',
args: ['-y', '@yourorg/mcp-server@latest'],
requiresApiKey: true,
apiKeyEnvVar: 'YOUR_API_KEY',
linkedProviderIds: ['provider-id'],
documentationUrl: 'https://docs.example.com',
icon: 'icon-name',
},
];

Описание полей пресета:

ПолеОбязательноОписание
idДаУникальный идентификатор
nameДаОтображаемое имя
providerДаИдентификатор провайдера
categoryДаКатегория: search / vision / web-reading / code-repo / general
descriptionДаОписание функциональности
toolsДаСписок предоставляемых имён инструментов
transportTypeНетstdio (по умолчанию) / http
commandДля StdioКоманда запуска
argsДля StdioАргументы команды
urlДля HTTPУдалённый URL
requiresApiKeyДаТребуется ли API Key
apiKeyEnvVarНетИмя переменной среды для API Key
linkedProviderIdsНетИдентификаторы связанных LLM-провайдеров (автоматическое получение ключа)
extraEnvНетДополнительные фиксированные переменные среды
documentationUrlНетСсылка на документацию

Расширение DependencyCheckService

Если ваш MCP-сервер зависит от нестандартных инструментов командной строки, можно расширить метод installCommand() в DependencyCheckService:

Путь к файлу: packages/desktop/app/main/services/capabilities/tools/mcp-users/DependencyCheckService.ts

async installCommand(command: string): Promise<DependencyInstallResult> {
// ...
if (command === 'your-tool') {
return await this.installYourTool(command);
}
// ...
}

Поддерживаемая автоматическая установка:

КомандаСпособ установки
npx / npm / nodeWindows: winget; macOS: Homebrew; другие: страница загрузки
uv / uvxОфициальный скрипт установки (Windows: PowerShell; Unix: curl + sh)

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