@atlisp/mcp 1.3.7 → 1.4.0
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 +267 -81
- package/package.json +1 -1
package/dist/atlisp-mcp.js
CHANGED
|
@@ -34,7 +34,8 @@ var SessionTransport = class {
|
|
|
34
34
|
this._started = true;
|
|
35
35
|
}
|
|
36
36
|
async send(message) {
|
|
37
|
-
if (this._closed)
|
|
37
|
+
if (this._closed)
|
|
38
|
+
return;
|
|
38
39
|
if (this._pendingRequest) {
|
|
39
40
|
const { resolve, reject, timeout } = this._pendingRequest;
|
|
40
41
|
clearTimeout(timeout);
|
|
@@ -43,7 +44,8 @@ var SessionTransport = class {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
async close() {
|
|
46
|
-
if (this._closed)
|
|
47
|
+
if (this._closed)
|
|
48
|
+
return;
|
|
47
49
|
this._closed = true;
|
|
48
50
|
if (this._pendingRequest) {
|
|
49
51
|
const { reject, timeout } = this._pendingRequest;
|
|
@@ -117,7 +119,7 @@ var FILE_EXTENSIONS = {
|
|
|
117
119
|
"BricsCAD": [".des"]
|
|
118
120
|
};
|
|
119
121
|
var SERVER_NAME = "atlisp-mcp-server";
|
|
120
|
-
var SERVER_VERSION = "1.
|
|
122
|
+
var SERVER_VERSION = "1.4.0";
|
|
121
123
|
var MOCK_PACKAGES = [
|
|
122
124
|
{ name: "base", description: "\u57FA\u7840\u51FD\u6570\u5E93", version: "1.0.0" },
|
|
123
125
|
{ name: "at-pm", description: "\u5DE5\u7A0B\u9879\u76EE\u7BA1\u7406", version: "2.1.0" },
|
|
@@ -210,7 +212,8 @@ function setupStdoutHandler(w) {
|
|
|
210
212
|
const lines = buffer.split("\n");
|
|
211
213
|
buffer = lines.pop() || "";
|
|
212
214
|
for (const line of lines) {
|
|
213
|
-
if (!line.trim())
|
|
215
|
+
if (!line.trim())
|
|
216
|
+
continue;
|
|
214
217
|
try {
|
|
215
218
|
const result = JSON.parse(line);
|
|
216
219
|
const rid = result.requestId;
|
|
@@ -235,7 +238,8 @@ function setupStdoutHandler(w) {
|
|
|
235
238
|
}
|
|
236
239
|
function getWorker() {
|
|
237
240
|
if (!worker || !worker.connected) {
|
|
238
|
-
if (worker)
|
|
241
|
+
if (worker)
|
|
242
|
+
worker.kill();
|
|
239
243
|
worker = spawn("node", [workerPath], {
|
|
240
244
|
stdio: ["pipe", "pipe", "pipe"]
|
|
241
245
|
});
|
|
@@ -244,7 +248,8 @@ function getWorker() {
|
|
|
244
248
|
const w = worker;
|
|
245
249
|
w.on("exit", (code) => {
|
|
246
250
|
console.error("worker exited:", code);
|
|
247
|
-
if (w !== worker)
|
|
251
|
+
if (w !== worker)
|
|
252
|
+
return;
|
|
248
253
|
w.connected = false;
|
|
249
254
|
for (const [id, { reject, timeout }] of pendingRequests) {
|
|
250
255
|
clearTimeout(timeout);
|
|
@@ -263,7 +268,8 @@ function getWorker() {
|
|
|
263
268
|
return worker;
|
|
264
269
|
}
|
|
265
270
|
function startHeartbeat() {
|
|
266
|
-
if (heartbeatTimer)
|
|
271
|
+
if (heartbeatTimer)
|
|
272
|
+
clearInterval(heartbeatTimer);
|
|
267
273
|
heartbeatTimer = setInterval(async () => {
|
|
268
274
|
try {
|
|
269
275
|
const result = await sendMessage({ type: "ping" });
|
|
@@ -308,7 +314,8 @@ var CadConnection = class {
|
|
|
308
314
|
return process.platform === "win32";
|
|
309
315
|
}
|
|
310
316
|
async connect() {
|
|
311
|
-
if (!this.isAvailable())
|
|
317
|
+
if (!this.isAvailable())
|
|
318
|
+
return false;
|
|
312
319
|
try {
|
|
313
320
|
const result = await sendMessage({ type: "connect" });
|
|
314
321
|
if (result && result.success) {
|
|
@@ -324,13 +331,16 @@ var CadConnection = class {
|
|
|
324
331
|
return false;
|
|
325
332
|
}
|
|
326
333
|
async sendCommand(code) {
|
|
327
|
-
if (!this.connected)
|
|
334
|
+
if (!this.connected)
|
|
335
|
+
throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
328
336
|
const result = await sendMessage({ type: "send", code, platform: _platform });
|
|
329
|
-
if (result.success)
|
|
337
|
+
if (result.success)
|
|
338
|
+
return true;
|
|
330
339
|
throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
|
|
331
340
|
}
|
|
332
341
|
async sendCommandWithResult(code, encoding = null) {
|
|
333
|
-
if (!this.connected)
|
|
342
|
+
if (!this.connected)
|
|
343
|
+
throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
334
344
|
const result = await sendMessage({ type: "sendResult", code, platform: _platform, encoding: encoding || "" });
|
|
335
345
|
if (result.success) {
|
|
336
346
|
return result.result || "";
|
|
@@ -344,7 +354,8 @@ var CadConnection = class {
|
|
|
344
354
|
return this.product;
|
|
345
355
|
}
|
|
346
356
|
async isBusy() {
|
|
347
|
-
if (!this.connected)
|
|
357
|
+
if (!this.connected)
|
|
358
|
+
return false;
|
|
348
359
|
try {
|
|
349
360
|
const result = await sendMessage({ type: "isBusy", platform: _platform });
|
|
350
361
|
return result && result.isBusy;
|
|
@@ -353,7 +364,8 @@ var CadConnection = class {
|
|
|
353
364
|
}
|
|
354
365
|
}
|
|
355
366
|
async hasDoc() {
|
|
356
|
-
if (!this.connected)
|
|
367
|
+
if (!this.connected)
|
|
368
|
+
return { hasDoc: false, docCount: 0 };
|
|
357
369
|
try {
|
|
358
370
|
const result = await sendMessage({ type: "hasdoc", platform: _platform });
|
|
359
371
|
return result || { hasDoc: false, docCount: 0 };
|
|
@@ -362,7 +374,8 @@ var CadConnection = class {
|
|
|
362
374
|
}
|
|
363
375
|
}
|
|
364
376
|
async newDoc() {
|
|
365
|
-
if (!this.connected)
|
|
377
|
+
if (!this.connected)
|
|
378
|
+
throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
366
379
|
try {
|
|
367
380
|
const result = await sendMessage({ type: "newdoc", platform: _platform });
|
|
368
381
|
return result && result.success;
|
|
@@ -371,7 +384,8 @@ var CadConnection = class {
|
|
|
371
384
|
}
|
|
372
385
|
}
|
|
373
386
|
async bringToFront() {
|
|
374
|
-
if (!this.connected)
|
|
387
|
+
if (!this.connected)
|
|
388
|
+
throw new Error("\u672A\u8FDE\u63A5 CAD");
|
|
375
389
|
try {
|
|
376
390
|
const result = await sendMessage({ type: "bringToFront", platform: _platform });
|
|
377
391
|
return result && result.success;
|
|
@@ -380,7 +394,8 @@ var CadConnection = class {
|
|
|
380
394
|
}
|
|
381
395
|
}
|
|
382
396
|
async getInfo() {
|
|
383
|
-
if (!this.connected)
|
|
397
|
+
if (!this.connected)
|
|
398
|
+
return "CAD \u672A\u8FDE\u63A5";
|
|
384
399
|
return `Platform: ${this.product}, Version: ${this.version}, Status: Connected`;
|
|
385
400
|
}
|
|
386
401
|
async disconnect() {
|
|
@@ -455,7 +470,8 @@ async function evalLisp(code, withResult = false, encoding = null) {
|
|
|
455
470
|
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
456
471
|
}
|
|
457
472
|
const trimmed = (code || "").trim();
|
|
458
|
-
if (!trimmed)
|
|
473
|
+
if (!trimmed)
|
|
474
|
+
return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
|
|
459
475
|
try {
|
|
460
476
|
if (withResult) {
|
|
461
477
|
const result = await cad.sendCommandWithResult(trimmed, encoding);
|
|
@@ -475,14 +491,17 @@ async function getCadInfo() {
|
|
|
475
491
|
if (!cad.connected) {
|
|
476
492
|
await cad.connect();
|
|
477
493
|
}
|
|
478
|
-
if (!cad.connected)
|
|
494
|
+
if (!cad.connected)
|
|
495
|
+
return { content: [{ type: "text", text: "CAD \u672A\u8FDE\u63A5" }] };
|
|
479
496
|
const info = await cad.getInfo();
|
|
480
497
|
return { content: [{ type: "text", text: info }] };
|
|
481
498
|
}
|
|
482
499
|
async function atCommand(command) {
|
|
483
|
-
if (!cad.connected)
|
|
500
|
+
if (!cad.connected)
|
|
501
|
+
return { content: [{ type: "text", text: "\u8BF7\u5148\u8FDE\u63A5 CAD" }], isError: true };
|
|
484
502
|
const trimmed = (command || "").trim();
|
|
485
|
-
if (!trimmed)
|
|
503
|
+
if (!trimmed)
|
|
504
|
+
return { content: [{ type: "text", text: "\u547D\u4EE4\u4E3A\u7A7A\uFF0C\u672A\u53D1\u9001" }] };
|
|
486
505
|
await cad.sendCommand(trimmed + "\n");
|
|
487
506
|
return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001\u547D\u4EE4" }] };
|
|
488
507
|
}
|
|
@@ -490,7 +509,8 @@ async function newDocument() {
|
|
|
490
509
|
if (!cad.connected) {
|
|
491
510
|
await cad.connect();
|
|
492
511
|
}
|
|
493
|
-
if (!cad.connected)
|
|
512
|
+
if (!cad.connected)
|
|
513
|
+
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
494
514
|
const result = await cad.newDoc();
|
|
495
515
|
if (result) {
|
|
496
516
|
return { content: [{ type: "text", text: "\u5DF2\u5728 CAD \u4E2D\u65B0\u5EFA\u7A7A\u767D\u6587\u6863" }] };
|
|
@@ -501,7 +521,8 @@ async function bringToFront() {
|
|
|
501
521
|
if (!cad.connected) {
|
|
502
522
|
await cad.connect();
|
|
503
523
|
}
|
|
504
|
-
if (!cad.connected)
|
|
524
|
+
if (!cad.connected)
|
|
525
|
+
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
505
526
|
const result = await cad.bringToFront();
|
|
506
527
|
if (result) {
|
|
507
528
|
return { content: [{ type: "text", text: "\u5DF2\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0" }] };
|
|
@@ -512,7 +533,8 @@ async function installAtlisp() {
|
|
|
512
533
|
if (!cad.connected) {
|
|
513
534
|
await cad.connect();
|
|
514
535
|
}
|
|
515
|
-
if (!cad.connected)
|
|
536
|
+
if (!cad.connected)
|
|
537
|
+
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
516
538
|
const installCode = `(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))))`;
|
|
517
539
|
await cad.sendCommand(installCode + "\n");
|
|
518
540
|
return { content: [{ type: "text", text: "\u5DF2\u53D1\u9001 @lisp \u5B89\u88C5\u4EE3\u7801\u5230 CAD" }] };
|
|
@@ -521,20 +543,68 @@ async function listFunctionsInCad() {
|
|
|
521
543
|
if (!cad.connected) {
|
|
522
544
|
await cad.connect();
|
|
523
545
|
}
|
|
524
|
-
if (!cad.connected)
|
|
546
|
+
if (!cad.connected)
|
|
547
|
+
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
525
548
|
try {
|
|
526
549
|
const result = await cad.sendCommandWithResult("(atoms-family 0)", null);
|
|
527
|
-
if (result)
|
|
550
|
+
if (result)
|
|
551
|
+
return { content: [{ type: "text", text: result }] };
|
|
528
552
|
return { content: [{ type: "text", text: "CAD \u51FD\u6570\u5217\u8868\u4E3A\u7A7A" }] };
|
|
529
553
|
} catch (e) {
|
|
530
554
|
return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
|
|
531
555
|
}
|
|
532
556
|
}
|
|
557
|
+
async function getSystemStatus() {
|
|
558
|
+
const status = {
|
|
559
|
+
mcp: { version: process.env.npm_package_version || "unknown" },
|
|
560
|
+
worker: { alive: false },
|
|
561
|
+
cad: { connected: false, platform: null, version: null, busy: false, hasDoc: false },
|
|
562
|
+
lisp: { available: false, testResult: null, error: null },
|
|
563
|
+
packages: null
|
|
564
|
+
};
|
|
565
|
+
try {
|
|
566
|
+
status.worker.alive = await cad.ping();
|
|
567
|
+
} catch {
|
|
568
|
+
status.worker.alive = false;
|
|
569
|
+
}
|
|
570
|
+
status.cad.connected = cad.connected;
|
|
571
|
+
if (cad.connected) {
|
|
572
|
+
status.cad.platform = cad.getPlatform();
|
|
573
|
+
status.cad.version = cad.getVersion();
|
|
574
|
+
try {
|
|
575
|
+
status.cad.busy = await cad.isBusy();
|
|
576
|
+
} catch {
|
|
577
|
+
}
|
|
578
|
+
try {
|
|
579
|
+
const doc = await cad.hasDoc();
|
|
580
|
+
status.cad.hasDoc = doc.hasDoc;
|
|
581
|
+
} catch {
|
|
582
|
+
}
|
|
583
|
+
try {
|
|
584
|
+
const r = await cad.sendCommandWithResult("(+ 1 2)");
|
|
585
|
+
if (r !== null && r !== void 0) {
|
|
586
|
+
status.lisp.available = true;
|
|
587
|
+
status.lisp.testResult = String(r).trim();
|
|
588
|
+
}
|
|
589
|
+
} catch (e) {
|
|
590
|
+
status.lisp.error = e.message;
|
|
591
|
+
}
|
|
592
|
+
try {
|
|
593
|
+
const pkgResult = await cad.sendCommandWithResult("(@::package-list-in-local)");
|
|
594
|
+
if (pkgResult && pkgResult !== "nil") {
|
|
595
|
+
status.packages = pkgResult;
|
|
596
|
+
}
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return { content: [{ type: "text", text: JSON.stringify(status, null, 2) }] };
|
|
601
|
+
}
|
|
533
602
|
async function initAtlisp() {
|
|
534
603
|
if (!cad.connected) {
|
|
535
604
|
await cad.connect();
|
|
536
605
|
}
|
|
537
|
-
if (!cad.connected)
|
|
606
|
+
if (!cad.connected)
|
|
607
|
+
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
538
608
|
const code = `(if (null @::load-module)
|
|
539
609
|
(progn
|
|
540
610
|
(vl-load-com)
|
|
@@ -574,10 +644,13 @@ async function fetchPackages() {
|
|
|
574
644
|
return null;
|
|
575
645
|
}
|
|
576
646
|
async function listPackages() {
|
|
577
|
-
if (!cad.connected)
|
|
578
|
-
|
|
647
|
+
if (!cad.connected)
|
|
648
|
+
await cad.connect();
|
|
649
|
+
if (!cad.connected)
|
|
650
|
+
return { content: [{ type: "text", text: "\u672A\u8FDE\u63A5 CAD" }], isError: true };
|
|
579
651
|
const result = await cad.sendCommandWithResult("(@::package-list-in-local)");
|
|
580
|
-
if (result && result !== "nil")
|
|
652
|
+
if (result && result !== "nil")
|
|
653
|
+
return { content: [{ type: "text", text: result }] };
|
|
581
654
|
const packages = MOCK_PACKAGES.map((p) => `${p.name} v${p.version} - ${p.description}`);
|
|
582
655
|
return { content: [{ type: "text", text: `\u5DF2\u5B89\u88C5\u7684 @lisp \u5305:
|
|
583
656
|
${packages.join("\n")}` }] };
|
|
@@ -594,10 +667,12 @@ async function searchPackages(query) {
|
|
|
594
667
|
for (const p of items) {
|
|
595
668
|
const name = (p.name || "").toLowerCase();
|
|
596
669
|
const desc = (p.description || "").toLowerCase();
|
|
597
|
-
if (name.includes(q) || desc.includes(q))
|
|
670
|
+
if (name.includes(q) || desc.includes(q))
|
|
671
|
+
results.push(p);
|
|
598
672
|
}
|
|
599
673
|
} else {
|
|
600
|
-
for (const p of items)
|
|
674
|
+
for (const p of items)
|
|
675
|
+
results.push(p);
|
|
601
676
|
}
|
|
602
677
|
if (results.length === 0) {
|
|
603
678
|
return { content: [{ type: "text", text: `\u672A\u627E\u5230\u5305\u542B "${query}" \u7684\u5305` }] };
|
|
@@ -639,7 +714,8 @@ async function getFunctionUsage(funcName, packageName) {
|
|
|
639
714
|
const data = await response.json();
|
|
640
715
|
const funcs = Object.values(data.all_functions || {});
|
|
641
716
|
const func = funcs.find((f2) => f2.name === funcName || f2.name === `${packageName}:${funcName}`);
|
|
642
|
-
if (func)
|
|
717
|
+
if (func)
|
|
718
|
+
results.push(func);
|
|
643
719
|
}
|
|
644
720
|
} catch (e) {
|
|
645
721
|
log(`function-handlers fetch error: ${e.message}`);
|
|
@@ -650,7 +726,8 @@ async function getFunctionUsage(funcName, packageName) {
|
|
|
650
726
|
const raw = await fs2.readFile(path3.join(FUNCTIONS_DIR, file), "utf-8");
|
|
651
727
|
const data = JSON.parse(raw);
|
|
652
728
|
const func = data.functions?.find((f2) => f2.name === funcName);
|
|
653
|
-
if (func)
|
|
729
|
+
if (func)
|
|
730
|
+
results.push(func);
|
|
654
731
|
}
|
|
655
732
|
}
|
|
656
733
|
if (results.length === 0) {
|
|
@@ -730,12 +807,26 @@ function getCached(key) {
|
|
|
730
807
|
function setCache(key, data) {
|
|
731
808
|
resourceCache.set(key, { data, timestamp: Date.now() });
|
|
732
809
|
}
|
|
810
|
+
function clearCache(uri) {
|
|
811
|
+
if (uri) {
|
|
812
|
+
for (const key of resourceCache.keys()) {
|
|
813
|
+
if (key.startsWith(uri.split("://")[1]?.split("/")[0] + ":")) {
|
|
814
|
+
resourceCache.delete(key);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
} else {
|
|
818
|
+
resourceCache.clear();
|
|
819
|
+
}
|
|
820
|
+
}
|
|
733
821
|
function parseLispList(str) {
|
|
734
|
-
if (!str || typeof str !== "string")
|
|
822
|
+
if (!str || typeof str !== "string")
|
|
823
|
+
return null;
|
|
735
824
|
const trimmed = str.trim();
|
|
736
|
-
if (!trimmed.startsWith("(") || !trimmed.endsWith(")"))
|
|
825
|
+
if (!trimmed.startsWith("(") || !trimmed.endsWith(")"))
|
|
826
|
+
return null;
|
|
737
827
|
const content = trimmed.slice(1, -1).trim();
|
|
738
|
-
if (!content)
|
|
828
|
+
if (!content)
|
|
829
|
+
return [];
|
|
739
830
|
const result = [];
|
|
740
831
|
let depth = 0;
|
|
741
832
|
let current = "";
|
|
@@ -777,15 +868,21 @@ function parseLispList(str) {
|
|
|
777
868
|
}
|
|
778
869
|
current += ch;
|
|
779
870
|
}
|
|
780
|
-
if (current.trim())
|
|
871
|
+
if (current.trim())
|
|
872
|
+
result.push(current.trim());
|
|
781
873
|
return result.map((item) => {
|
|
782
874
|
const t = item.trim();
|
|
783
|
-
if (t === "nil")
|
|
784
|
-
|
|
785
|
-
if (t === "
|
|
875
|
+
if (t === "nil")
|
|
876
|
+
return null;
|
|
877
|
+
if (t === "t")
|
|
878
|
+
return true;
|
|
879
|
+
if (t === "T")
|
|
880
|
+
return true;
|
|
786
881
|
const num = Number(t);
|
|
787
|
-
if (!isNaN(num) && t !== "")
|
|
788
|
-
|
|
882
|
+
if (!isNaN(num) && t !== "")
|
|
883
|
+
return num;
|
|
884
|
+
if (t.startsWith('"') && t.endsWith('"'))
|
|
885
|
+
return t.slice(1, -1);
|
|
789
886
|
return t;
|
|
790
887
|
});
|
|
791
888
|
}
|
|
@@ -800,14 +897,16 @@ var RESOURCES = [
|
|
|
800
897
|
];
|
|
801
898
|
function parseQuery(uri) {
|
|
802
899
|
const qIdx = uri.indexOf("?");
|
|
803
|
-
if (qIdx === -1)
|
|
900
|
+
if (qIdx === -1)
|
|
901
|
+
return { base: uri, params: {} };
|
|
804
902
|
const base = uri.substring(0, qIdx);
|
|
805
903
|
const params = {};
|
|
806
904
|
uri.substring(qIdx + 1).split("&").forEach((p) => {
|
|
807
905
|
const eqIdx = p.indexOf("=");
|
|
808
906
|
const k = eqIdx === -1 ? p : p.substring(0, eqIdx);
|
|
809
907
|
const v = eqIdx === -1 ? "" : p.substring(eqIdx + 1);
|
|
810
|
-
if (k)
|
|
908
|
+
if (k)
|
|
909
|
+
params[k] = decodeURIComponent(v);
|
|
811
910
|
});
|
|
812
911
|
return { base, params };
|
|
813
912
|
}
|
|
@@ -843,7 +942,8 @@ async function readResource(uri) {
|
|
|
843
942
|
}
|
|
844
943
|
async function getCadInfo2() {
|
|
845
944
|
const cached = getCached("cad:info");
|
|
846
|
-
if (cached)
|
|
945
|
+
if (cached)
|
|
946
|
+
return cached;
|
|
847
947
|
if (!cad.connected) {
|
|
848
948
|
await cad.connect();
|
|
849
949
|
}
|
|
@@ -870,9 +970,12 @@ async function getCadInfo2() {
|
|
|
870
970
|
async function getLayers(filterName = null) {
|
|
871
971
|
const cacheKey = filterName ? `layers:${filterName}` : "layers:all";
|
|
872
972
|
const cached = getCached(cacheKey);
|
|
873
|
-
if (cached)
|
|
874
|
-
|
|
875
|
-
if (!cad.connected)
|
|
973
|
+
if (cached)
|
|
974
|
+
return cached;
|
|
975
|
+
if (!cad.connected)
|
|
976
|
+
await cad.connect();
|
|
977
|
+
if (!cad.connected)
|
|
978
|
+
return [];
|
|
876
979
|
try {
|
|
877
980
|
const code = filterName ? `(tblnext "LAYER" T)` : `(progn (setq res nil)(while (setq e (tblnext "LAYER" (null res)))(setq res (cons (list (cdr (assoc 2 e)) (cdr (assoc 62 e)) (cdr (assoc 70 e))) res))) (reverse res))`;
|
|
878
981
|
const result = await cad.sendCommandWithResult(code);
|
|
@@ -919,8 +1022,10 @@ async function getLayers(filterName = null) {
|
|
|
919
1022
|
async function getEntities(filterType = null) {
|
|
920
1023
|
const cacheKey = filterType ? `entities:${filterType}` : "entities:all";
|
|
921
1024
|
const cached = getCached(cacheKey);
|
|
922
|
-
if (cached)
|
|
923
|
-
|
|
1025
|
+
if (cached)
|
|
1026
|
+
return cached;
|
|
1027
|
+
if (!cad.connected)
|
|
1028
|
+
await cad.connect();
|
|
924
1029
|
if (!cad.connected) {
|
|
925
1030
|
const result = { total: 0, byType: {} };
|
|
926
1031
|
setCache(cacheKey, result);
|
|
@@ -974,8 +1079,10 @@ async function getEntities(filterType = null) {
|
|
|
974
1079
|
}
|
|
975
1080
|
}
|
|
976
1081
|
async function getDwgName() {
|
|
977
|
-
if (!cad.connected)
|
|
978
|
-
|
|
1082
|
+
if (!cad.connected)
|
|
1083
|
+
await cad.connect();
|
|
1084
|
+
if (!cad.connected)
|
|
1085
|
+
return { name: null };
|
|
979
1086
|
try {
|
|
980
1087
|
const code = `(vl-princ-to-string (getvar "dwgname"))`;
|
|
981
1088
|
const name = await cad.sendCommandWithResult(code);
|
|
@@ -985,8 +1092,10 @@ async function getDwgName() {
|
|
|
985
1092
|
}
|
|
986
1093
|
}
|
|
987
1094
|
async function getDwgPath() {
|
|
988
|
-
if (!cad.connected)
|
|
989
|
-
|
|
1095
|
+
if (!cad.connected)
|
|
1096
|
+
await cad.connect();
|
|
1097
|
+
if (!cad.connected)
|
|
1098
|
+
return { path: null, name: null };
|
|
990
1099
|
try {
|
|
991
1100
|
const code = `(progn
|
|
992
1101
|
(setq prefix (vl-princ-to-string (getvar "dwgprefix")))
|
|
@@ -1004,7 +1113,8 @@ async function getDwgPath() {
|
|
|
1004
1113
|
}
|
|
1005
1114
|
if (!parsed) {
|
|
1006
1115
|
const listResult = parseLispList(result);
|
|
1007
|
-
if (listResult && listResult.length >= 2)
|
|
1116
|
+
if (listResult && listResult.length >= 2)
|
|
1117
|
+
parsed = listResult;
|
|
1008
1118
|
}
|
|
1009
1119
|
if (parsed && Array.isArray(parsed) && parsed.length >= 2) {
|
|
1010
1120
|
return { path: String(parsed[0]), name: String(parsed[1]) };
|
|
@@ -1015,17 +1125,71 @@ async function getDwgPath() {
|
|
|
1015
1125
|
}
|
|
1016
1126
|
}
|
|
1017
1127
|
async function getPackages(filterName = null) {
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
if (
|
|
1025
|
-
|
|
1026
|
-
|
|
1128
|
+
const cacheKey = filterName ? `packages:${filterName}` : "packages:all";
|
|
1129
|
+
const cached = getCached(cacheKey);
|
|
1130
|
+
if (cached)
|
|
1131
|
+
return cached;
|
|
1132
|
+
if (!cad.connected)
|
|
1133
|
+
await cad.connect();
|
|
1134
|
+
if (!cad.connected)
|
|
1135
|
+
return [];
|
|
1136
|
+
try {
|
|
1137
|
+
const code = `(mapcar 'cdr @::*local-pkgs*)`;
|
|
1138
|
+
const result = await cad.sendCommandWithResult(code);
|
|
1139
|
+
if (!result || result === "" || result === "nil") {
|
|
1140
|
+
setCache(cacheKey, []);
|
|
1141
|
+
return [];
|
|
1142
|
+
}
|
|
1143
|
+
let raw = [];
|
|
1144
|
+
try {
|
|
1145
|
+
raw = JSON.parse(result);
|
|
1146
|
+
} catch {
|
|
1147
|
+
raw = parseLispList(result) || [];
|
|
1148
|
+
}
|
|
1149
|
+
if (!Array.isArray(raw))
|
|
1150
|
+
raw = [];
|
|
1151
|
+
const packages = raw.map((item) => {
|
|
1152
|
+
if (Array.isArray(item)) {
|
|
1153
|
+
const pkg = { name: "", version: "0.0.0", description: "", loaded: true };
|
|
1154
|
+
for (const entry of item) {
|
|
1155
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
1156
|
+
const [[key, val]] = Object.entries(entry);
|
|
1157
|
+
const k = String(key);
|
|
1158
|
+
const v = String(val);
|
|
1159
|
+
if (k === ":NAME")
|
|
1160
|
+
pkg.name = v;
|
|
1161
|
+
else if (k === ":VERSION")
|
|
1162
|
+
pkg.version = v;
|
|
1163
|
+
else if (k === ":DESCRIPTION")
|
|
1164
|
+
pkg.description = v;
|
|
1165
|
+
else if (k === ":FULL-NAME")
|
|
1166
|
+
pkg.fullName = v;
|
|
1167
|
+
else if (k === ":AUTHOR")
|
|
1168
|
+
pkg.author = v;
|
|
1169
|
+
else if (k === ":CATEGORY")
|
|
1170
|
+
pkg.category = v;
|
|
1171
|
+
else if (k === ":URL")
|
|
1172
|
+
pkg.url = v;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
return pkg;
|
|
1176
|
+
}
|
|
1177
|
+
if (typeof item === "string" || typeof item === "number") {
|
|
1178
|
+
return { name: String(item), version: "0.0.0", loaded: true };
|
|
1179
|
+
}
|
|
1180
|
+
return null;
|
|
1181
|
+
}).filter(Boolean);
|
|
1182
|
+
if (filterName) {
|
|
1183
|
+
const filtered = packages.filter((p) => p.name === filterName);
|
|
1184
|
+
setCache(cacheKey, filtered);
|
|
1185
|
+
return filtered;
|
|
1186
|
+
}
|
|
1187
|
+
setCache(cacheKey, packages);
|
|
1188
|
+
return packages;
|
|
1189
|
+
} catch (e) {
|
|
1190
|
+
setCache(cacheKey, []);
|
|
1191
|
+
return [];
|
|
1027
1192
|
}
|
|
1028
|
-
return packages;
|
|
1029
1193
|
}
|
|
1030
1194
|
function getPlatforms() {
|
|
1031
1195
|
return CAD_PLATFORMS.map((name) => ({
|
|
@@ -1314,10 +1478,14 @@ ${generateSuggestions(entities, layers)}`
|
|
|
1314
1478
|
}
|
|
1315
1479
|
function generateSuggestions(entities, layers) {
|
|
1316
1480
|
const suggestions = [];
|
|
1317
|
-
if (entities.total > 1e3)
|
|
1318
|
-
|
|
1319
|
-
if (
|
|
1320
|
-
|
|
1481
|
+
if (entities.total > 1e3)
|
|
1482
|
+
suggestions.push("- \u56FE\u7EB8\u5B9E\u4F53\u8F83\u591A\uFF0C\u5EFA\u8BAE\u4F7F\u7528\u56FE\u5C42\u5206\u7C7B\u7BA1\u7406");
|
|
1483
|
+
if (layers.length > 20)
|
|
1484
|
+
suggestions.push("- \u56FE\u5C42\u8F83\u591A\uFF0C\u5EFA\u8BAE\u6E05\u7406\u672A\u4F7F\u7528\u7684\u56FE\u5C42");
|
|
1485
|
+
if (entities.byType.LINE && entities.byType.LINE > 500)
|
|
1486
|
+
suggestions.push("- \u7EBF\u6761\u8F83\u591A\uFF0C\u53EF\u8003\u8651\u4F7F\u7528 BLOCK \u51CF\u5C11\u5B9E\u4F53\u6570\u91CF");
|
|
1487
|
+
if (!entities.byType.DIMENSION)
|
|
1488
|
+
suggestions.push("- \u672A\u53D1\u73B0\u5C3A\u5BF8\u6807\u6CE8\uFF0C\u5EFA\u8BAE\u6DFB\u52A0\u6807\u6CE8");
|
|
1321
1489
|
return suggestions.length ? suggestions.join("\n") : "- \u56FE\u7EB8\u7ED3\u6784\u826F\u597D";
|
|
1322
1490
|
}
|
|
1323
1491
|
async function generateBatchLinesPrompt(args) {
|
|
@@ -2045,9 +2213,11 @@ var SseSession = class {
|
|
|
2045
2213
|
return lines.join("\n") + "\n\n";
|
|
2046
2214
|
}
|
|
2047
2215
|
_setupDrain() {
|
|
2048
|
-
if (typeof this.#res.on !== "function")
|
|
2216
|
+
if (typeof this.#res.on !== "function")
|
|
2217
|
+
return;
|
|
2049
2218
|
this.#drainHandler = () => {
|
|
2050
|
-
if (!this.#active)
|
|
2219
|
+
if (!this.#active)
|
|
2220
|
+
return;
|
|
2051
2221
|
if (this.#backpressureBuffer.length > 0) {
|
|
2052
2222
|
this._drainBuffer();
|
|
2053
2223
|
}
|
|
@@ -2069,7 +2239,8 @@ var SseSession = class {
|
|
|
2069
2239
|
}
|
|
2070
2240
|
}
|
|
2071
2241
|
_write(content) {
|
|
2072
|
-
if (!this.#active)
|
|
2242
|
+
if (!this.#active)
|
|
2243
|
+
return false;
|
|
2073
2244
|
try {
|
|
2074
2245
|
if (this.#backpressureBuffer.length > 0) {
|
|
2075
2246
|
this.#backpressureBuffer.push(content);
|
|
@@ -2339,7 +2510,8 @@ var SERVER_CAPABILITIES = {
|
|
|
2339
2510
|
prompts: {}
|
|
2340
2511
|
};
|
|
2341
2512
|
var { port, host, transport, apiKey, rateLimitWindow, rateLimitMax } = config_default;
|
|
2342
|
-
if (apiKey)
|
|
2513
|
+
if (apiKey)
|
|
2514
|
+
log("API Key authentication enabled");
|
|
2343
2515
|
var mcpLimiter = rateLimit({
|
|
2344
2516
|
windowMs: rateLimitWindow,
|
|
2345
2517
|
max: rateLimitMax,
|
|
@@ -2387,9 +2559,11 @@ ${CAD_PLATFORMS.join("\n")}
|
|
|
2387
2559
|
init_atlisp: () => initAtlisp(),
|
|
2388
2560
|
get_function_usage: (a) => getFunctionUsage(a.name, a.package),
|
|
2389
2561
|
list_symbols: (a) => listSymbols(a.package),
|
|
2562
|
+
get_system_status: () => getSystemStatus(),
|
|
2390
2563
|
import_funlib: async (a) => {
|
|
2391
2564
|
const data = await loadAtlibFunctionLib();
|
|
2392
|
-
if (!data)
|
|
2565
|
+
if (!data)
|
|
2566
|
+
return { content: [{ type: "text", text: "\u52A0\u8F7D\u51FD\u6570\u5E93\u5931\u8D25" }], isError: true };
|
|
2393
2567
|
if (a.format === "list") {
|
|
2394
2568
|
const items = Object.values(data.all_functions || {}).map((f) => `${f.name}: ${f.description || ""}`);
|
|
2395
2569
|
return { content: [{ type: "text", text: items.join("\n") }] };
|
|
@@ -2547,11 +2721,17 @@ var tools = [
|
|
|
2547
2721
|
format: { type: "string", enum: ["json", "list"], description: "\u8FD4\u56DE\u683C\u5F0F\uFF1Ajson\uFF08\u5B8C\u6574JSON\uFF09\u6216 list\uFF08\u51FD\u6570\u540D:\u63CF\u8FF0 \u5217\u8868\uFF09\uFF0C\u9ED8\u8BA4 json" }
|
|
2548
2722
|
}
|
|
2549
2723
|
}
|
|
2724
|
+
},
|
|
2725
|
+
{
|
|
2726
|
+
name: "get_system_status",
|
|
2727
|
+
description: "\u83B7\u53D6\u5B8C\u6574\u7CFB\u7EDF\u8BCA\u65AD\u4FE1\u606F\uFF1AMCP \u72B6\u6001\u3001CAD \u8FDE\u63A5\u3001Lisp \u6267\u884C\u3001\u5305\u5217\u8868",
|
|
2728
|
+
inputSchema: { type: "object", properties: {} }
|
|
2550
2729
|
}
|
|
2551
2730
|
];
|
|
2552
2731
|
async function handleToolCall(name, args) {
|
|
2553
2732
|
const handler = TOOL_HANDLERS[name];
|
|
2554
|
-
if (!handler)
|
|
2733
|
+
if (!handler)
|
|
2734
|
+
return { content: [{ type: "text", text: `\u672A\u77E5\u5DE5\u5177: ${name}` }], isError: true };
|
|
2555
2735
|
try {
|
|
2556
2736
|
const result = await handler(args || {});
|
|
2557
2737
|
notifyResourceChanges(name);
|
|
@@ -2563,14 +2743,16 @@ async function handleToolCall(name, args) {
|
|
|
2563
2743
|
}
|
|
2564
2744
|
function notifyResourceChanges(toolName) {
|
|
2565
2745
|
const resourceMap = {
|
|
2566
|
-
connect_cad: ["atlisp://cad/info"],
|
|
2746
|
+
connect_cad: ["atlisp://cad/info", "atlisp://cad/layers", "atlisp://dwg/name", "atlisp://dwg/path", "atlisp://packages"],
|
|
2567
2747
|
new_document: ["atlisp://dwg/name", "atlisp://dwg/path", "atlisp://cad/layers", "atlisp://cad/entities"],
|
|
2568
2748
|
install_package: ["atlisp://packages"],
|
|
2569
|
-
install_atlisp: ["atlisp://packages"]
|
|
2749
|
+
install_atlisp: ["atlisp://packages", "atlisp://cad/info"],
|
|
2750
|
+
init_atlisp: ["atlisp://packages", "atlisp://cad/info"]
|
|
2570
2751
|
};
|
|
2571
2752
|
const uris = resourceMap[toolName];
|
|
2572
2753
|
if (uris) {
|
|
2573
2754
|
for (const uri of uris) {
|
|
2755
|
+
clearCache(uri);
|
|
2574
2756
|
if (isSubscribed(uri)) {
|
|
2575
2757
|
notify(uri, null);
|
|
2576
2758
|
}
|
|
@@ -2672,7 +2854,8 @@ async function startServer() {
|
|
|
2672
2854
|
const JSON_CONTENT_TYPES = ["application/json", "application/json-rpc", "application/vnd.api+json"];
|
|
2673
2855
|
app.use(async (req, res, next) => {
|
|
2674
2856
|
const ct = (req.headers["content-type"] || "").toLowerCase();
|
|
2675
|
-
if (!JSON_CONTENT_TYPES.some((t) => ct.startsWith(t)))
|
|
2857
|
+
if (!JSON_CONTENT_TYPES.some((t) => ct.startsWith(t)))
|
|
2858
|
+
return next();
|
|
2676
2859
|
try {
|
|
2677
2860
|
const buf = await rawBody(req, { limit: "10mb" });
|
|
2678
2861
|
const m = ct.match(/charset\s*=\s*([^\s;]+)/i);
|
|
@@ -2693,9 +2876,11 @@ async function startServer() {
|
|
|
2693
2876
|
const PUBLIC_PATHS = ["/health"];
|
|
2694
2877
|
if (apiKey) {
|
|
2695
2878
|
app.use((req, res, next) => {
|
|
2696
|
-
if (PUBLIC_PATHS.includes(req.path))
|
|
2879
|
+
if (PUBLIC_PATHS.includes(req.path))
|
|
2880
|
+
return next();
|
|
2697
2881
|
const auth = req.get("Authorization");
|
|
2698
|
-
if (auth === `Bearer ${apiKey}`)
|
|
2882
|
+
if (auth === `Bearer ${apiKey}`)
|
|
2883
|
+
return next();
|
|
2699
2884
|
res.status(401).json({ error: "Unauthorized" });
|
|
2700
2885
|
});
|
|
2701
2886
|
}
|
|
@@ -2710,7 +2895,8 @@ async function startServer() {
|
|
|
2710
2895
|
res.setHeader("Access-Control-Expose-Headers", "mcp-session-id, content-type, x-accel-buffering");
|
|
2711
2896
|
res.setHeader("Access-Control-Max-Age", "86400");
|
|
2712
2897
|
res.setHeader("Vary", "Accept");
|
|
2713
|
-
if (req.method === "OPTIONS")
|
|
2898
|
+
if (req.method === "OPTIONS")
|
|
2899
|
+
return res.status(204).end();
|
|
2714
2900
|
next();
|
|
2715
2901
|
});
|
|
2716
2902
|
}
|