@atlisp/mcp 1.0.24 → 1.0.26
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/package.json +1 -1
- package/src/atlisp-mcp.js +60 -24
- package/src/cad-worker.js +16 -4
- package/src/constants.js +5 -1
- package/src/handlers/cad-handlers.js +19 -0
package/package.json
CHANGED
package/src/atlisp-mcp.js
CHANGED
|
@@ -75,16 +75,11 @@ const TOOL_HANDLERS = {
|
|
|
75
75
|
search_packages: (a) => packageHandlers.searchPackages(a.query),
|
|
76
76
|
install_package: (a) => packageHandlers.installPackage(a.packageName),
|
|
77
77
|
get_platform_info: () => ({ content: [{ type: 'text', text: `支持的 CAD 平台:\n${CAD_PLATFORMS.join('\n')}\n当前连接: ${cad.connected ? '已连接' : '未连接'}` }] }),
|
|
78
|
-
get_file_extensions: (a) => {
|
|
79
|
-
const exts = FILE_EXTENSIONS[a.platform];
|
|
80
|
-
if (!exts) return { content: [{ type: 'text', text: `错误: 不支持的平台 "${a.platform}"` }], isError: true };
|
|
81
|
-
return { content: [{ type: 'text', text: `${a.platform} 文件扩展名: ${exts.join(', ')}` }] };
|
|
82
|
-
},
|
|
83
|
-
get_install_code: () => ({ content: [{ type: 'text', text: `复制以下代码到 CAD 命令行安装 @lisp:\n\n(progn(vl-load-com)(setq s strcat h "http" o(vlax-create-object (s"win"h".win"h"request.5.1"))v vlax-invoke e eval r read)(v o'open "get" (s h"://atlisp.""cn/@"):vlax-true)(v o'send)(v o'WaitforResponse 1000)(e(r(vlax-get-property o'ResponseText))))` }] }),
|
|
84
78
|
at_command: (a) => cadHandlers.atCommand(a.command),
|
|
85
79
|
new_document: () => cadHandlers.newDocument(),
|
|
86
80
|
bring_to_front: () => cadHandlers.bringToFront(),
|
|
87
81
|
install_atlisp: () => cadHandlers.installAtlisp(),
|
|
82
|
+
init_atlisp: () => cadHandlers.initAtlisp(),
|
|
88
83
|
get_function_usage: (a) => functionHandlers.getFunctionUsage(a.name, a.package),
|
|
89
84
|
list_functions: (a) => functionHandlers.listFunctions(a.package),
|
|
90
85
|
};
|
|
@@ -149,20 +144,6 @@ export const tools = [
|
|
|
149
144
|
description: '获取 CAD 平台信息',
|
|
150
145
|
inputSchema: { type: 'object', properties: {} }
|
|
151
146
|
},
|
|
152
|
-
{
|
|
153
|
-
name: 'get_file_extensions',
|
|
154
|
-
description: '获取指定平台的文件扩展名',
|
|
155
|
-
inputSchema: {
|
|
156
|
-
type: 'object',
|
|
157
|
-
properties: { platform: { type: 'string', enum: CAD_PLATFORMS, description: 'CAD 平台' } },
|
|
158
|
-
required: ['platform']
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
name: 'get_install_code',
|
|
163
|
-
description: '获取 @lisp 安装代码',
|
|
164
|
-
inputSchema: { type: 'object', properties: {} }
|
|
165
|
-
},
|
|
166
147
|
{
|
|
167
148
|
name: 'at_command',
|
|
168
149
|
description: '执行 @lisp 命令',
|
|
@@ -187,6 +168,11 @@ export const tools = [
|
|
|
187
168
|
description: '在 CAD 中安装 @lisp',
|
|
188
169
|
inputSchema: { type: 'object', properties: {} }
|
|
189
170
|
},
|
|
171
|
+
{
|
|
172
|
+
name: 'init_atlisp',
|
|
173
|
+
description: '初始化 CAD 中的 @lisp 环境,加载函数库和初始变量',
|
|
174
|
+
inputSchema: { type: 'object', properties: {} }
|
|
175
|
+
},
|
|
190
176
|
{
|
|
191
177
|
name: 'get_function_usage',
|
|
192
178
|
description: '获取 @lisp 函数用法(从本地 JSON 库)',
|
|
@@ -247,7 +233,7 @@ async function initCadConnection() {
|
|
|
247
233
|
const connected = await cad.connect();
|
|
248
234
|
if (connected) {
|
|
249
235
|
log('Auto-connected to CAD: ' + cad.getPlatform() + ' ' + cad.getVersion());
|
|
250
|
-
console.
|
|
236
|
+
console.error('已自动连接到 CAD: ' + cad.getPlatform() + ' ' + cad.getVersion());
|
|
251
237
|
} else {
|
|
252
238
|
log('No CAD found on startup');
|
|
253
239
|
}
|
|
@@ -385,9 +371,9 @@ export async function startServer() {
|
|
|
385
371
|
if (config.transport === 'stdio') {
|
|
386
372
|
await initCadConnection();
|
|
387
373
|
const mcpServer = createMcpServer();
|
|
388
|
-
|
|
389
|
-
await mcpServer.connect(
|
|
390
|
-
console.
|
|
374
|
+
const transport = new StdioServerTransport();
|
|
375
|
+
await mcpServer.connect(transport);
|
|
376
|
+
console.error(`${SERVER_NAME} 运行在 stdio 模式`);
|
|
391
377
|
} else {
|
|
392
378
|
const app = express();
|
|
393
379
|
|
|
@@ -544,6 +530,56 @@ export async function startServer() {
|
|
|
544
530
|
});
|
|
545
531
|
}
|
|
546
532
|
|
|
533
|
+
app.post('/mcp/stream', mcpLimiter, async (req, res) => {
|
|
534
|
+
const body = req.body || {};
|
|
535
|
+
const { method, params, id } = body;
|
|
536
|
+
const accept = req.get('Accept') || '';
|
|
537
|
+
const wantsSse = accept.includes('text/event-stream');
|
|
538
|
+
const sessionId = req.get('mcp-session-id') || '';
|
|
539
|
+
log(`POST /mcp/stream - session: ${sessionId} - method: ${method} - wantsSSE: ${wantsSse}`);
|
|
540
|
+
|
|
541
|
+
if (wantsSse) {
|
|
542
|
+
if (!enableSse) {
|
|
543
|
+
res.status(400).json({ error: 'SSE mode is disabled' });
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const clientId = sessionId || crypto.randomUUID();
|
|
548
|
+
res.setHeader('mcp-session-id', clientId);
|
|
549
|
+
|
|
550
|
+
let session;
|
|
551
|
+
if (sessionId && sseSessionManager.has(sessionId)) {
|
|
552
|
+
session = sseSessionManager.get(sessionId);
|
|
553
|
+
if (!id) {
|
|
554
|
+
res.status(204).end();
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
await handleMcpRequest(session, method, params, id);
|
|
558
|
+
res.status(204).end();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
session = new SseSession(res, { clientId });
|
|
563
|
+
sseSessionManager.add(clientId, session);
|
|
564
|
+
|
|
565
|
+
if (!id) {
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
await handleMcpRequest(session, method, params, id);
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
res.setHeader('mcp-session-id', sessionId || crypto.randomUUID());
|
|
573
|
+
const { send } = createSseResponseHandler(res, wantsSse);
|
|
574
|
+
|
|
575
|
+
if (!id) return res.status(204).end();
|
|
576
|
+
|
|
577
|
+
await dispatchMcpMethod(
|
|
578
|
+
(response) => send(response, true),
|
|
579
|
+
method, params, id
|
|
580
|
+
);
|
|
581
|
+
});
|
|
582
|
+
|
|
547
583
|
app.get('/mcp', (req, res) => {
|
|
548
584
|
const accept = req.get('Accept') || '';
|
|
549
585
|
if (accept.includes('text/event-stream')) {
|
package/src/cad-worker.js
CHANGED
|
@@ -135,9 +135,16 @@ const cadSendWithResult = edge.func(function() {/*
|
|
|
135
135
|
tempFile = System.IO.Path.Combine(tempDir, "atlisp_result_" + System.Guid.NewGuid().ToString("N") + ".txt");
|
|
136
136
|
lispFile = System.IO.Path.Combine(tempDir, "atlisp_code_" + System.Guid.NewGuid().ToString("N") + ".lsp");
|
|
137
137
|
|
|
138
|
-
// 生成 LISP
|
|
139
|
-
//
|
|
140
|
-
string lispCode = "(progn
|
|
138
|
+
// 生成 LISP 代码:使用 vl-catch-all-apply 捕获结果和错误
|
|
139
|
+
// 返回 (success . result) 或 (nil . error-msg)
|
|
140
|
+
string lispCode = "(progn"
|
|
141
|
+
+ "(setq f(open \"" + tempFile.Replace("\\", "\\\\") + "\" \"w\"))"
|
|
142
|
+
+ "(setq r(vl-catch-all-apply '(lambda ()(progn " + code + "))))"
|
|
143
|
+
+ "(if (vl-catch-all-error-p r)"
|
|
144
|
+
+ "(princ(strcat \"ERROR:\"(vl-catch-all-error-message r)) f)"
|
|
145
|
+
+ "(princ r f))"
|
|
146
|
+
+ "(close f)"
|
|
147
|
+
+ "(princ))";
|
|
141
148
|
|
|
142
149
|
// 使用系统 ANSI 编码以兼容 GstarCAD / ZWCAD
|
|
143
150
|
System.IO.File.WriteAllText(lispFile, lispCode, System.Text.Encoding.GetEncoding(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ANSICodePage));
|
|
@@ -185,6 +192,11 @@ const cadSendWithResult = edge.func(function() {/*
|
|
|
185
192
|
|
|
186
193
|
result = enc.GetString(bytes).Trim();
|
|
187
194
|
|
|
195
|
+
// 检查是否有错误前缀
|
|
196
|
+
if (result.StartsWith("ERROR:")) {
|
|
197
|
+
return new { success = false, error = result.Substring(6).Trim() };
|
|
198
|
+
}
|
|
199
|
+
|
|
188
200
|
try { System.IO.File.Delete(tempFile); } catch {}
|
|
189
201
|
try { System.IO.File.Delete(lispFile); } catch {}
|
|
190
202
|
break;
|
|
@@ -334,7 +346,7 @@ async function waitForIdle(platform) {
|
|
|
334
346
|
return false;
|
|
335
347
|
}
|
|
336
348
|
|
|
337
|
-
function checkParens(code) {
|
|
349
|
+
export function checkParens(code) {
|
|
338
350
|
let depth = 0;
|
|
339
351
|
let inString = false;
|
|
340
352
|
for (let i = 0; i < code.length; i++) {
|
package/src/constants.js
CHANGED
|
@@ -8,7 +8,11 @@ export const FILE_EXTENSIONS = {
|
|
|
8
8
|
|
|
9
9
|
export const PROTOCOL_VERSION = '2024-11-05';
|
|
10
10
|
export const SERVER_NAME = 'atlisp-mcp-server';
|
|
11
|
-
|
|
11
|
+
<<<<<<< HEAD
|
|
12
|
+
export const SERVER_VERSION = '1.0.25';
|
|
13
|
+
=======
|
|
14
|
+
export const SERVER_VERSION = '1.0.22';
|
|
15
|
+
>>>>>>> 0627854 (chore: 升级 mcp-server 版本到 1.0.22)
|
|
12
16
|
|
|
13
17
|
export const MOCK_PACKAGES = [
|
|
14
18
|
{ name: 'base', description: '基础函数库', version: '1.0.0' },
|
|
@@ -77,3 +77,22 @@ export async function installAtlisp() {
|
|
|
77
77
|
await cad.sendCommand(installCode + '\n');
|
|
78
78
|
return { content: [{ type: 'text', text: '已发送 @lisp 安装代码到 CAD' }] };
|
|
79
79
|
}
|
|
80
|
+
|
|
81
|
+
export async function initAtlisp() {
|
|
82
|
+
if (!cad.connected) { await cad.connect(); }
|
|
83
|
+
if (!cad.connected) return { content: [{ type: 'text', text: '未连接 CAD' }], isError: true };
|
|
84
|
+
const code = `(if (null @::load-module)
|
|
85
|
+
(progn
|
|
86
|
+
(vl-load-com)
|
|
87
|
+
(setq s strcat h"http"o(vlax-create-object (s"win"h".win"h"request.5.1"))
|
|
88
|
+
v vlax-invoke e eval r read)(v o'open "get" (s h"://""atlisp.""cn/cloud"):vlax-true)
|
|
89
|
+
(v o'send)
|
|
90
|
+
(v o'WaitforResponse 1000)
|
|
91
|
+
(e(r(vlax-get o'ResponseText)))))`;
|
|
92
|
+
try {
|
|
93
|
+
await cad.sendCommand(code + '\n');
|
|
94
|
+
return { content: [{ type: 'text', text: '已发送 @lisp 函数库加载代码到 CAD' }] };
|
|
95
|
+
} catch (e) {
|
|
96
|
+
return { content: [{ type: 'text', text: `错误: ${e.message}` }], isError: true };
|
|
97
|
+
}
|
|
98
|
+
}
|