Skip to content

Commit e2bb9f1

Browse files
committed
feat: refactor mcpProxy to agent process
1 parent c68311a commit e2bb9f1

File tree

26 files changed

+724
-629
lines changed

26 files changed

+724
-629
lines changed

agent.js

Lines changed: 192 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,38 @@
1+
const http = require('http');
2+
const env = require('./env.json');
13
const {
24
createTimedTask,
35
changeTimedTask,
46
cancelTimedTask,
57
timedTaskList,
68
timedTaskResult,
79
} = require('./app/utils/timedTask');
8-
const { startMcpInspector } = require('./app/utils/mcpInspector');
10+
const { startMcpInspector } = require('./app/agent/mcpInspector');
11+
const { MCPHttpHandler } = require('./app/agent/mcpHttpHandler');
12+
const { MCPProxy } = require('./app/mcp/mcpProxy');
13+
const { buildMCPConfig } = require('./app/utils');
914

1015
// 接收 app 发送来的消息并作出反应
1116
module.exports = (agent) => {
17+
// 初始化MCP端点HTTP处理器
18+
const mcpHttpHandler = new MCPHttpHandler(agent.logger);
19+
const mcpProxy = new MCPProxy(agent.logger);
20+
let httpServer = null;
21+
22+
// 等待Worker进程启动完成后再启动MCP服务
23+
agent.messenger.once('egg-ready', async () => {
24+
try {
25+
agent.logger.info('Worker进程已就绪,开始启动MCP端点HTTP服务...');
26+
27+
httpServer = createHttpServer(mcpHttpHandler);
28+
29+
// 启动所有已注册的MCP服务器,包括STDIO、SSE、HTTP等
30+
await startMCPServices(agent);
31+
} catch (error) {
32+
agent.logger.error('MCP端点HTTP服务启动失败:', error);
33+
}
34+
});
35+
1236
// 创建文章订阅任务
1337
agent.messenger.on('createTimedTask', ({ id, sendCron }) => {
1438
createTimedTask(id, sendCron, agent);
@@ -34,6 +58,172 @@ module.exports = (agent) => {
3458
timedTaskResult(result, agent);
3559
});
3660

61+
// 处理MCP服务器启动请求
62+
agent.messenger.on('mcpStart', async ({ serverId, config }) => {
63+
try {
64+
await mcpProxy.startProxy(serverId, config);
65+
agent.logger.info(`MCP服务器启动成功 [${serverId}]`);
66+
67+
// 发送成功消息回 worker
68+
agent.messenger.sendRandom('mcpStartResult', {
69+
serverId,
70+
success: true,
71+
});
72+
} catch (error) {
73+
agent.logger.error(`MCP服务器启动失败 [${serverId}]:`, error);
74+
75+
// 发送失败消息回 worker
76+
agent.messenger.sendRandom('mcpStartResult', {
77+
serverId,
78+
success: false,
79+
error: error.message,
80+
});
81+
}
82+
});
83+
84+
// 处理MCP服务器停止请求
85+
agent.messenger.on('mcpStop', async ({ serverId }) => {
86+
try {
87+
await mcpProxy.stopProxy(serverId);
88+
agent.logger.info(`MCP服务器停止成功 [${serverId}]`);
89+
90+
// 发送成功消息回 worker
91+
agent.messenger.sendToApp('mcpStopResult', {
92+
serverId,
93+
success: true,
94+
});
95+
} catch (error) {
96+
agent.logger.error(`MCP服务器停止失败 [${serverId}]:`, error);
97+
98+
// 发送失败消息回 worker
99+
agent.messenger.sendRandom('mcpStopResult', {
100+
serverId,
101+
success: false,
102+
error: error.message,
103+
});
104+
}
105+
});
106+
107+
// 处理MCP服务器重启请求
108+
agent.messenger.on('mcpRestart', async ({ serverId }) => {
109+
try {
110+
await mcpProxy.restartProxy(serverId);
111+
agent.logger.info(`MCP服务器重启成功 [${serverId}]`);
112+
113+
// 发送成功消息回 worker
114+
agent.messenger.sendRandom('mcpRestartResult', {
115+
serverId,
116+
success: true,
117+
});
118+
} catch (error) {
119+
agent.logger.error(`MCP服务器重启失败 [${serverId}]:`, error);
120+
121+
// 发送失败消息回 worker
122+
agent.messenger.sendRandom('mcpRestartResult', {
123+
serverId,
124+
success: false,
125+
error: error.message,
126+
});
127+
}
128+
});
129+
37130
// 启动MCP Inspector
38-
startMcpInspector(agent)
131+
startMcpInspector(agent);
132+
133+
// 进程退出前清理
134+
agent.beforeClose(async () => {
135+
agent.logger.info('Agent进程关闭,清理MCP服务...');
136+
137+
try {
138+
// 关闭HTTP服务器
139+
if (httpServer) {
140+
await new Promise((resolve) => {
141+
httpServer.close(() => {
142+
resolve();
143+
});
144+
});
145+
}
146+
147+
// 清理MCP代理
148+
await mcpHttpHandler.cleanup();
149+
150+
agent.logger.info('MCP服务清理完成');
151+
} catch (error) {
152+
agent.logger.error('MCP服务清理失败:', error);
153+
}
154+
});
39155
};
156+
157+
// 创建HTTP服务(用于处理MCP端点请求)
158+
async function createHttpServer(mcpHttpHandler) {
159+
const port = env.mcpEndpointPort || 7005;
160+
161+
httpServer = http.createServer(async (req, res) => {
162+
await mcpHttpHandler.handleRequest(req, res);
163+
});
164+
165+
httpServer.listen(port, () => {
166+
agent.logger.info(`MCP端点HTTP服务已启动,监听端口: ${port}`);
167+
});
168+
169+
httpServer.on('error', (error) => {
170+
agent.logger.error('MCP端点HTTP服务错误:', error);
171+
});
172+
173+
return httpServer;
174+
}
175+
176+
/**
177+
* 启动所有MCP服务,缓存配置信息
178+
* @param {Agent} agent - Agent实例
179+
*/
180+
async function startMCPServices(agent) {
181+
agent.logger.info('开始启动MCP服务...');
182+
183+
const ctx = agent.createAnonymousContext();
184+
185+
// 获取所有未删除的MCP服务器
186+
const enabledServers = await ctx.model.McpServer.findAll({
187+
where: {
188+
is_delete: 0,
189+
},
190+
});
191+
192+
if (enabledServers.length === 0) {
193+
agent.logger.info('无需要启动的MCP服务器');
194+
return;
195+
}
196+
197+
agent.logger.info(`启动${enabledServers.length}个MCP服务器...`);
198+
199+
let successCount = 0;
200+
let failCount = 0;
201+
202+
// 启动每个服务器
203+
for (const server of enabledServers) {
204+
try {
205+
// 构建MCP配置对象
206+
const config = buildMCPConfig(server);
207+
await MCPProxy.getInstance().startProxy(server.server_id, config);
208+
209+
successCount++;
210+
} catch (error) {
211+
agent.logger.error(`MCP服务器启动失败 [${server.server_id}]:`, error);
212+
213+
// 更新状态为错误
214+
await server.update({
215+
status: 'error',
216+
ping_error: error.message,
217+
last_ping_at: new Date(),
218+
});
219+
220+
failCount++;
221+
}
222+
}
223+
224+
setTimeout(() => {
225+
agent.messenger.sendRandom('mcpCheckAllServersHealth');
226+
}, 2000);
227+
228+
agent.logger.info(`MCP服务启动完成: 成功${successCount}个, 失败${failCount}个`);
229+
}

app.js

Lines changed: 29 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const fs = require('fs');
22
const utils = require('./app/utils');
3-
const { MCPProxy } = require('./app/mcp/mcpProxy');
43

54
module.exports = class AppBootHook {
65
constructor(app) {
@@ -14,9 +13,6 @@ module.exports = class AppBootHook {
1413
fs.mkdirSync(cacheDirectory);
1514
}
1615

17-
// 启动MCP服务
18-
await this.startMCPServices();
19-
2016
// 监听 agent 进程发出的信息并作出反应
2117
app.messenger.on('sendArticleSubscription', (id) => {
2218
// create an anonymous context to access service
@@ -25,90 +21,40 @@ module.exports = class AppBootHook {
2521
await ctx.service.articleSubscription.sendArticleSubscription(id);
2622
});
2723
});
28-
}
2924

30-
/**
31-
* 启动MCP服务
32-
*/
33-
async startMCPServices() {
34-
const { app } = this;
35-
const ctx = app.createAnonymousContext();
36-
37-
try {
38-
app.logger.info('开始启动MCP服务...');
39-
40-
// 获取所有启用的MCP服务器
41-
const enabledServers = await ctx.model.McpServer.findAll({
42-
where: {
43-
is_delete: 0,
44-
}
25+
// 监听 MCP 服务器启动结果
26+
app.messenger.on('mcpStartResult', (data) => {
27+
const { serverId, success, error } = data;
28+
const ctx = app.createAnonymousContext();
29+
ctx.runInBackground(async () => {
30+
await ctx.service.mcp.handleMCPStartResult(serverId, success, error);
4531
});
32+
});
4633

47-
if (enabledServers.length === 0) {
48-
app.logger.info('没有找到需要启动的MCP服务器');
49-
return;
50-
}
51-
52-
app.logger.info(`找到 ${enabledServers.length} 个需要启动的MCP服务器`);
53-
54-
// 启动每个服务器
55-
const startPromises = enabledServers.map(async (server) => {
56-
await ctx.service.mcp.startMCPServer(server.server_id).catch(err => {
57-
app.logger.error(`MCP服务器启动失败 [${server.server_id}]:`, err.message);
58-
});
34+
// 监听 MCP 服务器停止结果
35+
app.messenger.on('mcpStopResult', (data) => {
36+
const { serverId, success, error } = data;
37+
const ctx = app.createAnonymousContext();
38+
ctx.runInBackground(async () => {
39+
await ctx.service.mcp.handleMCPStopResult(serverId, success, error);
5940
});
41+
});
6042

61-
await Promise.all(startPromises);
62-
} catch (error) {
63-
app.logger.error('MCP服务启动过程中发生错误:', error);
64-
}
65-
}
66-
67-
/**
68-
* 构建MCP配置对象
69-
* @param {Object} server - 数据库中的服务器记录
70-
* @returns {Object} MCP配置对象
71-
*/
72-
buildMCPConfig(server) {
73-
const config = {
74-
transport: {
75-
type: server.transport
76-
}
77-
};
78-
79-
if (server.transport === 'stdio') {
80-
config.command = server.command;
81-
config.args = server.args || [];
82-
config.env = server.env || {};
83-
config.cwd = server.deploy_path; // 设置工作目录为部署路径
84-
} else if (server.transport === 'streamable-http') {
85-
config.httpUrl = server.http_url;
86-
} else if (server.transport === 'sse') {
87-
config.sseUrl = server.sse_url;
88-
}
89-
90-
return config;
91-
}
43+
// 监听 MCP 服务器重启结果
44+
app.messenger.on('mcpRestartResult', (data) => {
45+
const { serverId, success, error } = data;
46+
const ctx = app.createAnonymousContext();
47+
ctx.runInBackground(async () => {
48+
await ctx.service.mcp.handleMCPRestartResult(serverId, success, error);
49+
});
50+
});
9251

93-
/**
94-
* 应用关闭时的清理工作
95-
*/
96-
async beforeClose() {
97-
const { app } = this;
98-
99-
try {
100-
app.logger.info('开始清理MCP服务...');
101-
102-
// 获取MCP代理实例并清理
103-
const mcpProxy = MCPProxy.getInstance();
104-
await mcpProxy.cleanup();
105-
106-
// 销毁单例实例
107-
MCPProxy.destroyInstance();
108-
109-
app.logger.info('MCP服务清理完成');
110-
} catch (error) {
111-
app.logger.error('MCP服务清理过程中发生错误:', error);
112-
}
52+
// 监听 MCP 服务器健康检查请求
53+
app.messenger.on('mcpCheckAllServersHealth', () => {
54+
const ctx = app.createAnonymousContext();
55+
ctx.runInBackground(async () => {
56+
await ctx.service.mcp.checkAllServersHealth();
57+
});
58+
});
11359
}
11460
};

0 commit comments

Comments
 (0)