如何扩展 MCP
本页提供两个扩展指南:一是在 Elftia 中添加新的 MCP 传输类型,二是编写能与 Elftia 配合使用的自定义 MCP 服务器。
指南一:添加新的传输类型
如果需要支持 Stdio/SSE/HTTP 以外的传输方式(如 WebSocket、gRPC 等),需要修改以下文件。
修改清单
| 步骤 | 文件 | 修改内容 |
|---|---|---|
| 1 | packages/desktop/app/shared/contracts/mcp-types.ts | 扩展 McpServerTransport 类型 |
| 2 | packages/desktop/app/main/services/capabilities/tools/mcp-users/McpService.ts | 在 createTransport() 添加新分支 |
| 3 | packages/desktop/app/main/services/routers/McpRouter.ts | 在 mcpAddSchema 中扩展 type 枚举 |
| 4 | packages/renderer/src/features/settings/components/tabs/tools-tab/types.ts | 更新前端类型 |
| 5 | packages/renderer/src/features/settings/components/tabs/tools-tab/McpServerForm.tsx | 添加表单选项 |
| 6 | 国际化文件 | 添加新传输类型的显示名称 |
步骤 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:实现传输层
在 McpService.ts 的 createTransport() 方法中添加新的 case 分支:
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');
}
// 使用你的 WebSocket 传输实现
return new WebSocketClientTransport(
new URL(server.config.url),
{ headers: server.config.headers || {} }
);
default:
throw new Error(`Unsupported transport type: ${server.type}`);
}
}
要求:传输实现必须符合 MCP SDK 的 Transport 接口,能够与 Client.connect() 配合使用。
步骤 3:更新 IPC 校验
在 McpRouter.ts 中扩展 Zod schema:
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 中添加新传输类型的显示名称。
指南二:编写自定义 MCP 服务器
编写一个能与 Elftia 配合使用的 MCP 服务器,需要遵循 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: {}
}
}
);
// 注册工具列表
server.setRequestHandler('tools/list', async () => ({
tools: [
{
name: 'hello',
description: '返回问候语',
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: '要问候的名字' }
},
required: ['name']
}
}
]
}));
// 处理工具调用
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
};
});
// 启动
const transport = new StdioServerTransport();
await server.connect(transport);
在 Elftia 中使用
将上述服务器保存为 my-server.js,在 Elftia 中添加 Stdio 服务器:
| 字段 | 值 |
|---|---|
| 名称 | 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: '结果文本' }
// 图片返回
{ type: 'image', mimeType: 'image/png', data: '<base64-encoded>' }
// 音频返回
{ type: 'audio', mimeType: 'audio/wav', data: '<base64-encoded>' }
注意:Elftia 的 McpToolAdapter 将图片和音频转换为占位符文本([Image: mime]),实际的二进制数据由 ToolCallDisplay 组件处理渲染。
超时注意事项
Elftia 对 MCP 工具调用设有 120 秒超时。如果你的工具可能执行较长时间的操作,建议:
- 实现异步处理,先返回任务 ID 再提供轮询接口
- 在工具描述中注明可能的等待时间
- 考虑使用流式返回(如果传输层支持)
npm 包发布
如果要将 MCP 服务器作为 npm 包发布(支持 npx 一键启动):
-
在
package.json中设置bin字段:{"name": "@yourorg/mcp-server-example","bin": {"mcp-server-example": "./dist/index.js"}} -
确保入口文件有 shebang:
#!/usr/bin/env node -
用户在 Elftia 中配置:
字段 值 命令 npx参数 -y,@yourorg/mcp-server-example
添加到官方预设
如果你的 MCP 服务器希望出现在 Elftia 的官方预设列表中,需要在 packages/desktop/app/shared/mcp-presets.ts 中添加配置:
export const OFFICIAL_MCP_PRESETS: OfficialMcpPreset[] = [
// 现有预设...
{
id: 'your-server-id',
name: 'Your Server Name',
provider: 'your-org',
category: 'general', // search | vision | web-reading | code-repo | general
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 提供商 ID(自动获取 Key) |
extraEnv | 否 | 额外固定环境变量 |
documentationUrl | 否 | 文档链接 |
DependencyCheckService 扩展
如果你的 MCP 服务器依赖非标准命令行工具,可以扩展 DependencyCheckService 的 installCommand() 方法:
文件路径: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 / node | Windows: winget; macOS: Homebrew; 其他: 下载页面 |
uv / uvx | 官方安装脚本(Windows: PowerShell; Unix: curl + sh) |