@xfe-repo/cli-plugin-ai-mcp 2.0.6 → 2.0.8
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/CHANGELOG.md +18 -0
- package/README.md +1 -0
- package/dist/index.js +3 -3
- package/dist/server.js +91 -6
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @xfe-repo/cli-plugin-ai-mcp
|
|
2
2
|
|
|
3
|
+
## 2.0.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 新增deploy自动部署支持
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @xfe-repo/cli-core@2.1.0
|
|
10
|
+
- @xfe-repo/cli-plugin-ai-rules@2.0.8
|
|
11
|
+
|
|
12
|
+
## 2.0.7
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 修复窗口高度计算问题
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @xfe-repo/cli-plugin-ai-rules@2.0.7
|
|
19
|
+
- @xfe-repo/cli-core@2.0.8
|
|
20
|
+
|
|
3
21
|
## 2.0.6
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -32,14 +32,14 @@ export function aiMcpPlugin() {
|
|
|
32
32
|
label: 'MCP',
|
|
33
33
|
icon: '⬡',
|
|
34
34
|
color: 'blue',
|
|
35
|
-
slot: '
|
|
35
|
+
slot: 'header',
|
|
36
36
|
value: (state) => {
|
|
37
37
|
const mcp = state['ai-mcp'];
|
|
38
38
|
if (!mcp || mcp.status === 'off')
|
|
39
39
|
return undefined;
|
|
40
40
|
if (mcp.status === 'error')
|
|
41
41
|
return '异常';
|
|
42
|
-
return
|
|
42
|
+
return `${mcp.port}`;
|
|
43
43
|
},
|
|
44
44
|
url: (state) => {
|
|
45
45
|
const mcp = state['ai-mcp'];
|
|
@@ -151,7 +151,7 @@ function buildMcpInjectionItems(config) {
|
|
|
151
151
|
'## XFE 项目脚手架 (重要!!!)',
|
|
152
152
|
'',
|
|
153
153
|
'- 对于项目运行、构建、错误检查、环境切换,优先使用 `xfe-cli-mcp` 提供的工具,不要直接运行 pnpm、npm、yarn 等脚本命令。',
|
|
154
|
-
'-
|
|
154
|
+
'- MCP 命令可能直接返回 completed/error 结果;当返回 status 为 running 时,必须使用 xfe-get-session-logs 基于 sessionId 轮询日志和状态。',
|
|
155
155
|
'- 除非用户明确要求停止任务,否则不要调用 xfe-kill-session 终止已有的开发任务。',
|
|
156
156
|
'- 项目错误、编译日志获取优先顺序是:`xfe-cli-mcp` dev session log > IDE TypeScript/ESLint 报错 > 相关模块代码链路',
|
|
157
157
|
].join('\n');
|
package/dist/server.js
CHANGED
|
@@ -11,11 +11,16 @@ import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/
|
|
|
11
11
|
import { Hono } from 'hono';
|
|
12
12
|
import { cors } from 'hono/cors';
|
|
13
13
|
import { z } from 'zod';
|
|
14
|
+
import { CommandExecutionMode } from '@xfe-repo/cli-core';
|
|
14
15
|
import { MemoryLogger, AutoPrompt, LogSpinner } from './adapters.js';
|
|
15
16
|
const MCP_SERVER_INFO = { name: 'xfe-cli', version: '2.0.0' };
|
|
16
17
|
const LIST_SESSIONS_TOOL_NAME = 'xfe-list-sessions';
|
|
17
18
|
const GET_SESSION_LOGS_TOOL_NAME = 'xfe-get-session-logs';
|
|
18
19
|
const KILL_SESSION_TOOL_NAME = 'xfe-kill-session';
|
|
20
|
+
const PERSISTENT_COMMAND_NAMES = new Set(['dev']);
|
|
21
|
+
const JSON_RPC_VERSION = '2.0';
|
|
22
|
+
const MCP_BAD_REQUEST_ERROR_CODE = -32000;
|
|
23
|
+
const MCP_SESSION_NOT_FOUND_ERROR_CODE = -32001;
|
|
19
24
|
// ─── Public API ────────────────────────────────────────────
|
|
20
25
|
export async function startMcpServer(ctx, port) {
|
|
21
26
|
const sessions = new Map();
|
|
@@ -72,14 +77,14 @@ function createHttpApp(ctx, sessions) {
|
|
|
72
77
|
app.get('/mcp', async (c) => {
|
|
73
78
|
const sessionId = c.req.header('mcp-session-id');
|
|
74
79
|
if (!sessionId || !sessions.has(sessionId)) {
|
|
75
|
-
return c
|
|
80
|
+
return mcpSessionErrorResponse(c, sessionId);
|
|
76
81
|
}
|
|
77
82
|
return sessions.get(sessionId).transport.handleRequest(c.req.raw);
|
|
78
83
|
});
|
|
79
84
|
app.on('DELETE', '/mcp', async (c) => {
|
|
80
85
|
const sessionId = c.req.header('mcp-session-id');
|
|
81
86
|
if (!sessionId || !sessions.has(sessionId)) {
|
|
82
|
-
return c
|
|
87
|
+
return mcpSessionErrorResponse(c, sessionId);
|
|
83
88
|
}
|
|
84
89
|
return sessions.get(sessionId).transport.handleRequest(c.req.raw);
|
|
85
90
|
});
|
|
@@ -158,8 +163,9 @@ function registerSingleCommandTool(mcpServer, ctx, command, pluginName) {
|
|
|
158
163
|
}
|
|
159
164
|
mcpServer.registerTool(toolName, toolConfig, (params) => executeCommandAsTool(ctx, command, params));
|
|
160
165
|
}
|
|
161
|
-
function executeCommandAsTool(ctx, command, params) {
|
|
166
|
+
async function executeCommandAsTool(ctx, command, params) {
|
|
162
167
|
const logger = new MemoryLogger();
|
|
168
|
+
const executionMode = resolveCommandExecutionMode(command, params);
|
|
163
169
|
const sessionId = ctx.sessions.createSession({
|
|
164
170
|
commandName: command.name,
|
|
165
171
|
source: 'mcp',
|
|
@@ -168,15 +174,21 @@ function executeCommandAsTool(ctx, command, params) {
|
|
|
168
174
|
createSpinner: () => new LogSpinner(logger),
|
|
169
175
|
prefilled: params,
|
|
170
176
|
});
|
|
177
|
+
if (executionMode === CommandExecutionMode.Sync) {
|
|
178
|
+
await waitForSessionSettled(ctx, sessionId);
|
|
179
|
+
const logResult = ctx.sessions.getSessionLogs(sessionId);
|
|
180
|
+
return mcpResult(buildCompletedCommandResult({ commandName: command.name, executionMode, logResult, sessionId }));
|
|
181
|
+
}
|
|
171
182
|
return mcpResult({
|
|
172
183
|
sessionId,
|
|
173
184
|
command: command.name,
|
|
174
185
|
status: 'running',
|
|
175
186
|
source: 'mcp',
|
|
187
|
+
executionMode,
|
|
176
188
|
logTool: GET_SESSION_LOGS_TOOL_NAME,
|
|
177
189
|
listSessionsTool: LIST_SESSIONS_TOOL_NAME,
|
|
178
190
|
killSessionTool: KILL_SESSION_TOOL_NAME,
|
|
179
|
-
message:
|
|
191
|
+
message: buildRunningCommandMessage(command.name, executionMode),
|
|
180
192
|
});
|
|
181
193
|
}
|
|
182
194
|
function mcpResult(data) {
|
|
@@ -190,8 +202,8 @@ function buildCommandToolDescription(command, pluginName) {
|
|
|
190
202
|
const lines = [
|
|
191
203
|
`[来源插件: ${pluginName}]`,
|
|
192
204
|
command.description ?? command.simpleDescription,
|
|
193
|
-
'
|
|
194
|
-
|
|
205
|
+
'调用该工具会创建一个新的 xfe session。同步任务会在命令完成后直接返回日志结果;异步或持续任务会立即返回 sessionId。',
|
|
206
|
+
`当返回 status 为 running 时,请使用 ${GET_SESSION_LOGS_TOOL_NAME} 轮询日志;如需确认是否已有可复用任务,先使用 ${LIST_SESSIONS_TOOL_NAME}。`,
|
|
195
207
|
];
|
|
196
208
|
if (command.parameters) {
|
|
197
209
|
lines.push('若命令可能触发交互,请在本次调用中一次性传入所有相关参数。');
|
|
@@ -201,4 +213,77 @@ function buildCommandToolDescription(command, pluginName) {
|
|
|
201
213
|
function resolveSession(ctx, sessionId) {
|
|
202
214
|
return ctx.sessions.getSession(sessionId);
|
|
203
215
|
}
|
|
216
|
+
function mcpSessionErrorResponse(c, sessionId) {
|
|
217
|
+
if (sessionId) {
|
|
218
|
+
return c.json(createJsonRpcError(MCP_SESSION_NOT_FOUND_ERROR_CODE, 'Session not found'), 404);
|
|
219
|
+
}
|
|
220
|
+
return c.json(createJsonRpcError(MCP_BAD_REQUEST_ERROR_CODE, 'Bad Request: Mcp-Session-Id header is required'), 400);
|
|
221
|
+
}
|
|
222
|
+
function createJsonRpcError(code, message) {
|
|
223
|
+
return {
|
|
224
|
+
jsonrpc: JSON_RPC_VERSION,
|
|
225
|
+
error: { code, message },
|
|
226
|
+
id: null,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function resolveCommandExecutionMode(command, params) {
|
|
230
|
+
if (typeof command.execMode === 'function') {
|
|
231
|
+
return command.execMode(params);
|
|
232
|
+
}
|
|
233
|
+
if (command.execMode)
|
|
234
|
+
return command.execMode;
|
|
235
|
+
if (PERSISTENT_COMMAND_NAMES.has(command.name))
|
|
236
|
+
return CommandExecutionMode.Persistent;
|
|
237
|
+
return CommandExecutionMode.Sync;
|
|
238
|
+
}
|
|
239
|
+
function waitForSessionSettled(ctx, sessionId) {
|
|
240
|
+
const session = ctx.sessions.getSession(sessionId);
|
|
241
|
+
if (!session || session.status !== 'running')
|
|
242
|
+
return Promise.resolve();
|
|
243
|
+
return new Promise((resolve) => {
|
|
244
|
+
let unsubscribe = () => { };
|
|
245
|
+
const completeIfSettled = () => {
|
|
246
|
+
const currentSession = ctx.sessions.getSession(sessionId);
|
|
247
|
+
if (currentSession?.status === 'running')
|
|
248
|
+
return;
|
|
249
|
+
unsubscribe();
|
|
250
|
+
resolve();
|
|
251
|
+
};
|
|
252
|
+
unsubscribe = ctx.sessions.subscribe(completeIfSettled);
|
|
253
|
+
completeIfSettled();
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
function buildCompletedCommandResult(options) {
|
|
257
|
+
const { commandName, executionMode, sessionId, logResult } = options;
|
|
258
|
+
const status = logResult?.status ?? 'completed';
|
|
259
|
+
return {
|
|
260
|
+
sessionId,
|
|
261
|
+
command: commandName,
|
|
262
|
+
status,
|
|
263
|
+
source: 'mcp',
|
|
264
|
+
executionMode,
|
|
265
|
+
logs: logResult?.logs ?? [],
|
|
266
|
+
totalLines: logResult?.totalLines ?? 0,
|
|
267
|
+
hasMore: logResult?.hasMore ?? false,
|
|
268
|
+
logTool: GET_SESSION_LOGS_TOOL_NAME,
|
|
269
|
+
listSessionsTool: LIST_SESSIONS_TOOL_NAME,
|
|
270
|
+
message: buildCompletedCommandMessage(commandName, status),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
function buildCompletedCommandMessage(commandName, status) {
|
|
274
|
+
if (status === 'error')
|
|
275
|
+
return `命令 "${commandName}" 执行失败,错误日志已随本次响应返回。`;
|
|
276
|
+
return `命令 "${commandName}" 已完成,结果已随本次响应返回。`;
|
|
277
|
+
}
|
|
278
|
+
function buildRunningCommandMessage(commandName, mode) {
|
|
279
|
+
const modeName = formatExecutionMode(mode);
|
|
280
|
+
return `命令 "${commandName}" 已启动。该任务为${modeName},请使用 ${GET_SESSION_LOGS_TOOL_NAME} 基于 sessionId 拉取日志。`;
|
|
281
|
+
}
|
|
282
|
+
function formatExecutionMode(mode) {
|
|
283
|
+
if (mode === CommandExecutionMode.Persistent)
|
|
284
|
+
return '持续任务';
|
|
285
|
+
if (mode === CommandExecutionMode.Async)
|
|
286
|
+
return '异步任务';
|
|
287
|
+
return '同步任务';
|
|
288
|
+
}
|
|
204
289
|
//# sourceMappingURL=server.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xfe-repo/cli-plugin-ai-mcp",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.8",
|
|
4
4
|
"description": "XFE CLI MCP Server 插件 —— 将 CLI 命令暴露为 MCP Tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"get-port": "^7.1.0",
|
|
12
12
|
"hono": "^4.7.0",
|
|
13
13
|
"zod": "^4.3.6",
|
|
14
|
-
"@xfe-repo/cli-core": "2.0
|
|
15
|
-
"@xfe-repo/cli-plugin-ai-rules": "2.0.
|
|
14
|
+
"@xfe-repo/cli-core": "2.1.0",
|
|
15
|
+
"@xfe-repo/cli-plugin-ai-rules": "2.0.8"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@types/node": "^24.3.0",
|