@atlisp/mcp 1.8.5 → 1.8.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/dist/atlisp-mcp.js +11307 -5946
- package/dist/cad-worker.js +65 -8
- package/package.json +60 -55
package/dist/cad-worker.js
CHANGED
|
@@ -3,10 +3,31 @@ import edge from 'edge-js';
|
|
|
3
3
|
import process from 'process';
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import path from 'path';
|
|
6
|
+
import crypto from 'crypto';
|
|
6
7
|
|
|
7
8
|
const BUSY_RETRIES = parseInt(process.env.BUSY_RETRIES || '10', 10);
|
|
8
9
|
const BUSY_DELAY = parseInt(process.env.BUSY_DELAY || '500', 10);
|
|
9
10
|
|
|
11
|
+
// Lisp expression cache (hash -> compiled Lisp code)
|
|
12
|
+
const LISP_CACHE = new Map();
|
|
13
|
+
const LISP_CACHE_MAX = parseInt(process.env.LISP_CACHE_MAX || '500', 10);
|
|
14
|
+
|
|
15
|
+
function getCachedLisp(code) {
|
|
16
|
+
const hash = crypto.createHash('sha256').update(code).digest('hex');
|
|
17
|
+
if (LISP_CACHE.has(hash)) return LISP_CACHE.get(hash);
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function setCachedLisp(code, compiled) {
|
|
22
|
+
const hash = crypto.createHash('sha256').update(code).digest('hex');
|
|
23
|
+
if (LISP_CACHE.size >= LISP_CACHE_MAX) {
|
|
24
|
+
const firstKey = LISP_CACHE.keys().next().value;
|
|
25
|
+
LISP_CACHE.delete(firstKey);
|
|
26
|
+
}
|
|
27
|
+
LISP_CACHE.set(hash, compiled);
|
|
28
|
+
return compiled;
|
|
29
|
+
}
|
|
30
|
+
|
|
10
31
|
const DEBUG_FILE = process.env.DEBUG_FILE || path.join(process.env.TEMP || '/tmp', 'cad-worker-debug.log');
|
|
11
32
|
|
|
12
33
|
function log(msg) {
|
|
@@ -107,10 +128,9 @@ string code = d.code.ToString();
|
|
|
107
128
|
dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progId);
|
|
108
129
|
if (cad != null) {
|
|
109
130
|
dynamic doc = cad.ActiveDocument;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
return new { success = true };
|
|
131
|
+
if (doc != null) {
|
|
132
|
+
doc.SendCommand(code);
|
|
133
|
+
return new { success = true };
|
|
114
134
|
}
|
|
115
135
|
}
|
|
116
136
|
} catch (Exception ex) {
|
|
@@ -156,10 +176,8 @@ string encoding = d.encoding != null ? d.encoding.ToString() : "";
|
|
|
156
176
|
dynamic cad = System.Runtime.InteropServices.Marshal.GetActiveObject(progId);
|
|
157
177
|
if (cad != null) {
|
|
158
178
|
dynamic doc = cad.ActiveDocument;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
// 加载 .lsp 文件执行
|
|
162
|
-
doc.SendCommand("(load \"" + lispFile.Replace("\\", "\\\\") + "\")\n");
|
|
179
|
+
if (doc != null) {
|
|
180
|
+
doc.SendCommand("(load \"" + lispFile.Replace("\\", "\\\\") + "\")\n");
|
|
163
181
|
|
|
164
182
|
int retries = 10;
|
|
165
183
|
string result = "";
|
|
@@ -452,6 +470,37 @@ async function waitForIdle(platform) {
|
|
|
452
470
|
return false;
|
|
453
471
|
}
|
|
454
472
|
|
|
473
|
+
const DANGEROUS_PATTERNS = [
|
|
474
|
+
{ re: /\beval\s*[(\s]/i, msg: '禁止使用 eval 函数' },
|
|
475
|
+
{ re: /\bload\s*[(\s"]/i, msg: '禁止使用 load 函数' },
|
|
476
|
+
{ re: /\bstartapp\s*[(\s]/i, msg: '禁止使用 startapp 函数' },
|
|
477
|
+
{ re: /\bvl-bt\b/i, msg: '禁止使用 vl-bt 函数' },
|
|
478
|
+
{ re: /\bvl-exit-with-value\b/i, msg: '禁止使用 vl-exit-with-value' },
|
|
479
|
+
{ re: /\bvl-exit-with-error\b/i, msg: '禁止使用 vl-exit-with-error' },
|
|
480
|
+
{ re: /\bvlax-import-type-library\b/i, msg: '禁止导入类型库' },
|
|
481
|
+
{ re: /\bvlax-add-cmd\b/i, msg: '禁止注册新命令' },
|
|
482
|
+
{ re: /\bvla-Delete\b/i, msg: '禁止直接删除 vla 对象' },
|
|
483
|
+
{ re: /\bvla-Save\b/i, msg: '禁止直接保存文档' },
|
|
484
|
+
{ re: /\bcommand\s*["\s]*[_(]?\s*["']?\.?\s*_?(?:quit|exit|close|open|new|recover|audit|purge|wblock|export)/i, msg: '禁止使用危险 CAD 命令' },
|
|
485
|
+
{ re: /\bdirectory\s*[(\s]/i, msg: '禁止使用 directory 函数' },
|
|
486
|
+
{ re: /\b(?:read-line|read-char|write-line|write-char)\s*[(\s]/i, msg: '禁止直接文件 I/O' },
|
|
487
|
+
{ re: /\bvla-deletefile\b/i, msg: '禁止删除文件' },
|
|
488
|
+
{ re: /\bvla-copyfile\b/i, msg: '禁止复制文件' },
|
|
489
|
+
{ re: /\bvla-movefile\b/i, msg: '禁止移动文件' },
|
|
490
|
+
{ re: /\bdos_command_string\s*[(\s]/i, msg: '禁止使用 dos_command_string' },
|
|
491
|
+
];
|
|
492
|
+
|
|
493
|
+
function validateLispCode(code) {
|
|
494
|
+
const withoutStrings = code.replace(/"([^"\\]*(?:\\.[^"\\]*)*)"/g, '');
|
|
495
|
+
const withoutComments = withoutStrings.replace(/;.*$/gm, '');
|
|
496
|
+
for (const { re, msg } of DANGEROUS_PATTERNS) {
|
|
497
|
+
if (re.test(withoutComments)) {
|
|
498
|
+
return { valid: false, error: msg };
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return { valid: true };
|
|
502
|
+
}
|
|
503
|
+
|
|
455
504
|
export function checkParens(code) {
|
|
456
505
|
let depth = 0;
|
|
457
506
|
let inString = false;
|
|
@@ -557,6 +606,10 @@ async function handleMessage(msg) {
|
|
|
557
606
|
if (!parenCheck.valid) {
|
|
558
607
|
return { success: false, error: `括号错误: ${parenCheck.error} (位置 ${parenCheck.pos})` };
|
|
559
608
|
}
|
|
609
|
+
const injectionCheck = validateLispCode(msg.code);
|
|
610
|
+
if (!injectionCheck.valid) {
|
|
611
|
+
return { success: false, error: `安全限制: ${injectionCheck.error}` };
|
|
612
|
+
}
|
|
560
613
|
if (msg.code.length > 255) {
|
|
561
614
|
log(`send (long code ${msg.code.length} chars, fallback to sendResult): ${msg.code.substring(0, 80)}...`);
|
|
562
615
|
const r = await new Promise((resolve, reject) => {
|
|
@@ -606,6 +659,10 @@ async function handleMessage(msg) {
|
|
|
606
659
|
if (!parenCheck.valid) {
|
|
607
660
|
return { success: false, error: `括号错误: ${parenCheck.error} (位置 ${parenCheck.pos})` };
|
|
608
661
|
}
|
|
662
|
+
const injectionCheck = validateLispCode(msg.code);
|
|
663
|
+
if (!injectionCheck.valid) {
|
|
664
|
+
return { success: false, error: `安全限制: ${injectionCheck.error}` };
|
|
665
|
+
}
|
|
609
666
|
const maxRetriesResult = 3;
|
|
610
667
|
let lastErrorResult = null;
|
|
611
668
|
for (let i = 0; i < maxRetriesResult; i++) {
|
package/package.json
CHANGED
|
@@ -1,57 +1,62 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
2
|
+
"name": "@atlisp/mcp",
|
|
3
|
+
"version": "1.8.8",
|
|
4
|
+
"description": "MCP Server for @lisp on CAD,support AutoCAD/GstarCAD/ZWCAD/BricsCAD or CAD platform compatible with AutoLISP",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"atlisp-mcp": "./dist/atlisp-mcp.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/atlisp-mcp.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./dist/atlisp-mcp.js",
|
|
12
|
+
"./cad": "./dist/atlisp-mcp.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"start": "node src/atlisp-mcp.js",
|
|
19
|
+
"build": "npm run build:main && npm run build:worker",
|
|
20
|
+
"build:main": "esbuild src/atlisp-mcp.js --bundle --platform=node --target=node18 --format=esm --outdir=dist --external:edge-js --packages=external --banner:js=\"#!/usr/bin/env node\"",
|
|
21
|
+
"build:worker": "node -e \"require('fs').copyFileSync('src/cad-worker.js','dist/cad-worker.js')\"",
|
|
22
|
+
"prepublishOnly": "npm run build",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"mcp",
|
|
28
|
+
"atlisp",
|
|
29
|
+
"cad",
|
|
30
|
+
"autolisp",
|
|
31
|
+
"package-manager"
|
|
32
|
+
],
|
|
33
|
+
"author": "vitalgg",
|
|
34
|
+
"license": "ISC",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://gitee.com/atlisp/atlisp-kernel.git"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://gitee.com/atlisp",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://gitee.com/organizations/atlisp/issues"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
45
|
+
"@opentelemetry/api": "^1.9.1",
|
|
46
|
+
"@opentelemetry/exporter-prometheus": "^0.218.0",
|
|
47
|
+
"@opentelemetry/instrumentation-http": "^0.218.0",
|
|
48
|
+
"@opentelemetry/sdk-metrics": "^2.7.1",
|
|
49
|
+
"edge-js": "^25.0.1",
|
|
50
|
+
"express": "^5.2.1",
|
|
51
|
+
"iconv-lite": "^0.6.3",
|
|
52
|
+
"ws": "^8.21.0",
|
|
53
|
+
"zod": "^3.24.0"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=18.0.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"esbuild": "^0.28.0",
|
|
60
|
+
"vitest": "^4.1.5"
|
|
61
|
+
}
|
|
57
62
|
}
|