@atlisp/mcp 1.5.0 → 1.5.1

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.
Files changed (2) hide show
  1. package/dist/atlisp-mcp.js +1578 -1302
  2. package/package.json +2 -2
@@ -1,138 +1,43 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/atlisp-mcp.js
4
- import path7 from "path";
5
- import fs6 from "fs";
6
- import { fileURLToPath as fileURLToPath4 } from "url";
7
- import { createRequire } from "module";
8
- import os4 from "os";
9
- import express from "express";
10
- import rawBody from "raw-body";
11
- import iconv from "iconv-lite";
12
- import rateLimit from "express-rate-limit";
13
- import { randomUUID as randomUUID4 } from "crypto";
14
- import { AsyncLocalStorage } from "async_hooks";
15
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
16
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
17
-
18
- // src/session-transport.js
19
- import { randomUUID } from "crypto";
20
- var SESSION_TIMEOUT = 30 * 60 * 1e3;
21
- var SessionTransport = class {
22
- constructor(sessionId) {
23
- this.sessionId = sessionId || randomUUID();
24
- this.onclose = null;
25
- this.onerror = null;
26
- this.onmessage = null;
27
- this._pendingRequest = null;
28
- this._started = false;
29
- this._closed = false;
30
- this._cleanupTimer = null;
31
- }
32
- async start() {
33
- if (this._started) {
34
- throw new Error("Transport already started");
35
- }
36
- this._started = true;
37
- }
38
- async send(message) {
39
- if (this._closed) return;
40
- if (this._pendingRequest) {
41
- const { resolve, reject, timeout } = this._pendingRequest;
42
- clearTimeout(timeout);
43
- this._pendingRequest = null;
44
- resolve(message);
45
- }
46
- }
47
- async close() {
48
- if (this._closed) return;
49
- this._closed = true;
50
- if (this._pendingRequest) {
51
- const { reject, timeout } = this._pendingRequest;
52
- clearTimeout(timeout);
53
- this._pendingRequest = null;
54
- reject(new Error("Transport closed"));
55
- }
56
- this._clearCleanupTimer();
57
- this.onclose?.();
58
- }
59
- async handleRequest(message, timeoutMs = 6e4) {
60
- if (this._closed) {
61
- throw new Error("Transport closed");
62
- }
63
- if (!message || !message.method) {
64
- throw new Error("Invalid message");
65
- }
66
- if (!message.id) {
67
- this.onmessage?.(message);
68
- return null;
69
- }
70
- return new Promise((resolve, reject) => {
71
- const timeout = setTimeout(() => {
72
- if (this._pendingRequest?.resolve === resolve) {
73
- this._pendingRequest = null;
74
- reject(new Error("Request timeout"));
75
- }
76
- }, timeoutMs);
77
- this._pendingRequest = { resolve, reject, timeout };
78
- this.onmessage?.(message);
79
- });
80
- }
81
- resetCleanupTimer() {
82
- this._clearCleanupTimer();
83
- this._cleanupTimer = setTimeout(() => {
84
- this.close();
85
- }, SESSION_TIMEOUT);
86
- }
87
- _clearCleanupTimer() {
88
- if (this._cleanupTimer) {
89
- clearTimeout(this._cleanupTimer);
90
- this._cleanupTimer = null;
91
- }
92
- }
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
93
10
  };
94
-
95
- // src/atlisp-mcp.js
96
- import {
97
- ListToolsRequestSchema,
98
- CallToolRequestSchema,
99
- ListResourcesRequestSchema,
100
- ReadResourceRequestSchema,
101
- SubscribeRequestSchema,
102
- UnsubscribeRequestSchema,
103
- ListPromptsRequestSchema,
104
- GetPromptRequestSchema
105
- } from "@modelcontextprotocol/sdk/types.js";
106
-
107
- // src/cad.js
108
- import { spawn } from "child_process";
109
- import path from "path";
110
- import { fileURLToPath } from "url";
111
- import { randomUUID as randomUUID2 } from "crypto";
112
11
 
113
12
  // src/constants.js
114
- var CAD_PLATFORMS = ["AutoCAD", "ZWCAD", "GStarCAD", "BricsCAD"];
115
- var FILE_EXTENSIONS = {
116
- "AutoCAD": [".fas", ".vlx"],
117
- "ZWCAD": [".zelx", ".vls"],
118
- "GStarCAD": [".fas", ".vlx"],
119
- "BricsCAD": [".des"]
120
- };
121
- var SERVER_NAME = "atlisp-mcp-server";
122
- var SERVER_VERSION = "1.5.0";
123
- var MOCK_PACKAGES = [
124
- { name: "base", description: "\u57FA\u7840\u51FD\u6570\u5E93", version: "1.0.0" },
125
- { name: "at-pm", description: "\u5DE5\u7A0B\u9879\u76EE\u7BA1\u7406", version: "2.1.0" },
126
- { name: "network", description: "\u7F51\u7EDC\u529F\u80FD\u6A21\u5757", version: "1.5.0" },
127
- { name: "userman", description: "\u7528\u6237\u7BA1\u7406", version: "1.2.0" },
128
- { name: "pkgman", description: "\u5305\u7BA1\u7406\u5668", version: "2.0.0" },
129
- { name: "sidebar", description: "\u4FA7\u8FB9\u680F\u5DE5\u5177", version: "1.0.0" },
130
- { name: "aibot", description: "AI \u52A9\u624B", version: "0.9.0" },
131
- { name: "tips", description: "\u6BCF\u65E5\u63D0\u793A", version: "1.0.0" },
132
- { name: "function", description: "\u51FD\u6570\u5E93", version: "3.0.0" }
133
- ];
13
+ var CAD_PLATFORMS, FILE_EXTENSIONS, SERVER_NAME, SERVER_VERSION, MOCK_PACKAGES;
14
+ var init_constants = __esm({
15
+ "src/constants.js"() {
16
+ CAD_PLATFORMS = ["AutoCAD", "ZWCAD", "GStarCAD", "BricsCAD"];
17
+ FILE_EXTENSIONS = {
18
+ "AutoCAD": [".fas", ".vlx"],
19
+ "ZWCAD": [".zelx", ".vls"],
20
+ "GStarCAD": [".fas", ".vlx"],
21
+ "BricsCAD": [".des"]
22
+ };
23
+ SERVER_NAME = "atlisp-mcp-server";
24
+ SERVER_VERSION = "1.5.0";
25
+ MOCK_PACKAGES = [
26
+ { name: "base", description: "\u57FA\u7840\u51FD\u6570\u5E93", version: "1.0.0" },
27
+ { name: "at-pm", description: "\u5DE5\u7A0B\u9879\u76EE\u7BA1\u7406", version: "2.1.0" },
28
+ { name: "network", description: "\u7F51\u7EDC\u529F\u80FD\u6A21\u5757", version: "1.5.0" },
29
+ { name: "userman", description: "\u7528\u6237\u7BA1\u7406", version: "1.2.0" },
30
+ { name: "pkgman", description: "\u5305\u7BA1\u7406\u5668", version: "2.0.0" },
31
+ { name: "sidebar", description: "\u4FA7\u8FB9\u680F\u5DE5\u5177", version: "1.0.0" },
32
+ { name: "aibot", description: "AI \u52A9\u624B", version: "0.9.0" },
33
+ { name: "tips", description: "\u6BCF\u65E5\u63D0\u793A", version: "1.0.0" },
34
+ { name: "function", description: "\u51FD\u6570\u5E93", version: "3.0.0" }
35
+ ];
36
+ }
37
+ });
134
38
 
135
39
  // src/config.js
40
+ import { z } from "zod";
136
41
  function parseArgs() {
137
42
  const args = process.argv.slice(2);
138
43
  const result = { transport: "http", port: "8110", host: "0.0.0.0" };
@@ -152,42 +57,65 @@ function parseArgs() {
152
57
  }
153
58
  return result;
154
59
  }
155
- var cliArgs = parseArgs();
156
- var config = {
157
- port: parseInt(process.env.PORT || cliArgs.port, 10),
158
- host: process.env.HOST || cliArgs.host,
159
- transport: process.env.TRANSPORT || cliArgs.transport,
160
- apiKey: process.env.MCP_API_KEY || "",
161
- enableSse: process.env.ENABLE_SSE !== "false",
162
- messageTimeout: parseInt(process.env.MESSAGE_TIMEOUT || "60000", 10),
163
- heartbeatInterval: parseInt(process.env.HEARTBEAT_INTERVAL || "30000", 10),
164
- busyRetries: parseInt(process.env.BUSY_RETRIES || "10", 10),
165
- busyDelay: parseInt(process.env.BUSY_DELAY || "500", 10),
166
- enableCors: process.env.ENABLE_CORS !== "false",
167
- corsOrigin: process.env.CORS_ORIGIN || "*",
168
- rateLimitWindow: parseInt(process.env.RATE_LIMIT_WINDOW || "60000", 10),
169
- rateLimitMax: parseInt(process.env.RATE_LIMIT_MAX || "100", 10),
170
- resourceCacheTtl: parseInt(process.env.RESOURCE_CACHE_TTL || "5000", 10),
171
- debug: process.env.DEBUG === "true",
172
- debugFile: process.env.DEBUG_FILE || ""
173
- };
174
- var config_default = config;
60
+ var envSchema, cliArgs, envResult, env, config, config_default;
61
+ var init_config = __esm({
62
+ "src/config.js"() {
63
+ envSchema = z.object({
64
+ PORT: z.string().optional().default("8110"),
65
+ HOST: z.string().optional().default("0.0.0.0"),
66
+ TRANSPORT: z.enum(["http", "stdio"]).optional().default("http"),
67
+ MCP_API_KEY: z.string().optional().default(""),
68
+ ENABLE_SSE: z.string().optional().default("true"),
69
+ MESSAGE_TIMEOUT: z.string().optional().default("60000"),
70
+ HEARTBEAT_INTERVAL: z.string().optional().default("30000"),
71
+ BUSY_RETRIES: z.string().optional().default("10"),
72
+ BUSY_DELAY: z.string().optional().default("500"),
73
+ ENABLE_CORS: z.string().optional().default("true"),
74
+ CORS_ORIGIN: z.string().optional().default("*"),
75
+ RATE_LIMIT_WINDOW: z.string().optional().default("60000"),
76
+ RATE_LIMIT_MAX: z.string().optional().default("100"),
77
+ RESOURCE_CACHE_TTL: z.string().optional().default("5000"),
78
+ FUNCTION_LIB_CACHE_TTL: z.string().optional().default("300000"),
79
+ DEBUG: z.string().optional().default("false"),
80
+ DEBUG_FILE: z.string().optional().default(""),
81
+ FUNCTION_LIB_URL: z.string().optional().default("http://s3.atlisp.cn/json/functions.json")
82
+ });
83
+ cliArgs = parseArgs();
84
+ envResult = envSchema.safeParse(process.env);
85
+ if (!envResult.success) {
86
+ console.error("\u73AF\u5883\u53D8\u91CF\u914D\u7F6E\u9519\u8BEF:", envResult.error.flatten().fieldErrors);
87
+ process.exit(1);
88
+ }
89
+ env = envResult.data;
90
+ config = {
91
+ port: parseInt(env.PORT || cliArgs.port, 10),
92
+ host: env.HOST || cliArgs.host,
93
+ transport: process.env.TRANSPORT ? env.TRANSPORT : cliArgs.transport,
94
+ apiKey: env.MCP_API_KEY,
95
+ enableSse: env.ENABLE_SSE === "true",
96
+ messageTimeout: parseInt(env.MESSAGE_TIMEOUT, 10),
97
+ heartbeatInterval: parseInt(env.HEARTBEAT_INTERVAL, 10),
98
+ busyRetries: parseInt(env.BUSY_RETRIES, 10),
99
+ busyDelay: parseInt(env.BUSY_DELAY, 10),
100
+ enableCors: env.ENABLE_CORS === "true",
101
+ corsOrigin: env.CORS_ORIGIN,
102
+ rateLimitWindow: parseInt(env.RATE_LIMIT_WINDOW, 10),
103
+ rateLimitMax: parseInt(env.RATE_LIMIT_MAX, 10),
104
+ resourceCacheTtl: parseInt(env.RESOURCE_CACHE_TTL, 10),
105
+ functionLibCacheTtl: parseInt(env.FUNCTION_LIB_CACHE_TTL, 10),
106
+ debug: env.DEBUG === "true",
107
+ debugFile: env.DEBUG_FILE,
108
+ functionLibUrl: env.FUNCTION_LIB_URL
109
+ };
110
+ config_default = config;
111
+ }
112
+ });
175
113
 
176
114
  // src/cad.js
177
- var MESSAGE_TIMEOUT = config_default.messageTimeout;
178
- var HEARTBEAT_INTERVAL = config_default.heartbeatInterval;
179
- var MAX_RESTART_ATTEMPTS = 5;
180
- var RESTART_BACKOFF_BASE = 1e3;
181
- var __dirname = path.dirname(fileURLToPath(import.meta.url));
182
- var workerPath = path.join(__dirname, "cad-worker.js");
183
- var worker = null;
184
- var _platform = null;
185
- var heartbeatTimer = null;
186
- var pendingRequests = /* @__PURE__ */ new Map();
187
- var stdoutHandlerSetup = false;
188
- var MAX_BUFFER_SIZE = 1024 * 1024;
189
- var restartCount = 0;
190
- var restartTimer = null;
115
+ import { spawn } from "child_process";
116
+ import path from "path";
117
+ import { fileURLToPath } from "url";
118
+ import { randomUUID } from "crypto";
191
119
  function resetWorker() {
192
120
  for (const [id, { reject, timeout }] of pendingRequests) {
193
121
  clearTimeout(timeout);
@@ -308,7 +236,7 @@ function startHeartbeat() {
308
236
  }
309
237
  function sendMessage(msg) {
310
238
  const w = getWorker();
311
- const requestId = randomUUID2();
239
+ const requestId = randomUUID();
312
240
  return new Promise((resolve, reject) => {
313
241
  const timeout = setTimeout(() => {
314
242
  const pending = pendingRequests.get(requestId);
@@ -327,125 +255,142 @@ function sendMessage(msg) {
327
255
  }
328
256
  });
329
257
  }
330
- var CadConnection = class {
331
- constructor() {
332
- this.connected = false;
333
- this.version = null;
334
- this.product = null;
335
- }
336
- isAvailable() {
337
- return process.platform === "win32";
338
- }
339
- async connect(platform = null) {
340
- if (!this.isAvailable()) return false;
341
- try {
342
- const msg = platform ? { type: "connect", platform } : { type: "connect" };
343
- const result = await sendMessage(msg);
344
- if (result && result.success) {
345
- this.version = result.version;
346
- this.product = result.platform;
347
- _platform = result.platform;
348
- this.connected = true;
349
- return true;
350
- }
351
- } catch (e) {
352
- console.error("CAD connect error:", e.message);
353
- }
354
- return false;
355
- }
356
- async sendCommand(code) {
357
- if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
358
- const result = await sendMessage({ type: "send", code, platform: _platform });
359
- if (result.success) return true;
360
- throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
361
- }
362
- async sendCommandWithResult(code, encoding = null) {
363
- if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
364
- const result = await sendMessage({ type: "sendResult", code, platform: _platform, encoding: encoding || "" });
365
- if (result.success) {
366
- return result.result || "";
367
- }
368
- throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
369
- }
370
- getVersion() {
371
- return this.version;
372
- }
373
- getPlatform() {
374
- return this.product;
375
- }
376
- async isBusy() {
377
- if (!this.connected) return false;
378
- try {
379
- const result = await sendMessage({ type: "isBusy", platform: _platform });
380
- return result && result.isBusy;
381
- } catch (e) {
382
- return false;
383
- }
384
- }
385
- async hasDoc() {
386
- if (!this.connected) return { hasDoc: false, docCount: 0 };
387
- try {
388
- const result = await sendMessage({ type: "hasdoc", platform: _platform });
389
- return result || { hasDoc: false, docCount: 0 };
390
- } catch (e) {
391
- return { hasDoc: false, docCount: 0 };
392
- }
393
- }
394
- async newDoc() {
395
- if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
396
- try {
397
- const result = await sendMessage({ type: "newdoc", platform: _platform });
398
- return result && result.success;
399
- } catch (e) {
400
- return false;
401
- }
402
- }
403
- async bringToFront() {
404
- if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
405
- try {
406
- const result = await sendMessage({ type: "bringToFront", platform: _platform });
407
- return result && result.success;
408
- } catch (e) {
409
- return false;
410
- }
411
- }
412
- async getInfo() {
413
- if (!this.connected) return "CAD \u672A\u8FDE\u63A5";
414
- return `Platform: ${this.product}, Version: ${this.version}, Status: Connected`;
415
- }
416
- async disconnect() {
417
- this.connected = false;
418
- this.version = null;
419
- this.product = null;
420
- _platform = null;
421
- resetWorker();
422
- }
423
- async ping() {
424
- try {
425
- const result = await sendMessage({ type: "ping" });
426
- return result && result.pong;
427
- } catch (e) {
428
- return false;
429
- }
430
- }
431
- _reset() {
432
- this.connected = false;
433
- this.version = null;
434
- this.product = null;
258
+ var MESSAGE_TIMEOUT, HEARTBEAT_INTERVAL, MAX_RESTART_ATTEMPTS, RESTART_BACKOFF_BASE, __dirname, workerPath, worker, _platform, heartbeatTimer, pendingRequests, stdoutHandlerSetup, MAX_BUFFER_SIZE, restartCount, restartTimer, CadConnection, cad;
259
+ var init_cad = __esm({
260
+ "src/cad.js"() {
261
+ init_constants();
262
+ init_config();
263
+ MESSAGE_TIMEOUT = config_default.messageTimeout;
264
+ HEARTBEAT_INTERVAL = config_default.heartbeatInterval;
265
+ MAX_RESTART_ATTEMPTS = 5;
266
+ RESTART_BACKOFF_BASE = 1e3;
267
+ __dirname = path.dirname(fileURLToPath(import.meta.url));
268
+ workerPath = path.join(__dirname, "cad-worker.js");
269
+ worker = null;
435
270
  _platform = null;
436
- resetWorker();
271
+ heartbeatTimer = null;
272
+ pendingRequests = /* @__PURE__ */ new Map();
273
+ stdoutHandlerSetup = false;
274
+ MAX_BUFFER_SIZE = 1024 * 1024;
275
+ restartCount = 0;
276
+ restartTimer = null;
277
+ CadConnection = class {
278
+ constructor() {
279
+ this.connected = false;
280
+ this.version = null;
281
+ this.product = null;
282
+ }
283
+ isAvailable() {
284
+ return process.platform === "win32";
285
+ }
286
+ async connect(platform = null) {
287
+ if (!this.isAvailable()) return false;
288
+ try {
289
+ const msg = platform ? { type: "connect", platform } : { type: "connect" };
290
+ const result = await sendMessage(msg);
291
+ if (result && result.success) {
292
+ this.version = result.version;
293
+ this.product = result.platform;
294
+ _platform = result.platform;
295
+ this.connected = true;
296
+ return true;
297
+ }
298
+ } catch (e) {
299
+ console.error("CAD connect error:", e.message);
300
+ }
301
+ return false;
302
+ }
303
+ async sendCommand(code) {
304
+ if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
305
+ const result = await sendMessage({ type: "send", code, platform: _platform });
306
+ if (result.success) return true;
307
+ throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
308
+ }
309
+ async sendCommandWithResult(code, encoding = null) {
310
+ if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
311
+ const result = await sendMessage({ type: "sendResult", code, platform: _platform, encoding: encoding || "" });
312
+ if (result.success) {
313
+ return result.result || "";
314
+ }
315
+ throw new Error(result.error || "\u53D1\u9001\u5931\u8D25");
316
+ }
317
+ getVersion() {
318
+ return this.version;
319
+ }
320
+ getPlatform() {
321
+ return this.product;
322
+ }
323
+ async isBusy() {
324
+ if (!this.connected) return false;
325
+ try {
326
+ const result = await sendMessage({ type: "isBusy", platform: _platform });
327
+ return result && result.isBusy;
328
+ } catch (e) {
329
+ return false;
330
+ }
331
+ }
332
+ async hasDoc() {
333
+ if (!this.connected) return { hasDoc: false, docCount: 0 };
334
+ try {
335
+ const result = await sendMessage({ type: "hasdoc", platform: _platform });
336
+ return result || { hasDoc: false, docCount: 0 };
337
+ } catch (e) {
338
+ return { hasDoc: false, docCount: 0 };
339
+ }
340
+ }
341
+ async newDoc() {
342
+ if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
343
+ try {
344
+ const result = await sendMessage({ type: "newdoc", platform: _platform });
345
+ return result && result.success;
346
+ } catch (e) {
347
+ return false;
348
+ }
349
+ }
350
+ async bringToFront() {
351
+ if (!this.connected) throw new Error("\u672A\u8FDE\u63A5 CAD");
352
+ try {
353
+ const result = await sendMessage({ type: "bringToFront", platform: _platform });
354
+ return result && result.success;
355
+ } catch (e) {
356
+ return false;
357
+ }
358
+ }
359
+ async getInfo() {
360
+ if (!this.connected) return "CAD \u672A\u8FDE\u63A5";
361
+ return `Platform: ${this.product}, Version: ${this.version}, Status: Connected`;
362
+ }
363
+ async disconnect() {
364
+ this.connected = false;
365
+ this.version = null;
366
+ this.product = null;
367
+ _platform = null;
368
+ resetWorker();
369
+ }
370
+ async ping() {
371
+ try {
372
+ const result = await sendMessage({ type: "ping" });
373
+ return result && result.pong;
374
+ } catch (e) {
375
+ return false;
376
+ }
377
+ }
378
+ _reset() {
379
+ this.connected = false;
380
+ this.version = null;
381
+ this.product = null;
382
+ _platform = null;
383
+ resetWorker();
384
+ }
385
+ };
386
+ cad = new CadConnection();
437
387
  }
438
- };
439
- var cad = new CadConnection();
388
+ });
440
389
 
441
390
  // src/logger.js
442
391
  import fs from "fs";
443
392
  import path2 from "path";
444
393
  import os from "os";
445
- var DEBUG_FILE = process.env.DEBUG_FILE || path2.join(os.tmpdir(), "mcp-server-debug.log");
446
- var MAX_LOG_SIZE = 10 * 1024 * 1024;
447
- var MAX_LOG_FILES = 5;
448
- var stream = null;
449
394
  function rotateLog() {
450
395
  if (!fs.existsSync(DEBUG_FILE)) return;
451
396
  const stat = fs.statSync(DEBUG_FILE);
@@ -476,10 +421,27 @@ function getStream() {
476
421
  }
477
422
  return stream;
478
423
  }
479
- function log(msg) {
480
- const entry = `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
481
- `;
482
- getStream().write(entry);
424
+ function formatMessage(level, message, meta = {}) {
425
+ const entry = {
426
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
427
+ level,
428
+ message,
429
+ ...meta,
430
+ pid: process.pid,
431
+ hostname: os.hostname()
432
+ };
433
+ return JSON.stringify(entry);
434
+ }
435
+ function log(message, meta = {}) {
436
+ if (config_default.debug) {
437
+ getStream().write(formatMessage("INFO", message, meta) + "\n");
438
+ }
439
+ }
440
+ function error(message, meta = {}) {
441
+ getStream().write(formatMessage("ERROR", message, meta) + "\n");
442
+ if (config_default.debug) {
443
+ console.error(`[ERROR] ${message}`, meta);
444
+ }
483
445
  }
484
446
  function closeLog() {
485
447
  if (stream) {
@@ -487,6 +449,16 @@ function closeLog() {
487
449
  stream = null;
488
450
  }
489
451
  }
452
+ var DEBUG_FILE, MAX_LOG_SIZE, MAX_LOG_FILES, stream;
453
+ var init_logger = __esm({
454
+ "src/logger.js"() {
455
+ init_config();
456
+ DEBUG_FILE = config_default.debugFile || path2.join(os.tmpdir(), "mcp-server-debug.log");
457
+ MAX_LOG_SIZE = 10 * 1024 * 1024;
458
+ MAX_LOG_FILES = 5;
459
+ stream = null;
460
+ }
461
+ });
490
462
 
491
463
  // src/handlers/cad-handlers.js
492
464
  async function connectCad(platform = null) {
@@ -651,12 +623,14 @@ async function initAtlisp() {
651
623
  return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
652
624
  }
653
625
  }
626
+ var init_cad_handlers = __esm({
627
+ "src/handlers/cad-handlers.js"() {
628
+ init_cad();
629
+ init_logger();
630
+ }
631
+ });
654
632
 
655
633
  // src/handlers/package-handlers.js
656
- var PACKAGES_LIST_URL = process.env.PACKAGES_LIST_URL || "http://s3.atlisp.cn/packages-list?fmt=json";
657
- var cachedPackages = null;
658
- var cachedAt = null;
659
- var CACHE_TTL = 10 * 60 * 1e3;
660
634
  async function fetchPackages() {
661
635
  const now = Date.now();
662
636
  if (cachedPackages && cachedAt && now - cachedAt < CACHE_TTL) {
@@ -732,16 +706,22 @@ async function installPackage(packageName) {
732
706
  }
733
707
  return { content: [{ type: "text", text: `\u5305 "${packageName}" \u5B89\u88C5\u547D\u4EE4\u5DF2\u53D1\u9001\uFF01` }] };
734
708
  }
709
+ var PACKAGES_LIST_URL, cachedPackages, cachedAt, CACHE_TTL;
710
+ var init_package_handlers = __esm({
711
+ "src/handlers/package-handlers.js"() {
712
+ init_cad();
713
+ init_constants();
714
+ PACKAGES_LIST_URL = process.env.PACKAGES_LIST_URL || "http://s3.atlisp.cn/packages-list?fmt=json";
715
+ cachedPackages = null;
716
+ cachedAt = null;
717
+ CACHE_TTL = 10 * 60 * 1e3;
718
+ }
719
+ });
735
720
 
736
721
  // src/handlers/function-handlers.js
737
722
  import fs2 from "fs";
738
723
  import path3 from "path";
739
724
  import os2 from "os";
740
- var FUNCTIONS_DIR = process.env.FUNCTIONS_DIR || "";
741
- var FUNCTIONS_URL = process.env.FUNCTIONS_URL || "http://s3.atlisp.cn/json/functions.json";
742
- var CACHE_DIR = path3.join(os2.homedir(), ".atlisp", "cache");
743
- var FUNCLIB_CACHE_FILE = path3.join(CACHE_DIR, "functions.json");
744
- var FUNCLIB_CACHE_TTL = 24 * 60 * 60 * 1e3;
745
725
  function readCacheFromDisk() {
746
726
  try {
747
727
  const stat = fs2.statSync(FUNCLIB_CACHE_FILE);
@@ -854,15 +834,23 @@ ${allFuncs.map((f) => f.name).join("\n")}` }] };
854
834
  return { content: [{ type: "text", text: `\u9519\u8BEF: ${e.message}` }], isError: true };
855
835
  }
856
836
  }
837
+ var FUNCTIONS_DIR, FUNCTIONS_URL, CACHE_DIR, FUNCLIB_CACHE_FILE, FUNCLIB_CACHE_TTL;
838
+ var init_function_handlers = __esm({
839
+ "src/handlers/function-handlers.js"() {
840
+ init_logger();
841
+ init_cad_handlers();
842
+ FUNCTIONS_DIR = process.env.FUNCTIONS_DIR || "";
843
+ FUNCTIONS_URL = process.env.FUNCTIONS_URL || "http://s3.atlisp.cn/json/functions.json";
844
+ CACHE_DIR = path3.join(os2.homedir(), ".atlisp", "cache");
845
+ FUNCLIB_CACHE_FILE = path3.join(CACHE_DIR, "functions.json");
846
+ FUNCLIB_CACHE_TTL = 24 * 60 * 60 * 1e3;
847
+ }
848
+ });
857
849
 
858
850
  // src/handlers/resource-handlers.js
859
851
  import fs3 from "fs";
860
852
  import path4 from "path";
861
853
  import { fileURLToPath as fileURLToPath2 } from "url";
862
- var __dirname2 = path4.dirname(fileURLToPath2(import.meta.url));
863
- var STANDARDS_DIR = path4.join(__dirname2, "..", "standards");
864
- var CACHE_TTL2 = config_default.resourceCacheTtl;
865
- var resourceCache = /* @__PURE__ */ new Map();
866
854
  function getCached(key) {
867
855
  const entry = resourceCache.get(key);
868
856
  if (entry && Date.now() - entry.timestamp < CACHE_TTL2) {
@@ -1143,19 +1131,6 @@ function buildTextCode({ layer, bbox, offset, limit }) {
1143
1131
  (@t:run))
1144
1132
  `;
1145
1133
  }
1146
- var RESOURCES = [
1147
- { uri: "atlisp://cad/info", name: "CAD Info", description: "CAD \u8FDE\u63A5\u4FE1\u606F", mimeType: "application/json", subscribable: true },
1148
- { uri: "atlisp://dwg/layers", name: "Layers", description: "\u56FE\u5C42\u5217\u8868", mimeType: "application/json", subscribable: true },
1149
- { uri: "atlisp://dwg/entities", name: "Entities", description: "\u56FE\u5143\u5217\u8868\uFF0C\u8FD4\u56DE\u603B\u6570\u548C\u524D3000\u4E2A\u56FE\u5143\uFF0C\u6587\u672C\u9644\u52A0 text \u5B57\u6BB5\uFF0C\u66F2\u7EBF\u9644\u52A0 points \u6570\u7EC4\uFF0CINSERT \u9644\u52A0 blockName\uFF0C\u652F\u6301 ?type=LINE&layer=0&bbox=0,0,100,100 \u8FC7\u6EE4", mimeType: "application/json", subscribable: true },
1150
- { uri: "atlisp://dwg/texts", name: "Texts", description: "\u6587\u672C\u5B9E\u4F53\u5185\u5BB9\u5217\u8868 (TEXT/MTEXT/ATTRIB/TCH_TEXT)\uFF0C\u652F\u6301 ?layer=0&bbox=0,0,100,100&limit=5000&offset=0", mimeType: "application/json", subscribable: true },
1151
- { uri: "atlisp://dwg/name", name: "DWG Name", description: "\u5F53\u524D DWG \u6587\u4EF6\u540D", mimeType: "application/json", subscribable: true },
1152
- { uri: "atlisp://dwg/path", name: "DWG Path", description: "\u6587\u4EF6\u5B8C\u6574\u8DEF\u5F84", mimeType: "application/json", subscribable: true },
1153
- { uri: "atlisp://cad/dwgs", name: "DWG List", description: "\u6240\u6709\u6253\u5F00\u7684 DWG \u6587\u4EF6\u5217\u8868", mimeType: "application/json", subscribable: true },
1154
- { uri: "atlisp://packages", name: "Packages", description: "\u5DF2\u5B89\u88C5\u5305\u5217\u8868", mimeType: "application/json", subscribable: true },
1155
- { uri: "atlisp://platforms", name: "Platforms", description: "\u652F\u6301\u7684\u5E73\u53F0\u4FE1\u606F", mimeType: "application/json", subscribable: false },
1156
- { uri: "atlisp://standards/drafting", name: "Drafting Standards", description: "CAD \u5236\u56FE\u89C4\u8303", mimeType: "application/json", subscribable: false },
1157
- { uri: "atlisp://standards/coding", name: "Coding Standards", description: "@lisp \u7F16\u7801\u89C4\u8303", mimeType: "application/json", subscribable: false }
1158
- ];
1159
1134
  function parseQuery(uri) {
1160
1135
  const qIdx = uri.indexOf("?");
1161
1136
  if (qIdx === -1) return { base: uri, params: {} };
@@ -1534,7 +1509,6 @@ function loadStandardsFile(filename) {
1534
1509
  return null;
1535
1510
  }
1536
1511
  }
1537
- var standardsCache = /* @__PURE__ */ new Map();
1538
1512
  function getCachedStandards(key) {
1539
1513
  const entry = standardsCache.get(key);
1540
1514
  if (entry && Date.now() - entry.timestamp < 3e4) return entry.data;
@@ -1558,16 +1532,38 @@ function getCodingStandards() {
1558
1532
  if (data) setCachedStandards("coding", data);
1559
1533
  return data || { error: "\u7F16\u7801\u89C4\u8303\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25" };
1560
1534
  }
1535
+ var __dirname2, STANDARDS_DIR, CACHE_TTL2, resourceCache, RESOURCES, standardsCache;
1536
+ var init_resource_handlers = __esm({
1537
+ "src/handlers/resource-handlers.js"() {
1538
+ init_cad();
1539
+ init_constants();
1540
+ init_logger();
1541
+ init_config();
1542
+ __dirname2 = path4.dirname(fileURLToPath2(import.meta.url));
1543
+ STANDARDS_DIR = path4.join(__dirname2, "..", "standards");
1544
+ CACHE_TTL2 = config_default.resourceCacheTtl;
1545
+ resourceCache = /* @__PURE__ */ new Map();
1546
+ RESOURCES = [
1547
+ { uri: "atlisp://cad/info", name: "CAD Info", description: "CAD \u8FDE\u63A5\u4FE1\u606F", mimeType: "application/json", subscribable: true },
1548
+ { uri: "atlisp://dwg/layers", name: "Layers", description: "\u56FE\u5C42\u5217\u8868", mimeType: "application/json", subscribable: true },
1549
+ { uri: "atlisp://dwg/entities", name: "Entities", description: "\u56FE\u5143\u5217\u8868\uFF0C\u8FD4\u56DE\u603B\u6570\u548C\u524D3000\u4E2A\u56FE\u5143\uFF0C\u6587\u672C\u9644\u52A0 text \u5B57\u6BB5\uFF0C\u66F2\u7EBF\u9644\u52A0 points \u6570\u7EC4\uFF0CINSERT \u9644\u52A0 blockName\uFF0C\u652F\u6301 ?type=LINE&layer=0&bbox=0,0,100,100 \u8FC7\u6EE4", mimeType: "application/json", subscribable: true },
1550
+ { uri: "atlisp://dwg/texts", name: "Texts", description: "\u6587\u672C\u5B9E\u4F53\u5185\u5BB9\u5217\u8868 (TEXT/MTEXT/ATTRIB/TCH_TEXT)\uFF0C\u652F\u6301 ?layer=0&bbox=0,0,100,100&limit=5000&offset=0", mimeType: "application/json", subscribable: true },
1551
+ { uri: "atlisp://dwg/name", name: "DWG Name", description: "\u5F53\u524D DWG \u6587\u4EF6\u540D", mimeType: "application/json", subscribable: true },
1552
+ { uri: "atlisp://dwg/path", name: "DWG Path", description: "\u6587\u4EF6\u5B8C\u6574\u8DEF\u5F84", mimeType: "application/json", subscribable: true },
1553
+ { uri: "atlisp://cad/dwgs", name: "DWG List", description: "\u6240\u6709\u6253\u5F00\u7684 DWG \u6587\u4EF6\u5217\u8868", mimeType: "application/json", subscribable: true },
1554
+ { uri: "atlisp://packages", name: "Packages", description: "\u5DF2\u5B89\u88C5\u5305\u5217\u8868", mimeType: "application/json", subscribable: true },
1555
+ { uri: "atlisp://platforms", name: "Platforms", description: "\u652F\u6301\u7684\u5E73\u53F0\u4FE1\u606F", mimeType: "application/json", subscribable: false },
1556
+ { uri: "atlisp://standards/drafting", name: "Drafting Standards", description: "CAD \u5236\u56FE\u89C4\u8303", mimeType: "application/json", subscribable: false },
1557
+ { uri: "atlisp://standards/coding", name: "Coding Standards", description: "@lisp \u7F16\u7801\u89C4\u8303", mimeType: "application/json", subscribable: false }
1558
+ ];
1559
+ standardsCache = /* @__PURE__ */ new Map();
1560
+ }
1561
+ });
1561
1562
 
1562
1563
  // src/handlers/prompt-handlers.js
1563
1564
  import fs4 from "fs";
1564
1565
  import path5 from "path";
1565
1566
  import { fileURLToPath as fileURLToPath3 } from "url";
1566
- var __dirname3 = path5.dirname(fileURLToPath3(import.meta.url));
1567
- var PROMPTS_DIR = path5.join(__dirname3, "..", "prompts");
1568
- var externalPrompts = null;
1569
- var externalPromptsAt = 0;
1570
- var EXTERNAL_PROMPTS_TTL = 3e4;
1571
1567
  function loadExternalPrompts() {
1572
1568
  const now = Date.now();
1573
1569
  if (externalPrompts && now - externalPromptsAt < EXTERNAL_PROMPTS_TTL) {
@@ -1597,121 +1593,6 @@ function loadExternalPrompts() {
1597
1593
  externalPromptsAt = now;
1598
1594
  return externalPrompts;
1599
1595
  }
1600
- var PROMPTS = [
1601
- {
1602
- name: "analyze-drawing",
1603
- description: "\u5206\u6790\u5F53\u524D\u56FE\u7EB8\u7EDF\u8BA1\u4FE1\u606F",
1604
- arguments: []
1605
- },
1606
- {
1607
- name: "batch-draw-lines",
1608
- description: "\u6279\u91CF\u7ED8\u5236\u7EBF\u6BB5",
1609
- arguments: [
1610
- { name: "count", description: "\u7EBF\u6BB5\u6570\u91CF", required: true },
1611
- { name: "length", description: "\u7EBF\u6BB5\u957F\u5EA6", required: false }
1612
- ]
1613
- },
1614
- {
1615
- name: "generate-dimension",
1616
- description: "\u751F\u6210\u5C3A\u5BF8\u6807\u6CE8",
1617
- arguments: [
1618
- { name: "style", description: "\u6807\u6CE8\u6837\u5F0F (horizontal/vertical/aligned)", required: false }
1619
- ]
1620
- },
1621
- {
1622
- name: "export-entities",
1623
- description: "\u5BFC\u51FA\u56FE\u7EB8\u5B9E\u4F53\u7EDF\u8BA1",
1624
- arguments: [
1625
- { name: "format", description: "\u5BFC\u51FA\u683C\u5F0F (json/list)", required: false }
1626
- ]
1627
- },
1628
- {
1629
- name: "manage-layers",
1630
- description: "\u56FE\u5C42\u7BA1\u7406\uFF1A\u521B\u5EFA\u3001\u51BB\u7ED3\u3001\u9501\u5B9A\u3001\u5220\u9664\u56FE\u5C42",
1631
- arguments: [
1632
- { name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/freeze/lock/off/make/delete)", required: true },
1633
- { name: "layers", description: "\u56FE\u5C42\u540D\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694", required: false },
1634
- { name: "color", description: '\u56FE\u5C42\u989C\u8272 (ACI\u53F7\u6216RGB\u5982 "1,2,3")', required: false }
1635
- ]
1636
- },
1637
- {
1638
- name: "manage-blocks",
1639
- description: "\u5757\u64CD\u4F5C\uFF1A\u63D2\u5165\u5757\u3001\u5217\u51FA\u5757\u3001\u83B7\u53D6/\u8BBE\u7F6E\u5C5E\u6027",
1640
- arguments: [
1641
- { name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/insert/attributes/dynprops)", required: true },
1642
- { name: "blockName", description: "\u5757\u540D", required: false },
1643
- { name: "insertPoint", description: '\u63D2\u5165\u70B9 "x,y"', required: false },
1644
- { name: "scale", description: "\u7F29\u653E\u6BD4\u4F8B", required: false }
1645
- ]
1646
- },
1647
- {
1648
- name: "curve-analysis",
1649
- description: "\u66F2\u7EBF\u5206\u6790\uFF1A\u4EA4\u70B9\u3001\u6700\u8FD1\u70B9\u3001\u5B50\u6BB5\u3001\u7F13\u51B2\u533A",
1650
- arguments: [
1651
- { name: "action", description: "\u64CD\u4F5C (inters/subsegments/closestpoint/join)", required: true },
1652
- { name: "distance", description: "\u8FDE\u63A5\u5BB9\u5DEE/\u504F\u79FB\u8DDD\u79BB", required: false }
1653
- ]
1654
- },
1655
- {
1656
- name: "geometry-calc",
1657
- description: "\u51E0\u4F55\u8BA1\u7B97\uFF1A\u51F8\u5305\u3001\u70B9\u5230\u7EBF\u8DDD\u79BB\u3001\u9762\u5185\u6D4B\u8BD5\u3001\u53D8\u6362",
1658
- arguments: [
1659
- { name: "action", description: "\u64CD\u4F5C (convexhull/dist-point-line/in-curve-p/transform/centroid)", required: true },
1660
- { name: "points", description: '\u70B9\u96C6 "x1,y1;x2,y2;..."', required: false }
1661
- ]
1662
- },
1663
- {
1664
- name: "text-process",
1665
- description: "\u6587\u672C\u5904\u7406\uFF1AMTEXT\u89E3\u6790\u3001Markdown\u8F6CMTEXT\u3001\u53BB\u683C\u5F0F",
1666
- arguments: [
1667
- { name: "action", description: "\u64CD\u4F5C (parse-mtext/remove-fmt/from-markdown/mtext2text)", required: true },
1668
- { name: "markdown", description: "Markdown\u6587\u672C\uFF08from-markdown\u64CD\u4F5C\u65F6\u7528\uFF09", required: false }
1669
- ]
1670
- },
1671
- {
1672
- name: "pickset-filter",
1673
- description: "\u9009\u62E9\u96C6\u64CD\u4F5C\uFF1A\u8FC7\u6EE4\u3001\u8F6C\u6362\u3001\u6279\u91CF\u64CD\u4F5C",
1674
- arguments: [
1675
- { name: "action", description: "\u64CD\u4F5C (by-layer/by-type/by-box/erase/zoom)", required: true },
1676
- { name: "dxfType", description: 'DXF\u7C7B\u578B "LINE, CIRCLE, LWPOLYLINE, INSERT, TEXT"', required: false },
1677
- { name: "layerName", description: "\u56FE\u5C42\u540D", required: false }
1678
- ]
1679
- },
1680
- {
1681
- name: "color-convert",
1682
- description: "\u989C\u8272\u8F6C\u6362\uFF1AACI/RGB/TrueColor/CSS\u4E92\u8F6C",
1683
- arguments: [
1684
- { name: "action", description: "\u64CD\u4F5C (aci2rgb/rgb2css/truecolor2rgb/rgb2truecolor)", required: true },
1685
- { name: "value", description: "\u989C\u8272\u503C", required: true }
1686
- ]
1687
- },
1688
- {
1689
- name: "json-exchange",
1690
- description: "JSON\u6570\u636E\u4EA4\u6362\uFF1A\u4ECE\u5B57\u7B26\u4E32\u89E3\u6790JSON alist\uFF0C\u4ECEalist\u751F\u6210JSON",
1691
- arguments: [
1692
- { name: "action", description: "\u64CD\u4F5C (encode/decode)", required: true },
1693
- { name: "data", description: "JSON\u5B57\u7B26\u4E32\u6216Lisp alist\u6587\u672C", required: true }
1694
- ]
1695
- },
1696
- {
1697
- name: "excel-report",
1698
- description: "Excel\u62A5\u8868\uFF1A\u5BFC\u51FACAD\u5B9E\u4F53\u6570\u636E\u5230Excel",
1699
- arguments: [
1700
- { name: "visible", description: "\u662F\u5426\u663E\u793AExcel\u7A97\u53E3 (true/false)", required: false },
1701
- { name: "savePath", description: "\u4FDD\u5B58\u8DEF\u5F84\uFF0C\u4E0D\u586B\u5219\u4E0D\u4FDD\u5B58", required: false }
1702
- ]
1703
- },
1704
- {
1705
- name: "string-process",
1706
- description: "\u5B57\u7B26\u4E32\u5904\u7406\uFF1A\u683C\u5F0F\u5316\u3001\u62C6\u5206\u3001\u66FF\u6362\u3001\u6B63\u5219",
1707
- arguments: [
1708
- { name: "action", description: "\u64CD\u4F5C (format/split/subst-all/regexp/trim/number2chinese)", required: true },
1709
- { name: "input", description: "\u8F93\u5165\u5B57\u7B26\u4E32", required: true },
1710
- { name: "arg1", description: "\u53C2\u65701\uFF08\u683C\u5F0F\u53C2\u6570/\u5206\u9694\u7B26/\u65E7\u4E32\uFF09", required: false },
1711
- { name: "arg2", description: "\u53C2\u65702\uFF08\u65B0\u4E32/\u6B63\u5219\u6A21\u5F0F\uFF09", required: false }
1712
- ]
1713
- }
1714
- ];
1715
1596
  function findExternalPrompt(name) {
1716
1597
  const ext = loadExternalPrompts();
1717
1598
  return ext.find((p) => p.name === name);
@@ -2328,86 +2209,215 @@ ${code}
2328
2209
  }]
2329
2210
  };
2330
2211
  }
2212
+ var __dirname3, PROMPTS_DIR, externalPrompts, externalPromptsAt, EXTERNAL_PROMPTS_TTL, PROMPTS;
2213
+ var init_prompt_handlers = __esm({
2214
+ "src/handlers/prompt-handlers.js"() {
2215
+ init_cad();
2216
+ __dirname3 = path5.dirname(fileURLToPath3(import.meta.url));
2217
+ PROMPTS_DIR = path5.join(__dirname3, "..", "prompts");
2218
+ externalPrompts = null;
2219
+ externalPromptsAt = 0;
2220
+ EXTERNAL_PROMPTS_TTL = 3e4;
2221
+ PROMPTS = [
2222
+ {
2223
+ name: "analyze-drawing",
2224
+ description: "\u5206\u6790\u5F53\u524D\u56FE\u7EB8\u7EDF\u8BA1\u4FE1\u606F",
2225
+ arguments: []
2226
+ },
2227
+ {
2228
+ name: "batch-draw-lines",
2229
+ description: "\u6279\u91CF\u7ED8\u5236\u7EBF\u6BB5",
2230
+ arguments: [
2231
+ { name: "count", description: "\u7EBF\u6BB5\u6570\u91CF", required: true },
2232
+ { name: "length", description: "\u7EBF\u6BB5\u957F\u5EA6", required: false }
2233
+ ]
2234
+ },
2235
+ {
2236
+ name: "generate-dimension",
2237
+ description: "\u751F\u6210\u5C3A\u5BF8\u6807\u6CE8",
2238
+ arguments: [
2239
+ { name: "style", description: "\u6807\u6CE8\u6837\u5F0F (horizontal/vertical/aligned)", required: false }
2240
+ ]
2241
+ },
2242
+ {
2243
+ name: "export-entities",
2244
+ description: "\u5BFC\u51FA\u56FE\u7EB8\u5B9E\u4F53\u7EDF\u8BA1",
2245
+ arguments: [
2246
+ { name: "format", description: "\u5BFC\u51FA\u683C\u5F0F (json/list)", required: false }
2247
+ ]
2248
+ },
2249
+ {
2250
+ name: "manage-layers",
2251
+ description: "\u56FE\u5C42\u7BA1\u7406\uFF1A\u521B\u5EFA\u3001\u51BB\u7ED3\u3001\u9501\u5B9A\u3001\u5220\u9664\u56FE\u5C42",
2252
+ arguments: [
2253
+ { name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/freeze/lock/off/make/delete)", required: true },
2254
+ { name: "layers", description: "\u56FE\u5C42\u540D\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694", required: false },
2255
+ { name: "color", description: '\u56FE\u5C42\u989C\u8272 (ACI\u53F7\u6216RGB\u5982 "1,2,3")', required: false }
2256
+ ]
2257
+ },
2258
+ {
2259
+ name: "manage-blocks",
2260
+ description: "\u5757\u64CD\u4F5C\uFF1A\u63D2\u5165\u5757\u3001\u5217\u51FA\u5757\u3001\u83B7\u53D6/\u8BBE\u7F6E\u5C5E\u6027",
2261
+ arguments: [
2262
+ { name: "action", description: "\u64CD\u4F5C\u7C7B\u578B (list/insert/attributes/dynprops)", required: true },
2263
+ { name: "blockName", description: "\u5757\u540D", required: false },
2264
+ { name: "insertPoint", description: '\u63D2\u5165\u70B9 "x,y"', required: false },
2265
+ { name: "scale", description: "\u7F29\u653E\u6BD4\u4F8B", required: false }
2266
+ ]
2267
+ },
2268
+ {
2269
+ name: "curve-analysis",
2270
+ description: "\u66F2\u7EBF\u5206\u6790\uFF1A\u4EA4\u70B9\u3001\u6700\u8FD1\u70B9\u3001\u5B50\u6BB5\u3001\u7F13\u51B2\u533A",
2271
+ arguments: [
2272
+ { name: "action", description: "\u64CD\u4F5C (inters/subsegments/closestpoint/join)", required: true },
2273
+ { name: "distance", description: "\u8FDE\u63A5\u5BB9\u5DEE/\u504F\u79FB\u8DDD\u79BB", required: false }
2274
+ ]
2275
+ },
2276
+ {
2277
+ name: "geometry-calc",
2278
+ description: "\u51E0\u4F55\u8BA1\u7B97\uFF1A\u51F8\u5305\u3001\u70B9\u5230\u7EBF\u8DDD\u79BB\u3001\u9762\u5185\u6D4B\u8BD5\u3001\u53D8\u6362",
2279
+ arguments: [
2280
+ { name: "action", description: "\u64CD\u4F5C (convexhull/dist-point-line/in-curve-p/transform/centroid)", required: true },
2281
+ { name: "points", description: '\u70B9\u96C6 "x1,y1;x2,y2;..."', required: false }
2282
+ ]
2283
+ },
2284
+ {
2285
+ name: "text-process",
2286
+ description: "\u6587\u672C\u5904\u7406\uFF1AMTEXT\u89E3\u6790\u3001Markdown\u8F6CMTEXT\u3001\u53BB\u683C\u5F0F",
2287
+ arguments: [
2288
+ { name: "action", description: "\u64CD\u4F5C (parse-mtext/remove-fmt/from-markdown/mtext2text)", required: true },
2289
+ { name: "markdown", description: "Markdown\u6587\u672C\uFF08from-markdown\u64CD\u4F5C\u65F6\u7528\uFF09", required: false }
2290
+ ]
2291
+ },
2292
+ {
2293
+ name: "pickset-filter",
2294
+ description: "\u9009\u62E9\u96C6\u64CD\u4F5C\uFF1A\u8FC7\u6EE4\u3001\u8F6C\u6362\u3001\u6279\u91CF\u64CD\u4F5C",
2295
+ arguments: [
2296
+ { name: "action", description: "\u64CD\u4F5C (by-layer/by-type/by-box/erase/zoom)", required: true },
2297
+ { name: "dxfType", description: 'DXF\u7C7B\u578B "LINE, CIRCLE, LWPOLYLINE, INSERT, TEXT"', required: false },
2298
+ { name: "layerName", description: "\u56FE\u5C42\u540D", required: false }
2299
+ ]
2300
+ },
2301
+ {
2302
+ name: "color-convert",
2303
+ description: "\u989C\u8272\u8F6C\u6362\uFF1AACI/RGB/TrueColor/CSS\u4E92\u8F6C",
2304
+ arguments: [
2305
+ { name: "action", description: "\u64CD\u4F5C (aci2rgb/rgb2css/truecolor2rgb/rgb2truecolor)", required: true },
2306
+ { name: "value", description: "\u989C\u8272\u503C", required: true }
2307
+ ]
2308
+ },
2309
+ {
2310
+ name: "json-exchange",
2311
+ description: "JSON\u6570\u636E\u4EA4\u6362\uFF1A\u4ECE\u5B57\u7B26\u4E32\u89E3\u6790JSON alist\uFF0C\u4ECEalist\u751F\u6210JSON",
2312
+ arguments: [
2313
+ { name: "action", description: "\u64CD\u4F5C (encode/decode)", required: true },
2314
+ { name: "data", description: "JSON\u5B57\u7B26\u4E32\u6216Lisp alist\u6587\u672C", required: true }
2315
+ ]
2316
+ },
2317
+ {
2318
+ name: "excel-report",
2319
+ description: "Excel\u62A5\u8868\uFF1A\u5BFC\u51FACAD\u5B9E\u4F53\u6570\u636E\u5230Excel",
2320
+ arguments: [
2321
+ { name: "visible", description: "\u662F\u5426\u663E\u793AExcel\u7A97\u53E3 (true/false)", required: false },
2322
+ { name: "savePath", description: "\u4FDD\u5B58\u8DEF\u5F84\uFF0C\u4E0D\u586B\u5219\u4E0D\u4FDD\u5B58", required: false }
2323
+ ]
2324
+ },
2325
+ {
2326
+ name: "string-process",
2327
+ description: "\u5B57\u7B26\u4E32\u5904\u7406\uFF1A\u683C\u5F0F\u5316\u3001\u62C6\u5206\u3001\u66FF\u6362\u3001\u6B63\u5219",
2328
+ arguments: [
2329
+ { name: "action", description: "\u64CD\u4F5C (format/split/subst-all/regexp/trim/number2chinese)", required: true },
2330
+ { name: "input", description: "\u8F93\u5165\u5B57\u7B26\u4E32", required: true },
2331
+ { name: "arg1", description: "\u53C2\u65701\uFF08\u683C\u5F0F\u53C2\u6570/\u5206\u9694\u7B26/\u65E7\u4E32\uFF09", required: false },
2332
+ { name: "arg2", description: "\u53C2\u65702\uFF08\u65B0\u4E32/\u6B63\u5219\u6A21\u5F0F\uFF09", required: false }
2333
+ ]
2334
+ }
2335
+ ];
2336
+ }
2337
+ });
2331
2338
 
2332
2339
  // src/session-manager.js
2333
- var Session = class {
2334
- constructor(clientId) {
2335
- this.clientId = clientId;
2336
- this.subscriptions = /* @__PURE__ */ new Set();
2337
- this.createdAt = Date.now();
2338
- this.connected = false;
2339
- }
2340
- };
2341
- var SessionManager = class {
2342
- #sessions = /* @__PURE__ */ new Map();
2343
- createSession(clientId) {
2344
- let session = this.#sessions.get(clientId);
2345
- if (!session) {
2346
- session = new Session(clientId);
2347
- this.#sessions.set(clientId, session);
2348
- }
2349
- return session;
2350
- }
2351
- getSession(clientId) {
2352
- return this.#sessions.get(clientId) || null;
2353
- }
2354
- hasSession(clientId) {
2355
- return this.#sessions.has(clientId);
2356
- }
2357
- removeSession(clientId) {
2358
- return this.#sessions.delete(clientId);
2359
- }
2360
- subscribe(clientId, uri) {
2361
- const session = this.#sessions.get(clientId);
2362
- if (session) {
2363
- session.subscriptions.add(uri);
2364
- return true;
2365
- }
2366
- return false;
2367
- }
2368
- unsubscribe(clientId, uri) {
2369
- const session = this.#sessions.get(clientId);
2370
- if (session) {
2371
- return session.subscriptions.delete(uri);
2372
- }
2373
- return false;
2374
- }
2375
- getSubscriptions(clientId) {
2376
- const session = this.#sessions.get(clientId);
2377
- return session ? Array.from(session.subscriptions) : [];
2378
- }
2379
- isSubscribed(clientId, uri) {
2380
- const session = this.#sessions.get(clientId);
2381
- return session ? session.subscriptions.has(uri) : false;
2382
- }
2383
- getAllSubscribedUris() {
2384
- const all = /* @__PURE__ */ new Set();
2385
- for (const session of this.#sessions.values()) {
2386
- for (const uri of session.subscriptions) {
2387
- all.add(uri);
2340
+ var Session, SessionManager;
2341
+ var init_session_manager = __esm({
2342
+ "src/session-manager.js"() {
2343
+ Session = class {
2344
+ constructor(clientId) {
2345
+ this.clientId = clientId;
2346
+ this.subscriptions = /* @__PURE__ */ new Set();
2347
+ this.createdAt = Date.now();
2348
+ this.connected = false;
2388
2349
  }
2389
- }
2390
- return all;
2391
- }
2392
- list() {
2393
- return Array.from(this.#sessions.entries()).map(([id, s]) => ({
2394
- clientId: id,
2395
- subscriptions: Array.from(s.subscriptions),
2396
- createdAt: s.createdAt,
2397
- connected: s.connected
2398
- }));
2399
- }
2400
- count() {
2401
- return this.#sessions.size;
2402
- }
2403
- clear() {
2404
- this.#sessions.clear();
2350
+ };
2351
+ SessionManager = class {
2352
+ #sessions = /* @__PURE__ */ new Map();
2353
+ createSession(clientId) {
2354
+ let session = this.#sessions.get(clientId);
2355
+ if (!session) {
2356
+ session = new Session(clientId);
2357
+ this.#sessions.set(clientId, session);
2358
+ }
2359
+ return session;
2360
+ }
2361
+ getSession(clientId) {
2362
+ return this.#sessions.get(clientId) || null;
2363
+ }
2364
+ hasSession(clientId) {
2365
+ return this.#sessions.has(clientId);
2366
+ }
2367
+ removeSession(clientId) {
2368
+ return this.#sessions.delete(clientId);
2369
+ }
2370
+ subscribe(clientId, uri) {
2371
+ const session = this.#sessions.get(clientId);
2372
+ if (session) {
2373
+ session.subscriptions.add(uri);
2374
+ return true;
2375
+ }
2376
+ return false;
2377
+ }
2378
+ unsubscribe(clientId, uri) {
2379
+ const session = this.#sessions.get(clientId);
2380
+ if (session) {
2381
+ return session.subscriptions.delete(uri);
2382
+ }
2383
+ return false;
2384
+ }
2385
+ getSubscriptions(clientId) {
2386
+ const session = this.#sessions.get(clientId);
2387
+ return session ? Array.from(session.subscriptions) : [];
2388
+ }
2389
+ isSubscribed(clientId, uri) {
2390
+ const session = this.#sessions.get(clientId);
2391
+ return session ? session.subscriptions.has(uri) : false;
2392
+ }
2393
+ getAllSubscribedUris() {
2394
+ const all = /* @__PURE__ */ new Set();
2395
+ for (const session of this.#sessions.values()) {
2396
+ for (const uri of session.subscriptions) {
2397
+ all.add(uri);
2398
+ }
2399
+ }
2400
+ return all;
2401
+ }
2402
+ list() {
2403
+ return Array.from(this.#sessions.entries()).map(([id, s]) => ({
2404
+ clientId: id,
2405
+ subscriptions: Array.from(s.subscriptions),
2406
+ createdAt: s.createdAt,
2407
+ connected: s.connected
2408
+ }));
2409
+ }
2410
+ count() {
2411
+ return this.#sessions.size;
2412
+ }
2413
+ clear() {
2414
+ this.#sessions.clear();
2415
+ }
2416
+ };
2405
2417
  }
2406
- };
2418
+ });
2407
2419
 
2408
2420
  // src/subscription-manager.js
2409
- var sessionManager = new SessionManager();
2410
- var _notifyFn = null;
2411
2421
  function setNotify(fn) {
2412
2422
  _notifyFn = fn;
2413
2423
  }
@@ -2440,239 +2450,250 @@ function notify(uri, data) {
2440
2450
  _notifyFn(uri, data);
2441
2451
  }
2442
2452
  }
2453
+ var sessionManager, _notifyFn;
2454
+ var init_subscription_manager = __esm({
2455
+ "src/subscription-manager.js"() {
2456
+ init_session_manager();
2457
+ sessionManager = new SessionManager();
2458
+ _notifyFn = null;
2459
+ }
2460
+ });
2443
2461
 
2444
2462
  // src/sse-session.js
2445
- import { randomUUID as randomUUID3 } from "crypto";
2446
- var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
2447
- var DEFAULT_RETRY_INTERVAL = 3e4;
2448
- var MAX_SENT_MESSAGES = 1e3;
2449
- var SSE_EVENTS = {
2450
- MESSAGE: "message",
2451
- ENDPOINT: "endpoint",
2452
- PING: "ping",
2453
- ERROR: "error",
2454
- PROGRESS: "progress",
2455
- CAPABILITIES: "capabilities"
2456
- };
2457
- var SseSession = class {
2458
- #res;
2459
- #clientId;
2460
- #active = true;
2461
- #heartbeatTimer = null;
2462
- #lastEventId = 0;
2463
- #heartbeatInterval;
2464
- #retryInterval;
2465
- #sessionData = {};
2466
- #sentMessages = [];
2467
- #backpressureBuffer = [];
2468
- #drainHandler = null;
2469
- constructor(res, options = {}) {
2470
- this.#res = res;
2471
- this.#clientId = options.clientId || randomUUID3();
2472
- this.#heartbeatInterval = options.heartbeatInterval || DEFAULT_HEARTBEAT_INTERVAL;
2473
- this.#retryInterval = options.retryInterval || DEFAULT_RETRY_INTERVAL;
2474
- this.#sessionData = options.sessionData || {};
2475
- if (options.resumeFromId && options.resumeFromId > 0) {
2476
- this.#lastEventId = options.resumeFromId;
2477
- }
2478
- this._setupSseHeaders();
2479
- this._sendRetry();
2480
- this._setupDrain();
2481
- }
2482
- get clientId() {
2483
- return this.#clientId;
2484
- }
2485
- get isActive() {
2486
- return this.#active;
2487
- }
2488
- get lastEventId() {
2489
- return this.#lastEventId;
2490
- }
2491
- get sessionData() {
2492
- return this.#sessionData;
2493
- }
2494
- get sentMessages() {
2495
- return [...this.#sentMessages];
2496
- }
2497
- getMessagesSince(eventId) {
2498
- return this.#sentMessages.filter((m) => m.id > eventId);
2499
- }
2500
- setSessionData(key, value) {
2501
- this.#sessionData[key] = value;
2502
- }
2503
- getSessionData(key) {
2504
- return this.#sessionData[key];
2505
- }
2506
- get retryInterval() {
2507
- return this.#retryInterval;
2508
- }
2509
- setRetryInterval(ms) {
2510
- this.#retryInterval = ms;
2511
- }
2512
- _sendRetry() {
2513
- this._write(`retry: ${this.#retryInterval}
2514
-
2515
- `);
2516
- }
2517
- _setupSseHeaders() {
2518
- this.#res.setHeader("Content-Type", "text/event-stream");
2519
- this.#res.setHeader("Cache-Control", "no-cache");
2520
- this.#res.setHeader("Connection", "keep-alive");
2521
- this.#res.setHeader("Transfer-Encoding", "chunked");
2522
- this.#res.setHeader("X-Accel-Buffering", "no");
2523
- if (typeof this.#res.flush !== "function") {
2524
- this.#res.flush = () => {
2525
- };
2526
- }
2527
- }
2528
- _formatEvent(event, data, id = null) {
2529
- const lines = [];
2530
- if (id !== null) {
2531
- lines.push(`id: ${id}`);
2532
- }
2533
- lines.push(`event: ${event}`);
2534
- if (data !== null && data !== void 0) {
2535
- const jsonStr = JSON.stringify(data);
2536
- lines.push(`data: ${jsonStr}`);
2537
- } else {
2538
- lines.push("data:");
2539
- }
2540
- return lines.join("\n") + "\n\n";
2541
- }
2542
- _setupDrain() {
2543
- if (typeof this.#res.on !== "function") return;
2544
- this.#drainHandler = () => {
2545
- if (!this.#active) return;
2546
- if (this.#backpressureBuffer.length > 0) {
2547
- this._drainBuffer();
2548
- }
2463
+ import { randomUUID as randomUUID2 } from "crypto";
2464
+ var DEFAULT_HEARTBEAT_INTERVAL, DEFAULT_RETRY_INTERVAL, MAX_SENT_MESSAGES, SSE_EVENTS, SseSession;
2465
+ var init_sse_session = __esm({
2466
+ "src/sse-session.js"() {
2467
+ DEFAULT_HEARTBEAT_INTERVAL = 3e4;
2468
+ DEFAULT_RETRY_INTERVAL = 3e4;
2469
+ MAX_SENT_MESSAGES = 1e3;
2470
+ SSE_EVENTS = {
2471
+ MESSAGE: "message",
2472
+ ENDPOINT: "endpoint",
2473
+ PING: "ping",
2474
+ ERROR: "error",
2475
+ PROGRESS: "progress",
2476
+ CAPABILITIES: "capabilities"
2549
2477
  };
2550
- this.#res.on("drain", this.#drainHandler);
2551
- }
2552
- _drainBuffer() {
2553
- const batch = this.#backpressureBuffer.splice(0, 50);
2554
- for (const item of batch) {
2555
- const ok = this.#res.write(item);
2556
- if (!ok) {
2557
- this.#backpressureBuffer.unshift(...batch.slice(batch.indexOf(item)));
2558
- return;
2478
+ SseSession = class {
2479
+ #res;
2480
+ #clientId;
2481
+ #active = true;
2482
+ #heartbeatTimer = null;
2483
+ #lastEventId = 0;
2484
+ #heartbeatInterval;
2485
+ #retryInterval;
2486
+ #sessionData = {};
2487
+ #sentMessages = [];
2488
+ #backpressureBuffer = [];
2489
+ #drainHandler = null;
2490
+ constructor(res, options = {}) {
2491
+ this.#res = res;
2492
+ this.#clientId = options.clientId || randomUUID2();
2493
+ this.#heartbeatInterval = options.heartbeatInterval || DEFAULT_HEARTBEAT_INTERVAL;
2494
+ this.#retryInterval = options.retryInterval || DEFAULT_RETRY_INTERVAL;
2495
+ this.#sessionData = options.sessionData || {};
2496
+ if (options.resumeFromId && options.resumeFromId > 0) {
2497
+ this.#lastEventId = options.resumeFromId;
2498
+ }
2499
+ this._setupSseHeaders();
2500
+ this._sendRetry();
2501
+ this._setupDrain();
2559
2502
  }
2560
- }
2561
- this._flush();
2562
- if (this.#backpressureBuffer.length > 0) {
2563
- this._drainBuffer();
2564
- }
2565
- }
2566
- _write(content) {
2567
- if (!this.#active) return false;
2568
- try {
2569
- if (this.#backpressureBuffer.length > 0) {
2570
- this.#backpressureBuffer.push(content);
2571
- return true;
2503
+ get clientId() {
2504
+ return this.#clientId;
2572
2505
  }
2573
- const result = this.#res.write(content);
2574
- if (typeof this.#res.flush === "function") {
2575
- this.#res.flush();
2506
+ get isActive() {
2507
+ return this.#active;
2576
2508
  }
2577
- if (result === false) {
2578
- this.#backpressureBuffer.push(content);
2579
- return true;
2509
+ get lastEventId() {
2510
+ return this.#lastEventId;
2580
2511
  }
2581
- return true;
2582
- } catch (e) {
2583
- this.#active = false;
2584
- this.close();
2585
- return false;
2586
- }
2587
- }
2588
- _flush() {
2589
- try {
2590
- if (typeof this.#res.flush === "function") {
2591
- this.#res.flush();
2512
+ get sessionData() {
2513
+ return this.#sessionData;
2592
2514
  }
2593
- } catch (e) {
2594
- }
2595
- }
2596
- flushBackpressure() {
2597
- if (this.#backpressureBuffer.length > 0) {
2598
- this._drainBuffer();
2599
- }
2600
- }
2601
- sendEvent(event, data, id = null) {
2602
- this.#lastEventId++;
2603
- const eventId = id !== null ? id : this.#lastEventId;
2604
- const formatted = this._formatEvent(event, data, eventId);
2605
- this.#sentMessages.push({ event, data, id: eventId, timestamp: Date.now() });
2606
- if (this.#sentMessages.length > MAX_SENT_MESSAGES) {
2607
- this.#sentMessages.splice(0, this.#sentMessages.length - MAX_SENT_MESSAGES);
2608
- }
2609
- this._write(formatted);
2610
- this._flush();
2611
- return true;
2612
- }
2613
- sendMessage(data) {
2614
- return this.sendEvent(SSE_EVENTS.MESSAGE, data);
2615
- }
2616
- sendEndpoint(path8) {
2617
- return this.sendEvent(SSE_EVENTS.ENDPOINT, path8);
2618
- }
2619
- sendError(code, message, id = null) {
2620
- return this.sendEvent(SSE_EVENTS.ERROR, { code, message }, id);
2621
- }
2622
- sendPing() {
2623
- return this.sendEvent(SSE_EVENTS.PING, { timestamp: Date.now() });
2624
- }
2625
- sendProgress(current, total, message = "") {
2626
- return this.sendEvent(SSE_EVENTS.PROGRESS, { current, total, message });
2627
- }
2628
- sendCapabilities(capabilities) {
2629
- return this.sendEvent(SSE_EVENTS.CAPABILITIES, capabilities);
2630
- }
2631
- sendResponse(jsonrpcResponse, id = null) {
2632
- const eventId = id !== null ? id : this.#lastEventId;
2633
- return this.sendEvent(SSE_EVENTS.MESSAGE, jsonrpcResponse, eventId);
2634
- }
2635
- startHeartbeat(interval = null) {
2636
- this.stopHeartbeat();
2637
- const ms = interval || this.#heartbeatInterval;
2638
- this.#heartbeatTimer = setInterval(() => {
2639
- if (!this.#active) {
2515
+ get sentMessages() {
2516
+ return [...this.#sentMessages];
2517
+ }
2518
+ getMessagesSince(eventId) {
2519
+ return this.#sentMessages.filter((m) => m.id > eventId);
2520
+ }
2521
+ setSessionData(key, value) {
2522
+ this.#sessionData[key] = value;
2523
+ }
2524
+ getSessionData(key) {
2525
+ return this.#sessionData[key];
2526
+ }
2527
+ get retryInterval() {
2528
+ return this.#retryInterval;
2529
+ }
2530
+ setRetryInterval(ms) {
2531
+ this.#retryInterval = ms;
2532
+ }
2533
+ _sendRetry() {
2534
+ this._write(`retry: ${this.#retryInterval}
2535
+
2536
+ `);
2537
+ }
2538
+ _setupSseHeaders() {
2539
+ this.#res.setHeader("Content-Type", "text/event-stream");
2540
+ this.#res.setHeader("Cache-Control", "no-cache");
2541
+ this.#res.setHeader("Connection", "keep-alive");
2542
+ this.#res.setHeader("Transfer-Encoding", "chunked");
2543
+ this.#res.setHeader("X-Accel-Buffering", "no");
2544
+ if (typeof this.#res.flush !== "function") {
2545
+ this.#res.flush = () => {
2546
+ };
2547
+ }
2548
+ }
2549
+ _formatEvent(event, data, id = null) {
2550
+ const lines = [];
2551
+ if (id !== null) {
2552
+ lines.push(`id: ${id}`);
2553
+ }
2554
+ lines.push(`event: ${event}`);
2555
+ if (data !== null && data !== void 0) {
2556
+ const jsonStr = JSON.stringify(data);
2557
+ lines.push(`data: ${jsonStr}`);
2558
+ } else {
2559
+ lines.push("data:");
2560
+ }
2561
+ return lines.join("\n") + "\n\n";
2562
+ }
2563
+ _setupDrain() {
2564
+ if (typeof this.#res.on !== "function") return;
2565
+ this.#drainHandler = () => {
2566
+ if (!this.#active) return;
2567
+ if (this.#backpressureBuffer.length > 0) {
2568
+ this._drainBuffer();
2569
+ }
2570
+ };
2571
+ this.#res.on("drain", this.#drainHandler);
2572
+ }
2573
+ _drainBuffer() {
2574
+ const batch = this.#backpressureBuffer.splice(0, 50);
2575
+ for (const item of batch) {
2576
+ const ok = this.#res.write(item);
2577
+ if (!ok) {
2578
+ this.#backpressureBuffer.unshift(...batch.slice(batch.indexOf(item)));
2579
+ return;
2580
+ }
2581
+ }
2582
+ this._flush();
2583
+ if (this.#backpressureBuffer.length > 0) {
2584
+ this._drainBuffer();
2585
+ }
2586
+ }
2587
+ _write(content) {
2588
+ if (!this.#active) return false;
2589
+ try {
2590
+ if (this.#backpressureBuffer.length > 0) {
2591
+ this.#backpressureBuffer.push(content);
2592
+ return true;
2593
+ }
2594
+ const result = this.#res.write(content);
2595
+ if (typeof this.#res.flush === "function") {
2596
+ this.#res.flush();
2597
+ }
2598
+ if (result === false) {
2599
+ this.#backpressureBuffer.push(content);
2600
+ return true;
2601
+ }
2602
+ return true;
2603
+ } catch (e) {
2604
+ this.#active = false;
2605
+ this.close();
2606
+ return false;
2607
+ }
2608
+ }
2609
+ _flush() {
2610
+ try {
2611
+ if (typeof this.#res.flush === "function") {
2612
+ this.#res.flush();
2613
+ }
2614
+ } catch (e) {
2615
+ }
2616
+ }
2617
+ flushBackpressure() {
2618
+ if (this.#backpressureBuffer.length > 0) {
2619
+ this._drainBuffer();
2620
+ }
2621
+ }
2622
+ sendEvent(event, data, id = null) {
2623
+ this.#lastEventId++;
2624
+ const eventId = id !== null ? id : this.#lastEventId;
2625
+ const formatted = this._formatEvent(event, data, eventId);
2626
+ this.#sentMessages.push({ event, data, id: eventId, timestamp: Date.now() });
2627
+ if (this.#sentMessages.length > MAX_SENT_MESSAGES) {
2628
+ this.#sentMessages.splice(0, this.#sentMessages.length - MAX_SENT_MESSAGES);
2629
+ }
2630
+ this._write(formatted);
2631
+ this._flush();
2632
+ return true;
2633
+ }
2634
+ sendMessage(data) {
2635
+ return this.sendEvent(SSE_EVENTS.MESSAGE, data);
2636
+ }
2637
+ sendEndpoint(path8) {
2638
+ return this.sendEvent(SSE_EVENTS.ENDPOINT, path8);
2639
+ }
2640
+ sendError(code, message, id = null) {
2641
+ return this.sendEvent(SSE_EVENTS.ERROR, { code, message }, id);
2642
+ }
2643
+ sendPing() {
2644
+ return this.sendEvent(SSE_EVENTS.PING, { timestamp: Date.now() });
2645
+ }
2646
+ sendProgress(current, total, message = "") {
2647
+ return this.sendEvent(SSE_EVENTS.PROGRESS, { current, total, message });
2648
+ }
2649
+ sendCapabilities(capabilities) {
2650
+ return this.sendEvent(SSE_EVENTS.CAPABILITIES, capabilities);
2651
+ }
2652
+ sendResponse(jsonrpcResponse, id = null) {
2653
+ const eventId = id !== null ? id : this.#lastEventId;
2654
+ return this.sendEvent(SSE_EVENTS.MESSAGE, jsonrpcResponse, eventId);
2655
+ }
2656
+ startHeartbeat(interval = null) {
2640
2657
  this.stopHeartbeat();
2641
- return;
2658
+ const ms = interval || this.#heartbeatInterval;
2659
+ this.#heartbeatTimer = setInterval(() => {
2660
+ if (!this.#active) {
2661
+ this.stopHeartbeat();
2662
+ return;
2663
+ }
2664
+ if (!this.sendPing()) {
2665
+ this.stopHeartbeat();
2666
+ this.close();
2667
+ }
2668
+ }, ms);
2669
+ }
2670
+ stopHeartbeat() {
2671
+ if (this.#heartbeatTimer) {
2672
+ clearInterval(this.#heartbeatTimer);
2673
+ this.#heartbeatTimer = null;
2674
+ }
2642
2675
  }
2643
- if (!this.sendPing()) {
2676
+ close() {
2677
+ this.#active = false;
2644
2678
  this.stopHeartbeat();
2645
- this.close();
2679
+ if (this.#drainHandler) {
2680
+ this.#res.removeListener("drain", this.#drainHandler);
2681
+ this.#drainHandler = null;
2682
+ }
2683
+ this.#backpressureBuffer = [];
2684
+ try {
2685
+ this.#res.end();
2686
+ } catch (e) {
2687
+ }
2646
2688
  }
2647
- }, ms);
2648
- }
2649
- stopHeartbeat() {
2650
- if (this.#heartbeatTimer) {
2651
- clearInterval(this.#heartbeatTimer);
2652
- this.#heartbeatTimer = null;
2653
- }
2654
- }
2655
- close() {
2656
- this.#active = false;
2657
- this.stopHeartbeat();
2658
- if (this.#drainHandler) {
2659
- this.#res.removeListener("drain", this.#drainHandler);
2660
- this.#drainHandler = null;
2661
- }
2662
- this.#backpressureBuffer = [];
2663
- try {
2664
- this.#res.end();
2665
- } catch (e) {
2666
- }
2689
+ };
2667
2690
  }
2668
- };
2691
+ });
2669
2692
 
2670
2693
  // src/sse-session-manager.js
2671
2694
  import fs5 from "fs";
2672
2695
  import path6 from "path";
2673
2696
  import os3 from "os";
2674
- var SESSION_STORE_DIR = path6.join(os3.homedir(), ".atlisp", "sessions");
2675
- var SESSION_STORE_TTL = 24 * 60 * 60 * 1e3;
2676
2697
  function getSessionStorePath(clientId) {
2677
2698
  return path6.join(SESSION_STORE_DIR, `${clientId}.json`);
2678
2699
  }
@@ -2704,199 +2725,571 @@ function loadPersistedSessionData(clientId) {
2704
2725
  return null;
2705
2726
  }
2706
2727
  }
2707
- var SseSessionManager = class {
2708
- #sessions = /* @__PURE__ */ new Map();
2709
- #eventHandlers = /* @__PURE__ */ new Map();
2710
- constructor() {
2711
- this.#sessions = /* @__PURE__ */ new Map();
2712
- this.#eventHandlers = /* @__PURE__ */ new Map();
2713
- }
2714
- add(clientId, session) {
2715
- if (!(session instanceof SseSession)) {
2716
- throw new Error("session must be an SseSession instance");
2717
- }
2718
- const persisted = loadPersistedSessionData(clientId);
2719
- if (persisted) {
2720
- for (const [key, value] of Object.entries(persisted)) {
2721
- session.setSessionData(key, value);
2728
+ var SESSION_STORE_DIR, SESSION_STORE_TTL, SseSessionManager;
2729
+ var init_sse_session_manager = __esm({
2730
+ "src/sse-session-manager.js"() {
2731
+ init_sse_session();
2732
+ SESSION_STORE_DIR = path6.join(os3.homedir(), ".atlisp", "sessions");
2733
+ SESSION_STORE_TTL = 24 * 60 * 60 * 1e3;
2734
+ SseSessionManager = class {
2735
+ #sessions = /* @__PURE__ */ new Map();
2736
+ #eventHandlers = /* @__PURE__ */ new Map();
2737
+ constructor() {
2738
+ this.#sessions = /* @__PURE__ */ new Map();
2739
+ this.#eventHandlers = /* @__PURE__ */ new Map();
2740
+ }
2741
+ add(clientId, session) {
2742
+ if (!(session instanceof SseSession)) {
2743
+ throw new Error("session must be an SseSession instance");
2744
+ }
2745
+ const persisted = loadPersistedSessionData(clientId);
2746
+ if (persisted) {
2747
+ for (const [key, value] of Object.entries(persisted)) {
2748
+ session.setSessionData(key, value);
2749
+ }
2750
+ }
2751
+ this.#sessions.set(clientId, session);
2752
+ session.startHeartbeat();
2753
+ }
2754
+ remove(clientId) {
2755
+ const session = this.#sessions.get(clientId);
2756
+ if (session) {
2757
+ persistSessionData(clientId, session.sessionData);
2758
+ session.close();
2759
+ this.#sessions.delete(clientId);
2760
+ return true;
2761
+ }
2762
+ return false;
2722
2763
  }
2723
- }
2724
- this.#sessions.set(clientId, session);
2725
- session.startHeartbeat();
2726
- }
2727
- remove(clientId) {
2728
- const session = this.#sessions.get(clientId);
2729
- if (session) {
2730
- persistSessionData(clientId, session.sessionData);
2731
- session.close();
2732
- this.#sessions.delete(clientId);
2733
- return true;
2734
- }
2735
- return false;
2736
- }
2737
- get(clientId) {
2738
- return this.#sessions.get(clientId) || null;
2739
- }
2740
- has(clientId) {
2741
- return this.#sessions.has(clientId);
2742
- }
2743
- list() {
2744
- return Array.from(this.#sessions.keys()).map((id) => ({
2745
- clientId: id,
2746
- isActive: this.#sessions.get(id)?.isActive ?? false
2747
- }));
2748
- }
2749
- listActive() {
2750
- return this.list().filter((s) => s.isActive);
2764
+ get(clientId) {
2765
+ return this.#sessions.get(clientId) || null;
2766
+ }
2767
+ has(clientId) {
2768
+ return this.#sessions.has(clientId);
2769
+ }
2770
+ list() {
2771
+ return Array.from(this.#sessions.keys()).map((id) => ({
2772
+ clientId: id,
2773
+ isActive: this.#sessions.get(id)?.isActive ?? false
2774
+ }));
2775
+ }
2776
+ listActive() {
2777
+ return this.list().filter((s) => s.isActive);
2778
+ }
2779
+ count() {
2780
+ return this.#sessions.size;
2781
+ }
2782
+ sendToClient(clientId, event, data, id = null) {
2783
+ const session = this.#sessions.get(clientId);
2784
+ if (!session || !session.isActive) {
2785
+ return false;
2786
+ }
2787
+ return session.sendEvent(event, data, id);
2788
+ }
2789
+ sendMessageToClient(clientId, data) {
2790
+ return this.sendToClient(clientId, SSE_EVENTS.MESSAGE, data);
2791
+ }
2792
+ sendErrorToClient(clientId, code, message, id = null) {
2793
+ return this.sendToClient(clientId, SSE_EVENTS.ERROR, { code, message }, id);
2794
+ }
2795
+ sendProgressToClient(clientId, current, total, message = "") {
2796
+ return this.sendToClient(clientId, SSE_EVENTS.PROGRESS, { current, total, message });
2797
+ }
2798
+ broadcast(event, data) {
2799
+ let successCount = 0;
2800
+ for (const [clientId, session] of this.#sessions) {
2801
+ if (session.isActive && session.sendEvent(event, data)) {
2802
+ successCount++;
2803
+ }
2804
+ }
2805
+ return successCount;
2806
+ }
2807
+ broadcastMessage(data) {
2808
+ return this.broadcast(SSE_EVENTS.MESSAGE, data);
2809
+ }
2810
+ broadcastError(code, message) {
2811
+ return this.broadcast(SSE_EVENTS.ERROR, { code, message });
2812
+ }
2813
+ on(event, handler) {
2814
+ if (!this.#eventHandlers.has(event)) {
2815
+ this.#eventHandlers.set(event, /* @__PURE__ */ new Set());
2816
+ }
2817
+ this.#eventHandlers.get(event).add(handler);
2818
+ }
2819
+ off(event, handler) {
2820
+ const handlers = this.#eventHandlers.get(event);
2821
+ if (handlers) {
2822
+ handlers.delete(handler);
2823
+ }
2824
+ }
2825
+ emit(event, data) {
2826
+ const handlers = this.#eventHandlers.get(event);
2827
+ if (handlers) {
2828
+ for (const handler of handlers) {
2829
+ try {
2830
+ handler(data);
2831
+ } catch (e) {
2832
+ }
2833
+ }
2834
+ }
2835
+ }
2836
+ cleanupInactive() {
2837
+ for (const [clientId, session] of this.#sessions) {
2838
+ if (!session.isActive) {
2839
+ session.close();
2840
+ this.#sessions.delete(clientId);
2841
+ }
2842
+ }
2843
+ }
2844
+ closeAll() {
2845
+ for (const [clientId, session] of this.#sessions) {
2846
+ persistSessionData(clientId, session.sessionData);
2847
+ session.close();
2848
+ }
2849
+ this.#sessions.clear();
2850
+ }
2851
+ };
2751
2852
  }
2752
- count() {
2753
- return this.#sessions.size;
2853
+ });
2854
+
2855
+ // src/session-transport.js
2856
+ import { randomUUID as randomUUID3 } from "crypto";
2857
+ var SESSION_TIMEOUT, SessionTransport;
2858
+ var init_session_transport = __esm({
2859
+ "src/session-transport.js"() {
2860
+ SESSION_TIMEOUT = 30 * 60 * 1e3;
2861
+ SessionTransport = class {
2862
+ constructor(sessionId) {
2863
+ this.sessionId = sessionId || randomUUID3();
2864
+ this.onclose = null;
2865
+ this.onerror = null;
2866
+ this.onmessage = null;
2867
+ this._pendingRequest = null;
2868
+ this._started = false;
2869
+ this._closed = false;
2870
+ this._cleanupTimer = null;
2871
+ }
2872
+ async start() {
2873
+ if (this._started) {
2874
+ throw new Error("Transport already started");
2875
+ }
2876
+ this._started = true;
2877
+ }
2878
+ async send(message) {
2879
+ if (this._closed) return;
2880
+ if (this._pendingRequest) {
2881
+ const { resolve, reject, timeout } = this._pendingRequest;
2882
+ clearTimeout(timeout);
2883
+ this._pendingRequest = null;
2884
+ resolve(message);
2885
+ }
2886
+ }
2887
+ async close() {
2888
+ if (this._closed) return;
2889
+ this._closed = true;
2890
+ if (this._pendingRequest) {
2891
+ const { reject, timeout } = this._pendingRequest;
2892
+ clearTimeout(timeout);
2893
+ this._pendingRequest = null;
2894
+ reject(new Error("Transport closed"));
2895
+ }
2896
+ this._clearCleanupTimer();
2897
+ this.onclose?.();
2898
+ }
2899
+ async handleRequest(message, timeoutMs = 6e4) {
2900
+ if (this._closed) {
2901
+ throw new Error("Transport closed");
2902
+ }
2903
+ if (!message || !message.method) {
2904
+ throw new Error("Invalid message");
2905
+ }
2906
+ if (!message.id) {
2907
+ this.onmessage?.(message);
2908
+ return null;
2909
+ }
2910
+ return new Promise((resolve, reject) => {
2911
+ const timeout = setTimeout(() => {
2912
+ if (this._pendingRequest?.resolve === resolve) {
2913
+ this._pendingRequest = null;
2914
+ reject(new Error("Request timeout"));
2915
+ }
2916
+ }, timeoutMs);
2917
+ this._pendingRequest = { resolve, reject, timeout };
2918
+ this.onmessage?.(message);
2919
+ });
2920
+ }
2921
+ resetCleanupTimer() {
2922
+ this._clearCleanupTimer();
2923
+ this._cleanupTimer = setTimeout(() => {
2924
+ this.close();
2925
+ }, SESSION_TIMEOUT);
2926
+ }
2927
+ _clearCleanupTimer() {
2928
+ if (this._cleanupTimer) {
2929
+ clearTimeout(this._cleanupTimer);
2930
+ this._cleanupTimer = null;
2931
+ }
2932
+ }
2933
+ };
2754
2934
  }
2755
- sendToClient(clientId, event, data, id = null) {
2756
- const session = this.#sessions.get(clientId);
2757
- if (!session || !session.isActive) {
2758
- return false;
2935
+ });
2936
+
2937
+ // src/mcp-handlers.js
2938
+ import {
2939
+ ListToolsRequestSchema,
2940
+ CallToolRequestSchema,
2941
+ ListResourcesRequestSchema,
2942
+ ReadResourceRequestSchema,
2943
+ SubscribeRequestSchema,
2944
+ UnsubscribeRequestSchema,
2945
+ ListPromptsRequestSchema,
2946
+ GetPromptRequestSchema
2947
+ } from "@modelcontextprotocol/sdk/types.js";
2948
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2949
+ function createMcpServer(handlers = {}) {
2950
+ const { tools: tools2 = [], handleToolCall: handleToolCall2 = () => ({ content: [] }) } = handlers;
2951
+ const server = new Server(
2952
+ { name: SERVER_NAME, version: SERVER_VERSION },
2953
+ { capabilities: SERVER_CAPABILITIES }
2954
+ );
2955
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: tools2 }));
2956
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
2957
+ const { name, arguments: args } = request.params;
2958
+ return await handleToolCall2(name, args || {});
2959
+ });
2960
+ server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
2961
+ const ctx = mcpContext.getStore();
2962
+ const sessionId = ctx?.sessionId;
2963
+ const subscribedUris = sessionId ? list(sessionId) : list();
2964
+ return {
2965
+ resources: await listResources(subscribedUris)
2966
+ };
2967
+ });
2968
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
2969
+ const { uri } = request.params;
2970
+ try {
2971
+ const data = await readResource(uri);
2972
+ return {
2973
+ contents: [{
2974
+ uri,
2975
+ mimeType: "application/json",
2976
+ text: JSON.stringify(data)
2977
+ }]
2978
+ };
2979
+ } catch (e) {
2980
+ return {
2981
+ contents: [],
2982
+ isError: true,
2983
+ error: { code: -32603, message: e.message }
2984
+ };
2759
2985
  }
2760
- return session.sendEvent(event, data, id);
2761
- }
2762
- sendMessageToClient(clientId, data) {
2763
- return this.sendToClient(clientId, SSE_EVENTS.MESSAGE, data);
2986
+ });
2987
+ server.setRequestHandler(SubscribeRequestSchema, async (request) => {
2988
+ const { uri } = request.params;
2989
+ const ctx = mcpContext.getStore();
2990
+ subscribe(uri, ctx?.sessionId);
2991
+ return { success: true };
2992
+ });
2993
+ server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
2994
+ const { uri } = request.params;
2995
+ const ctx = mcpContext.getStore();
2996
+ unsubscribe(uri, ctx?.sessionId);
2997
+ return { success: true };
2998
+ });
2999
+ server.setRequestHandler(ListPromptsRequestSchema, async () => ({
3000
+ prompts: await listPrompts()
3001
+ }));
3002
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
3003
+ const { name, arguments: args } = request.params;
3004
+ return await getPrompt(name, args || {});
3005
+ });
3006
+ return server;
3007
+ }
3008
+ var SERVER_CAPABILITIES;
3009
+ var init_mcp_handlers = __esm({
3010
+ "src/mcp-handlers.js"() {
3011
+ init_resource_handlers();
3012
+ init_prompt_handlers();
3013
+ init_constants();
3014
+ init_subscription_manager();
3015
+ init_mcp_server_state();
3016
+ SERVER_CAPABILITIES = {
3017
+ tools: {},
3018
+ resources: { subscribe: true, listChanged: true },
3019
+ prompts: {}
3020
+ };
2764
3021
  }
2765
- sendErrorToClient(clientId, code, message, id = null) {
2766
- return this.sendToClient(clientId, SSE_EVENTS.ERROR, { code, message }, id);
3022
+ });
3023
+
3024
+ // src/mcp-server-state.js
3025
+ import { AsyncLocalStorage } from "async_hooks";
3026
+ async function getOrCreateSessionServer(sessionId) {
3027
+ if (!mcpHandlers) {
3028
+ const { tools: tools2, handleToolCall: handleToolCall2 } = await init_atlisp_mcp().then(() => atlisp_mcp_exports);
3029
+ mcpHandlers = { tools: tools2, handleToolCall: handleToolCall2 };
2767
3030
  }
2768
- sendProgressToClient(clientId, current, total, message = "") {
2769
- return this.sendToClient(clientId, SSE_EVENTS.PROGRESS, { current, total, message });
3031
+ let entry = sessionServers.get(sessionId);
3032
+ if (!entry) {
3033
+ const server = createMcpServer(mcpHandlers);
3034
+ const transport = new SessionTransport(sessionId);
3035
+ server.connect(transport);
3036
+ entry = { server, transport };
3037
+ sessionServers.set(sessionId, entry);
3038
+ sessionTransports.set(sessionId, transport);
2770
3039
  }
2771
- broadcast(event, data) {
2772
- let successCount = 0;
2773
- for (const [clientId, session] of this.#sessions) {
2774
- if (session.isActive && session.sendEvent(event, data)) {
2775
- successCount++;
2776
- }
2777
- }
2778
- return successCount;
3040
+ return entry;
3041
+ }
3042
+ function createStdioServer(handlers) {
3043
+ mcpHandlers = handlers;
3044
+ return createMcpServer(handlers);
3045
+ }
3046
+ function removeSessionServer(sessionId) {
3047
+ const entry = sessionServers.get(sessionId);
3048
+ if (entry) {
3049
+ entry.transport.close().catch(() => {
3050
+ });
3051
+ entry.server.close().catch(() => {
3052
+ });
3053
+ sessionServers.delete(sessionId);
3054
+ sessionTransports.delete(sessionId);
2779
3055
  }
2780
- broadcastMessage(data) {
2781
- return this.broadcast(SSE_EVENTS.MESSAGE, data);
3056
+ }
3057
+ function broadcastToAllSessions(uri) {
3058
+ for (const [sid, entry] of sessionServers) {
3059
+ entry.server.sendResourceUpdated({ uri }).catch((err) => {
3060
+ error(`Failed to send resource update to session ${sid}: ${err.message}`, { sessionId: sid, uri });
3061
+ });
2782
3062
  }
2783
- broadcastError(code, message) {
2784
- return this.broadcast(SSE_EVENTS.ERROR, { code, message });
3063
+ }
3064
+ var mcpContext, sessionServers, sessionTransports, mcpHandlers;
3065
+ var init_mcp_server_state = __esm({
3066
+ "src/mcp-server-state.js"() {
3067
+ init_session_transport();
3068
+ init_mcp_handlers();
3069
+ init_logger();
3070
+ mcpContext = new AsyncLocalStorage();
3071
+ sessionServers = /* @__PURE__ */ new Map();
3072
+ sessionTransports = /* @__PURE__ */ new Map();
3073
+ mcpHandlers = null;
2785
3074
  }
2786
- on(event, handler) {
2787
- if (!this.#eventHandlers.has(event)) {
2788
- this.#eventHandlers.set(event, /* @__PURE__ */ new Set());
3075
+ });
3076
+
3077
+ // src/routes.js
3078
+ import express from "express";
3079
+ import { randomUUID as randomUUID4 } from "crypto";
3080
+ import iconv from "iconv-lite";
3081
+ import rateLimit from "express-rate-limit";
3082
+ function createJsonBodyParser() {
3083
+ return async (req, res, next) => {
3084
+ const ct = (req.headers["content-type"] || "").toLowerCase();
3085
+ if (!JSON_CONTENT_TYPES.some((t) => ct.startsWith(t))) return next();
3086
+ try {
3087
+ const chunks = [];
3088
+ for await (const chunk of req) {
3089
+ chunks.push(chunk);
3090
+ }
3091
+ const totalLength = chunks.reduce((acc, c) => acc + c.length, 0);
3092
+ if (totalLength > 10 * 1024 * 1024) {
3093
+ throw new Error("Request body too large");
3094
+ }
3095
+ const buf = Buffer.concat(chunks);
3096
+ const m = ct.match(/charset\s*=\s*([^\s;]+)/i);
3097
+ let charset = m ? m[1].toLowerCase() : "utf-8";
3098
+ const charsetMap = { "gb2312": "gbk", "gb18030": "gbk", "gbk": "gbk", "936": "gbk" };
3099
+ charset = charsetMap[charset] || charset;
3100
+ const str = iconv.decode(buf, charset);
3101
+ req.body = JSON.parse(str);
3102
+ next();
3103
+ } catch (e) {
3104
+ res.status(400).json({ error: "Invalid JSON body", message: e.message });
2789
3105
  }
2790
- this.#eventHandlers.get(event).add(handler);
2791
- }
2792
- off(event, handler) {
2793
- const handlers = this.#eventHandlers.get(event);
2794
- if (handlers) {
2795
- handlers.delete(handler);
3106
+ };
3107
+ }
3108
+ function createLoggingMiddleware() {
3109
+ return (req, res, next) => {
3110
+ log(`${req.method} ${req.path}`, { method: req.method, path: req.path, query: req.query });
3111
+ next();
3112
+ };
3113
+ }
3114
+ function createAuthMiddleware() {
3115
+ const PUBLIC_PATHS = ["/health"];
3116
+ return (req, res, next) => {
3117
+ if (apiKey) {
3118
+ if (PUBLIC_PATHS.includes(req.path)) return next();
3119
+ const auth = req.get("Authorization");
3120
+ if (auth === `Bearer ${apiKey}`) return next();
3121
+ return res.status(401).json({ error: "Unauthorized" });
2796
3122
  }
2797
- }
2798
- emit(event, data) {
2799
- const handlers = this.#eventHandlers.get(event);
2800
- if (handlers) {
2801
- for (const handler of handlers) {
2802
- try {
2803
- handler(data);
2804
- } catch (e) {
3123
+ next();
3124
+ };
3125
+ }
3126
+ function createCorsMiddleware() {
3127
+ return (req, res, next) => {
3128
+ if (!enableCors) return next();
3129
+ res.setHeader("Access-Control-Allow-Origin", corsOrigin);
3130
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, CONNECT");
3131
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, mcp-session-id, last-event-id");
3132
+ res.setHeader("Access-Control-Expose-Headers", "mcp-session-id, content-type, x-accel-buffering");
3133
+ res.setHeader("Access-Control-Max-Age", "86400");
3134
+ res.setHeader("Vary", "Accept");
3135
+ if (req.method === "OPTIONS") return res.status(204).end();
3136
+ next();
3137
+ };
3138
+ }
3139
+ function createErrorHandler() {
3140
+ return (err, req, res, next) => {
3141
+ error(`Unhandled error: ${err.message}`, { stack: err.stack, path: req.path });
3142
+ res.status(500).json({ error: "Internal server error", message: err.message });
3143
+ };
3144
+ }
3145
+ function setupRoutes(app) {
3146
+ app.use(createJsonBodyParser());
3147
+ app.use(createLoggingMiddleware());
3148
+ app.use(createAuthMiddleware());
3149
+ app.use(createCorsMiddleware());
3150
+ app.get("/health", (req, res) => {
3151
+ res.json({ status: "ok", cad: cad.connected ? "connected" : "disconnected" });
3152
+ });
3153
+ app.get("/api/docs", (req, res) => {
3154
+ res.json({
3155
+ openapi: "3.0.0",
3156
+ info: { title: "@lisp MCP Server", version: "1.5.0" },
3157
+ paths: {
3158
+ "/mcp": { post: { summary: "MCP JSON-RPC endpoint" } },
3159
+ "/sse": { get: { summary: "Server-Sent Events endpoint" } },
3160
+ "/message": { post: { summary: "SSE message endpoint" } },
3161
+ "/health": { get: { summary: "Health check" } }
3162
+ }
3163
+ });
3164
+ });
3165
+ app.all("/mcp", mcpLimiter, handleMcpPost);
3166
+ app.all("/mcp/:path", mcpLimiter, handleMcpPost);
3167
+ app.get("/mcp/stream", mcpLimiter, handleMcpPost);
3168
+ app.get("/sse", handleSse);
3169
+ app.post("/message", mcpLimiter, handleMessage);
3170
+ app.use(createErrorHandler());
3171
+ return app;
3172
+ }
3173
+ async function handleMcpPost(req, res) {
3174
+ const sessionId = req.headers["mcp-session-id"] || req.query.sessionId || randomUUID4();
3175
+ sessionManager.createSession(sessionId);
3176
+ const body = req.body;
3177
+ if (!body || !body.method) {
3178
+ return res.status(400).json({ error: "Invalid request" });
3179
+ }
3180
+ const { server, transport } = await getOrCreateSessionServer(sessionId);
3181
+ transport.resetCleanupTimer();
3182
+ await mcpContext.run({ sessionId }, async () => {
3183
+ try {
3184
+ const response = await transport.handleRequest(body);
3185
+ if (response) {
3186
+ const headers = { "Content-Type": "application/json" };
3187
+ if (transport.sessionId) {
3188
+ headers["mcp-session-id"] = transport.sessionId;
3189
+ }
3190
+ res.writeHead(200, headers);
3191
+ res.end(JSON.stringify(response));
3192
+ } else {
3193
+ if (!res.headersSent) {
3194
+ res.status(202).end();
2805
3195
  }
2806
3196
  }
2807
- }
2808
- }
2809
- cleanupInactive() {
2810
- for (const [clientId, session] of this.#sessions) {
2811
- if (!session.isActive) {
2812
- session.close();
2813
- this.#sessions.delete(clientId);
3197
+ } catch (err) {
3198
+ error(`Transport error [${sessionId}]: ${err.message}`);
3199
+ if (!res.headersSent) {
3200
+ res.status(500).json({ error: "Internal server error", message: err.message });
2814
3201
  }
2815
3202
  }
3203
+ });
3204
+ }
3205
+ async function handleSse(req, res) {
3206
+ const sessionId = randomUUID4();
3207
+ sessionManager.createSession(sessionId);
3208
+ getOrCreateSessionServer(sessionId);
3209
+ const sseSession = new SseSession(res, { clientId: sessionId });
3210
+ sseSessionManager.add(sessionId, sseSession);
3211
+ sseSession.sendEndpoint(`/message?sessionId=${sessionId}`);
3212
+ req.on("close", () => {
3213
+ sseSessionManager.remove(sessionId);
3214
+ removeSessionServer(sessionId);
3215
+ });
3216
+ }
3217
+ async function handleMessage(req, res) {
3218
+ const sessionId = req.query.sessionId;
3219
+ if (!sessionId) {
3220
+ return res.status(400).json({ error: "Missing sessionId" });
3221
+ }
3222
+ const sseSession = sseSessionManager.get(sessionId);
3223
+ if (!sseSession) {
3224
+ return res.status(404).json({ error: "Session not found" });
2816
3225
  }
2817
- closeAll() {
2818
- for (const [clientId, session] of this.#sessions) {
2819
- persistSessionData(clientId, session.sessionData);
2820
- session.close();
3226
+ sessionManager.createSession(sessionId);
3227
+ const { server, transport } = await getOrCreateSessionServer(sessionId);
3228
+ transport.resetCleanupTimer();
3229
+ const body = req.body;
3230
+ if (body && body.method) {
3231
+ try {
3232
+ const response = await transport.handleRequest(body);
3233
+ if (response) {
3234
+ sseSession.sendResponse(response);
3235
+ }
3236
+ if (!res.headersSent) {
3237
+ res.status(202).end();
3238
+ }
3239
+ } catch (err) {
3240
+ error(`SSE message error [${sessionId}]: ${err.message}`);
3241
+ if (!res.headersSent) {
3242
+ res.status(500).json({ error: "Internal server error" });
3243
+ }
2821
3244
  }
2822
- this.#sessions.clear();
3245
+ } else {
3246
+ res.status(400).json({ error: "Invalid request" });
3247
+ }
3248
+ }
3249
+ var sseSessionManager, apiKey, enableCors, corsOrigin, rateLimitWindow, rateLimitMax, mcpLimiter, JSON_CONTENT_TYPES;
3250
+ var init_routes = __esm({
3251
+ "src/routes.js"() {
3252
+ init_config();
3253
+ init_logger();
3254
+ init_cad();
3255
+ init_subscription_manager();
3256
+ init_sse_session_manager();
3257
+ init_mcp_server_state();
3258
+ init_sse_session();
3259
+ sseSessionManager = new SseSessionManager();
3260
+ ({ apiKey, enableCors, corsOrigin, rateLimitWindow, rateLimitMax } = config_default);
3261
+ mcpLimiter = rateLimit({
3262
+ windowMs: rateLimitWindow,
3263
+ max: rateLimitMax,
3264
+ standardHeaders: true,
3265
+ legacyHeaders: false,
3266
+ message: { error: "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5" }
3267
+ });
3268
+ JSON_CONTENT_TYPES = ["application/json", "application/json-rpc", "application/vnd.api+json"];
2823
3269
  }
2824
- };
3270
+ });
2825
3271
 
2826
3272
  // src/atlisp-mcp.js
2827
- var __dirname4 = path7.dirname(fileURLToPath4(import.meta.url));
2828
- var require2 = createRequire(import.meta.url);
2829
- var { version } = require2(path7.join(__dirname4, "..", "package.json"));
2830
- var CACHE_DIR2 = path7.join(os4.homedir(), ".atlisp", "cache");
2831
- var FUNCLIB_CACHE_FILE2 = path7.join(CACHE_DIR2, "functions.json");
2832
- var FUNCLIB_CACHE_TTL2 = 24 * 60 * 60 * 1e3;
2833
- var isMcpScript = process.argv[1]?.includes("atlisp-mcp");
2834
- if (isMcpScript) {
2835
- const args = process.argv.slice(2);
2836
- for (let i = 0; i < args.length; i++) {
2837
- if (args[i] === "--version" || args[i] === "-v") {
2838
- console.log(`atlisp-mcp v${version}`);
2839
- process.exit(0);
2840
- } else if (args[i] === "--help" || args[i] === "-h") {
2841
- console.log(`
2842
- @lisp MCP Server v${version}
2843
-
2844
- Usage: atlisp-mcp [options]
2845
-
2846
- Options:
2847
- -v, --version Show version number
2848
- --transport <type> Transport type: http or stdio (default: http)
2849
- --port <port> HTTP port (default: 8110)
2850
- --host <host> HTTP host (default: 0.0.0.0)
2851
- --stdio Shorthand for --transport stdio
2852
- -h, --help Show this help message
2853
-
2854
- Examples:
2855
- atlisp-mcp # Start HTTP server on port 8110
2856
- atlisp-mcp --port 3000 # Start HTTP server on port 3000
2857
- atlisp-mcp --stdio # Start in stdio mode for MCP clients
2858
- atlisp-mcp --transport stdio # Same as --stdio
2859
- `);
2860
- process.exit(0);
2861
- } else if (args[i] === "--transport" && args[i + 1]) {
2862
- process.env.TRANSPORT = args[i + 1];
2863
- i++;
2864
- } else if (args[i] === "--stdio") {
2865
- process.env.TRANSPORT = "stdio";
2866
- } else if (args[i] === "--port" && args[i + 1]) {
2867
- process.env.PORT = args[i + 1];
2868
- i++;
2869
- } else if (args[i] === "--host" && args[i + 1]) {
2870
- process.env.HOST = args[i + 1];
2871
- i++;
2872
- }
2873
- }
2874
- }
2875
- var { decode: charsetDecode, encodingExists } = iconv;
2876
- var mcpContext = new AsyncLocalStorage();
2877
- var sseSessionManager = new SseSessionManager();
2878
- var SERVER_CAPABILITIES = {
2879
- tools: {},
2880
- resources: { subscribe: true, listChanged: true },
2881
- prompts: {}
2882
- };
2883
- var { port, host, transport, apiKey, rateLimitWindow, rateLimitMax } = config_default;
2884
- if (apiKey) log("API Key authentication enabled");
2885
- var mcpLimiter = rateLimit({
2886
- windowMs: rateLimitWindow,
2887
- max: rateLimitMax,
2888
- standardHeaders: true,
2889
- legacyHeaders: false,
2890
- message: { error: "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5" }
3273
+ var atlisp_mcp_exports = {};
3274
+ __export(atlisp_mcp_exports, {
3275
+ CAD_PLATFORMS: () => CAD_PLATFORMS,
3276
+ FILE_EXTENSIONS: () => FILE_EXTENSIONS,
3277
+ handleToolCall: () => handleToolCall,
3278
+ loadAtlibFunctionLib: () => loadAtlibFunctionLib,
3279
+ startServer: () => startServer,
3280
+ tools: () => tools
2891
3281
  });
2892
- var FUNCTION_LIB_URL = process.env.FUNCTION_LIB_URL || "http://s3.atlisp.cn/json/functions.json";
2893
- var cachedFunctionLib = null;
2894
- var cachedAt2 = null;
2895
- var CACHE_TTL3 = 5 * 60 * 1e3;
3282
+ import path7 from "path";
3283
+ import fs6 from "fs";
3284
+ import { fileURLToPath as fileURLToPath4 } from "url";
3285
+ import { createRequire } from "module";
3286
+ import os4 from "os";
3287
+ import express2 from "express";
3288
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2896
3289
  async function readCacheFromDisk2() {
2897
3290
  try {
2898
3291
  const stat = fs6.statSync(FUNCLIB_CACHE_FILE2);
2899
- if (Date.now() - stat.mtimeMs < FUNCLIB_CACHE_TTL2) {
3292
+ if (Date.now() - stat.mtimeMs < CACHE_TTL3) {
2900
3293
  const raw = fs6.readFileSync(FUNCLIB_CACHE_FILE2, "utf-8");
2901
3294
  return JSON.parse(raw);
2902
3295
  }
@@ -2909,7 +3302,7 @@ function writeCacheToDisk2(data) {
2909
3302
  fs6.mkdirSync(CACHE_DIR2, { recursive: true });
2910
3303
  fs6.writeFileSync(FUNCLIB_CACHE_FILE2, JSON.stringify(data), "utf-8");
2911
3304
  } catch (e) {
2912
- log(`writeCacheToDisk error: ${e.message}`);
3305
+ error(`writeCacheToDisk error: ${e.message}`);
2913
3306
  }
2914
3307
  }
2915
3308
  async function loadAtlibFunctionLib() {
@@ -2933,235 +3326,31 @@ async function loadAtlibFunctionLib() {
2933
3326
  return data;
2934
3327
  }
2935
3328
  } catch (e) {
2936
- log(`loadAtlibFunctionLib error: ${e.message}`);
3329
+ error(`loadAtlibFunctionLib error: ${e.message}`);
2937
3330
  }
2938
3331
  return cachedFunctionLib;
2939
3332
  }
2940
- var TOOL_HANDLERS = {
2941
- connect_cad: (a) => connectCad(a?.platform),
2942
- eval_lisp: (a) => evalLisp(a.code),
2943
- eval_lisp_with_result: (a) => evalLisp(a.code, true, a.encoding),
2944
- get_cad_info: () => getCadInfo(),
2945
- list_packages: () => listPackages(),
2946
- search_packages: (a) => searchPackages(a.query),
2947
- install_package: (a) => installPackage(a.packageName),
2948
- get_platform_info: () => ({ content: [{ type: "text", text: `\u652F\u6301\u7684 CAD \u5E73\u53F0:
2949
- ${CAD_PLATFORMS.join("\n")}
2950
- \u5F53\u524D\u8FDE\u63A5: ${cad.connected ? "\u5DF2\u8FDE\u63A5" : "\u672A\u8FDE\u63A5"}` }] }),
2951
- at_command: (a) => atCommand(a.command),
2952
- new_document: () => newDocument(),
2953
- bring_to_front: () => bringToFront(),
2954
- install_atlisp: () => installAtlisp(),
2955
- init_atlisp: () => initAtlisp(),
2956
- get_function_usage: (a) => getFunctionUsage(a.name, a.package),
2957
- list_symbols: (a) => listSymbols(a.package),
2958
- get_system_status: () => getSystemStatus(),
2959
- list_prompts: async () => {
2960
- const prompts = await listPrompts();
2961
- return { content: [{ type: "text", text: JSON.stringify(prompts) }] };
2962
- },
2963
- get_prompt: async (a) => {
2964
- const prompt = await getPrompt(a.name, a.args || {});
2965
- return { content: prompt.messages.map((m) => ({ type: "text", text: m.content.text || m.content })) };
2966
- },
2967
- import_funlib: async (a) => {
2968
- const data = await loadAtlibFunctionLib();
2969
- if (!data) return { content: [{ type: "text", text: "\u52A0\u8F7D\u51FD\u6570\u5E93\u5931\u8D25" }], isError: true };
2970
- if (a.format === "list") {
2971
- const items = Object.values(data.all_functions || {}).map((f) => `${f.name}: ${f.description || ""}`);
2972
- return { content: [{ type: "text", text: items.join("\n") }] };
2973
- }
2974
- return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
2975
- }
2976
- };
2977
- function getOrCreateSessionServer(sessionId) {
2978
- let entry = sessionServers.get(sessionId);
2979
- if (!entry) {
2980
- const server = createMcpServer();
2981
- const transport2 = new SessionTransport(sessionId);
2982
- server.connect(transport2);
2983
- entry = { server, transport: transport2 };
2984
- sessionServers.set(sessionId, entry);
2985
- sessionTransports.set(sessionId, transport2);
2986
- }
2987
- return entry;
2988
- }
2989
- function removeSessionServer(sessionId) {
2990
- const entry = sessionServers.get(sessionId);
2991
- if (entry) {
2992
- entry.transport.close().catch(() => {
2993
- });
2994
- entry.server.close().catch(() => {
2995
- });
2996
- sessionServers.delete(sessionId);
2997
- sessionTransports.delete(sessionId);
2998
- }
2999
- }
3000
- function broadcastToAllSessions(uri) {
3001
- for (const [sid, entry] of sessionServers) {
3002
- entry.server.sendResourceUpdated({ uri }).catch((err) => {
3003
- log(`Failed to send resource update to session ${sid}: ${err.message}`);
3004
- });
3005
- }
3006
- }
3007
- var tools = [
3008
- {
3009
- name: "connect_cad",
3010
- description: "\u8FDE\u63A5\u5230 CAD (AutoCAD/ZWCAD/GStarCAD/BricsCAD)",
3011
- inputSchema: {
3012
- type: "object",
3013
- properties: {
3014
- platform: { type: "string", description: "\u6307\u5B9A CAD \u5E73\u53F0: AutoCAD, ZWCAD, GStarCAD, BricsCAD\uFF08\u53EF\u9009\uFF0C\u81EA\u52A8\u68C0\u6D4B\uFF09" }
3015
- }
3016
- }
3017
- },
3018
- {
3019
- name: "eval_lisp",
3020
- description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\uFF08\u4E0D\u8FD4\u56DE\u7ED3\u679C\uFF09",
3021
- inputSchema: {
3022
- type: "object",
3023
- properties: { code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" } },
3024
- required: ["code"]
3025
- }
3026
- },
3027
- {
3028
- name: "eval_lisp_with_result",
3029
- description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\u5E76\u8FD4\u56DE\u7ED3\u679C",
3030
- inputSchema: {
3031
- type: "object",
3032
- properties: {
3033
- code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" },
3034
- encoding: { type: "string", description: "\u7ED3\u679C\u7F16\u7801\uFF0C\u5982 utf-8, gbk, gb2312, gb18030\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4\u81EA\u52A8\u68C0\u6D4B\uFF09" }
3035
- },
3036
- required: ["code"]
3037
- }
3038
- },
3039
- {
3040
- name: "get_cad_info",
3041
- description: "\u83B7\u53D6\u5F53\u524D CAD \u4FE1\u606F",
3042
- inputSchema: { type: "object", properties: {} }
3043
- },
3044
- {
3045
- name: "list_packages",
3046
- description: "\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 @lisp \u5305",
3047
- inputSchema: { type: "object", properties: {} }
3048
- },
3049
- {
3050
- name: "search_packages",
3051
- description: "\u641C\u7D22 @lisp \u5305",
3052
- inputSchema: {
3053
- type: "object",
3054
- properties: { query: { type: "string", description: "\u641C\u7D22\u5173\u952E\u8BCD" } },
3055
- required: ["query"]
3056
- }
3057
- },
3058
- {
3059
- name: "install_package",
3060
- description: "\u5B89\u88C5 @lisp \u5305\u5230 CAD",
3061
- inputSchema: {
3062
- type: "object",
3063
- properties: { packageName: { type: "string", description: "\u5305\u540D\u79F0" } },
3064
- required: ["packageName"]
3065
- }
3066
- },
3067
- {
3068
- name: "get_platform_info",
3069
- description: "\u83B7\u53D6 CAD \u5E73\u53F0\u4FE1\u606F",
3070
- inputSchema: { type: "object", properties: {} }
3071
- },
3072
- {
3073
- name: "at_command",
3074
- description: "\u6267\u884C @lisp \u547D\u4EE4",
3075
- inputSchema: {
3076
- type: "object",
3077
- properties: { command: { type: "string", description: "@lisp \u547D\u4EE4" } },
3078
- required: ["command"]
3079
- }
3080
- },
3081
- {
3082
- name: "new_document",
3083
- description: "\u5728 CAD \u4E2D\u65B0\u5EFA\u7A7A\u767D\u6587\u6863",
3084
- inputSchema: { type: "object", properties: {} }
3085
- },
3086
- {
3087
- name: "bring_to_front",
3088
- description: "\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0\uFF08\u4ECE\u540E\u53F0\u8FD0\u884C\u72B6\u6001\u5524\u9192\uFF09",
3089
- inputSchema: { type: "object", properties: {} }
3090
- },
3091
- {
3092
- name: "install_atlisp",
3093
- description: "\u5728 CAD \u4E2D\u5B89\u88C5 @lisp",
3094
- inputSchema: { type: "object", properties: {} }
3095
- },
3096
- {
3097
- name: "init_atlisp",
3098
- description: "\u521D\u59CB\u5316 CAD \u4E2D\u7684 @lisp \u73AF\u5883\uFF0C\u52A0\u8F7D\u51FD\u6570\u5E93\u548C\u521D\u59CB\u53D8\u91CF",
3099
- inputSchema: { type: "object", properties: {} }
3100
- },
3101
- {
3102
- name: "get_function_usage",
3103
- description: "\u83B7\u53D6 @lisp \u51FD\u6570\u7528\u6CD5",
3104
- inputSchema: {
3105
- type: "object",
3106
- properties: {
3107
- name: { type: "string", description: "\u51FD\u6570\u540D\uFF0C\u5982 string:length" },
3108
- package: { type: "string", description: "\u5305\u540D\uFF0C\u5982 string\uFF08\u53EF\u9009\uFF0C\u4E0D\u4F20\u5219\u81EA\u52A8\u641C\u7D22\uFF09" }
3109
- },
3110
- required: ["name"]
3111
- }
3112
- },
3113
- {
3114
- name: "list_symbols",
3115
- description: "\u5217\u51FA @lisp \u6240\u6709\u7B26\u53F7\uFF0C\u7528\u4E8E\u68C0\u67E5\u51FD\u6570\u548C\u53D8\u91CF",
3116
- inputSchema: {
3117
- type: "object",
3118
- properties: {
3119
- package: { type: "string", description: "\u5305\u540D\uFF0C\u5982 string\uFF08\u53EF\u9009\uFF09" }
3120
- }
3121
- }
3122
- },
3123
- {
3124
- name: "import_funlib",
3125
- description: "\u4ECE\u7F51\u7EDC\u5BFC\u5165 @lisp \u51FD\u6570\u5E93\u6570\u636E\u5230 AI Agent",
3126
- inputSchema: {
3127
- type: "object",
3128
- properties: {
3129
- 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" }
3130
- }
3131
- }
3132
- },
3133
- {
3134
- name: "get_system_status",
3135
- description: "\u83B7\u53D6\u5B8C\u6574\u7CFB\u7EDF\u8BCA\u65AD\u4FE1\u606F\uFF1AMCP \u72B6\u6001\u3001CAD \u8FDE\u63A5\u3001Lisp \u6267\u884C\u3001\u5305\u5217\u8868",
3136
- inputSchema: { type: "object", properties: {} }
3137
- },
3138
- {
3139
- name: "list_prompts",
3140
- description: "\u5217\u51FA\u6240\u6709\u53EF\u7528\u7684 @lisp \u63D0\u793A\u6A21\u677F",
3141
- inputSchema: { type: "object", properties: {} }
3142
- },
3143
- {
3144
- name: "get_prompt",
3145
- description: "\u83B7\u53D6\u6307\u5B9A\u63D0\u793A\u6A21\u677F\u7684\u5185\u5BB9",
3146
- inputSchema: {
3147
- type: "object",
3148
- properties: {
3149
- name: { type: "string", description: "\u63D0\u793A\u6A21\u677F\u540D\u79F0" },
3150
- args: { type: "object", description: "\u6A21\u677F\u53C2\u6570\uFF08\u53EF\u9009\uFF09" }
3151
- },
3152
- required: ["name"]
3333
+ function validateToolArgs(name, args) {
3334
+ const schema = toolInputSchema[name];
3335
+ if (!schema) return true;
3336
+ for (const [key, type] of Object.entries(schema)) {
3337
+ if (type.endsWith("?")) continue;
3338
+ if (!args[key]) {
3339
+ throw new Error(`Missing required argument: ${key}`);
3153
3340
  }
3154
3341
  }
3155
- ];
3342
+ return true;
3343
+ }
3156
3344
  async function handleToolCall(name, args) {
3157
3345
  const handler = TOOL_HANDLERS[name];
3158
3346
  if (!handler) return { content: [{ type: "text", text: `\u672A\u77E5\u5DE5\u5177: ${name}` }], isError: true };
3159
3347
  try {
3348
+ validateToolArgs(name, args || {});
3160
3349
  const result = await handler(args || {});
3161
3350
  notifyResourceChanges(name);
3162
3351
  return result;
3163
3352
  } catch (e) {
3164
- log(`Tool call error [${name}]: ${e.message}`);
3353
+ error(`Tool call error [${name}]: ${e.message}`, { tool: name, args });
3165
3354
  return { content: [{ type: "text", text: `\u5DE5\u5177\u6267\u884C\u9519\u8BEF: ${e.message}` }], isError: true };
3166
3355
  }
3167
3356
  }
@@ -3188,222 +3377,38 @@ async function initCadConnection() {
3188
3377
  try {
3189
3378
  const connected = await cad.connect();
3190
3379
  if (connected) {
3191
- log("Auto-connected to CAD: " + cad.getPlatform() + " " + cad.getVersion());
3192
- console.error("\u5DF2\u81EA\u52A8\u8FDE\u63A5\u5230 CAD: " + cad.getPlatform() + " " + cad.getVersion());
3380
+ log(`Auto-connected to CAD: ${cad.getPlatform()} ${cad.getVersion()}`);
3381
+ console.error(`\u5DF2\u81EA\u52A8\u8FDE\u63A5\u5230 CAD: ${cad.getPlatform()} ${cad.getVersion()}`);
3193
3382
  } else {
3194
3383
  log("No CAD found on startup");
3195
3384
  }
3196
3385
  } catch (e) {
3197
- log("Auto-connect failed: " + e.message);
3386
+ error(`Auto-connect failed: ${e.message}`);
3198
3387
  }
3199
3388
  }
3200
- var sessionServers = /* @__PURE__ */ new Map();
3201
- var sessionTransports = /* @__PURE__ */ new Map();
3202
- function createMcpServer() {
3203
- const server = new Server(
3204
- { name: SERVER_NAME, version: SERVER_VERSION },
3205
- { capabilities: SERVER_CAPABILITIES }
3206
- );
3207
- server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
3208
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
3209
- const { name, arguments: args } = request.params;
3210
- return await handleToolCall(name, args || {});
3211
- });
3212
- server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
3213
- const ctx = mcpContext.getStore();
3214
- const sessionId = ctx?.sessionId;
3215
- const subscribedUris = sessionId ? list(sessionId) : list();
3216
- return {
3217
- resources: await listResources(subscribedUris)
3218
- };
3219
- });
3220
- server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
3221
- const { uri } = request.params;
3222
- try {
3223
- const data = await readResource(uri);
3224
- return {
3225
- contents: [{
3226
- uri,
3227
- mimeType: "application/json",
3228
- text: JSON.stringify(data)
3229
- }]
3230
- };
3231
- } catch (e) {
3232
- return {
3233
- contents: [],
3234
- isError: true,
3235
- error: { code: -32603, message: e.message }
3236
- };
3237
- }
3238
- });
3239
- server.setRequestHandler(SubscribeRequestSchema, async (request) => {
3240
- const { uri } = request.params;
3241
- const ctx = mcpContext.getStore();
3242
- subscribe(uri, ctx?.sessionId);
3243
- return { success: true };
3244
- });
3245
- server.setRequestHandler(UnsubscribeRequestSchema, async (request) => {
3246
- const { uri } = request.params;
3247
- const ctx = mcpContext.getStore();
3248
- unsubscribe(uri, ctx?.sessionId);
3249
- return { success: true };
3250
- });
3251
- server.setRequestHandler(ListPromptsRequestSchema, async () => ({
3252
- prompts: await listPrompts()
3253
- }));
3254
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
3255
- const { name, arguments: args } = request.params;
3256
- return await getPrompt(name, args || {});
3257
- });
3258
- return server;
3259
- }
3260
3389
  async function startServer() {
3261
3390
  if (config_default.transport === "stdio") {
3262
3391
  await initCadConnection();
3263
- const mcpServer = createMcpServer();
3264
- const transport2 = new StdioServerTransport();
3392
+ const mcpServer = createStdioServer({ tools, handleToolCall });
3393
+ const transport = new StdioServerTransport();
3265
3394
  const sessionId = "stdio-session";
3266
3395
  sessionManager.createSession(sessionId);
3267
3396
  await mcpContext.run({ sessionId }, async () => {
3268
- await mcpServer.connect(transport2);
3397
+ await mcpServer.connect(transport);
3269
3398
  });
3270
3399
  console.error(`${SERVER_NAME} \u8FD0\u884C\u5728 stdio \u6A21\u5F0F`);
3271
3400
  setNotify((uri, data) => {
3272
3401
  mcpServer.sendResourceUpdated({ uri }).catch((err) => {
3273
- log(`Failed to send resource update: ${err.message}`);
3402
+ error(`Failed to send resource update: ${err.message}`);
3274
3403
  });
3275
3404
  });
3276
3405
  } else {
3277
- const app = express();
3278
- const JSON_CONTENT_TYPES = ["application/json", "application/json-rpc", "application/vnd.api+json"];
3279
- app.use(async (req, res, next) => {
3280
- const ct = (req.headers["content-type"] || "").toLowerCase();
3281
- if (!JSON_CONTENT_TYPES.some((t) => ct.startsWith(t))) return next();
3282
- try {
3283
- const buf = await rawBody(req, { limit: "10mb" });
3284
- const m = ct.match(/charset\s*=\s*([^\s;]+)/i);
3285
- let charset = m ? m[1].toLowerCase() : "utf-8";
3286
- const charsetMap = { "gb2312": "gbk", "gb18030": "gbk", "gbk": "gbk", "936": "gbk" };
3287
- charset = charsetMap[charset] || charset;
3288
- const str = encodingExists(charset) ? charsetDecode(buf, charset) : buf.toString("utf-8");
3289
- req.body = JSON.parse(str);
3290
- next();
3291
- } catch (e) {
3292
- res.status(400).json({ error: "Invalid JSON body", message: e.message });
3293
- }
3294
- });
3295
- app.use((req, res, next) => {
3296
- log(`${req.method} ${req.path}`);
3297
- next();
3298
- });
3299
- const PUBLIC_PATHS = ["/health"];
3300
- if (apiKey) {
3301
- app.use((req, res, next) => {
3302
- if (PUBLIC_PATHS.includes(req.path)) return next();
3303
- const auth = req.get("Authorization");
3304
- if (auth === `Bearer ${apiKey}`) return next();
3305
- res.status(401).json({ error: "Unauthorized" });
3306
- });
3307
- }
3308
- app.get("/health", (req, res) => {
3309
- res.json({ status: "ok", cad: cad.connected ? "connected" : "disconnected" });
3310
- });
3311
- if (config_default.enableCors) {
3312
- app.use((req, res, next) => {
3313
- res.setHeader("Access-Control-Allow-Origin", config_default.corsOrigin);
3314
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, CONNECT");
3315
- res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, mcp-session-id, last-event-id");
3316
- res.setHeader("Access-Control-Expose-Headers", "mcp-session-id, content-type, x-accel-buffering");
3317
- res.setHeader("Access-Control-Max-Age", "86400");
3318
- res.setHeader("Vary", "Accept");
3319
- if (req.method === "OPTIONS") return res.status(204).end();
3320
- next();
3321
- });
3322
- }
3406
+ const app = express2();
3407
+ setupRoutes(app);
3323
3408
  setNotify((uri, data) => {
3324
3409
  broadcastToAllSessions(uri);
3325
- for (const session of sseSessionManager.listActive()) {
3326
- sseSessionManager.sendToClient(session.clientId, "resource_updated", { uri });
3327
- }
3328
- });
3329
- async function handleMcpPost(req, res) {
3330
- const sessionId = req.headers["mcp-session-id"] || req.query.sessionId || randomUUID4();
3331
- sessionManager.createSession(sessionId);
3332
- const body = req.body;
3333
- if (!body || !body.method) {
3334
- return res.status(400).json({ error: "Invalid request" });
3335
- }
3336
- const { server, transport: transport2 } = getOrCreateSessionServer(sessionId);
3337
- transport2.resetCleanupTimer();
3338
- await mcpContext.run({ sessionId }, async () => {
3339
- try {
3340
- const response = await transport2.handleRequest(body);
3341
- if (response) {
3342
- const headers = { "Content-Type": "application/json" };
3343
- if (transport2.sessionId) {
3344
- headers["mcp-session-id"] = transport2.sessionId;
3345
- }
3346
- res.writeHead(200, headers);
3347
- res.end(JSON.stringify(response));
3348
- } else {
3349
- if (!res.headersSent) {
3350
- res.status(202).end();
3351
- }
3352
- }
3353
- } catch (error) {
3354
- log(`Transport error [${sessionId}]: ${error.message}`);
3355
- if (!res.headersSent) {
3356
- res.status(500).json({ error: "Internal server error", message: error.message });
3357
- }
3358
- }
3359
- });
3360
- }
3361
- app.all("/mcp", mcpLimiter, handleMcpPost);
3362
- app.all("/mcp/:path", mcpLimiter, handleMcpPost);
3363
- app.get("/mcp/stream", mcpLimiter, handleMcpPost);
3364
- const sseEndpoint = "/sse";
3365
- app.get(sseEndpoint, async (req, res) => {
3366
- const sessionId = randomUUID4();
3367
- sessionManager.createSession(sessionId);
3368
- getOrCreateSessionServer(sessionId);
3369
- const sseSession = new SseSession(res, { clientId: sessionId });
3370
- sseSessionManager.add(sessionId, sseSession);
3371
- sseSession.sendEndpoint(`/message?sessionId=${sessionId}`);
3372
- req.on("close", () => {
3373
- sseSessionManager.remove(sessionId);
3374
- removeSessionServer(sessionId);
3375
- });
3376
- });
3377
- app.post("/message", mcpLimiter, async (req, res) => {
3378
- const sessionId = req.query.sessionId;
3379
- if (!sessionId) {
3380
- return res.status(400).json({ error: "Missing sessionId" });
3381
- }
3382
- const sseSession = sseSessionManager.get(sessionId);
3383
- if (!sseSession) {
3384
- return res.status(404).json({ error: "Session not found" });
3385
- }
3386
- sessionManager.createSession(sessionId);
3387
- const { server, transport: transport2 } = getOrCreateSessionServer(sessionId);
3388
- transport2.resetCleanupTimer();
3389
- const body = req.body;
3390
- if (body && body.method) {
3391
- try {
3392
- const response = await transport2.handleRequest(body);
3393
- if (response) {
3394
- sseSession.sendResponse(response);
3395
- }
3396
- if (!res.headersSent) {
3397
- res.status(202).end();
3398
- }
3399
- } catch (error) {
3400
- log(`SSE message error [${sessionId}]: ${error.message}`);
3401
- if (!res.headersSent) {
3402
- res.status(500).json({ error: "Internal server error" });
3403
- }
3404
- }
3405
- } else {
3406
- res.status(400).json({ error: "Invalid request" });
3410
+ for (const session of sseSessionManager2.listActive()) {
3411
+ sseSessionManager2.sendToClient(session.clientId, "resource_updated", { uri });
3407
3412
  }
3408
3413
  });
3409
3414
  const httpServer = app.listen(config_default.port, config_default.host, async () => {
@@ -3413,7 +3418,7 @@ async function startServer() {
3413
3418
  async function shutdown(signal) {
3414
3419
  console.error(`
3415
3420
  \u6536\u5230 ${signal}\uFF0C\u6B63\u5728\u4F18\u96C5\u5173\u95ED...`);
3416
- sseSessionManager.closeAll();
3421
+ sseSessionManager2.closeAll();
3417
3422
  sessionManager.clear();
3418
3423
  for (const [sid] of sessionServers) {
3419
3424
  removeSessionServer(sid);
@@ -3427,14 +3432,285 @@ async function startServer() {
3427
3432
  process.on("SIGTERM", () => shutdown("SIGTERM"));
3428
3433
  }
3429
3434
  }
3430
- if (!process.env.VITEST) {
3431
- await startServer();
3432
- }
3435
+ var __dirname4, require2, version, sseSessionManager2, isMcpScript, CACHE_DIR2, FUNCLIB_CACHE_FILE2, CACHE_TTL3, FUNCTION_LIB_URL, cachedFunctionLib, cachedAt2, toolInputSchema, TOOL_HANDLERS, tools;
3436
+ var init_atlisp_mcp = __esm({
3437
+ async "src/atlisp-mcp.js"() {
3438
+ init_cad();
3439
+ init_constants();
3440
+ init_logger();
3441
+ init_cad_handlers();
3442
+ init_package_handlers();
3443
+ init_function_handlers();
3444
+ init_resource_handlers();
3445
+ init_prompt_handlers();
3446
+ init_subscription_manager();
3447
+ init_subscription_manager();
3448
+ init_sse_session_manager();
3449
+ init_sse_session();
3450
+ init_config();
3451
+ init_routes();
3452
+ init_mcp_server_state();
3453
+ init_constants();
3454
+ __dirname4 = path7.dirname(fileURLToPath4(import.meta.url));
3455
+ require2 = createRequire(import.meta.url);
3456
+ ({ version } = require2(path7.join(__dirname4, "..", "package.json")));
3457
+ sseSessionManager2 = new SseSessionManager();
3458
+ isMcpScript = process.argv[1]?.includes("atlisp-mcp");
3459
+ if (isMcpScript) {
3460
+ const args = process.argv.slice(2);
3461
+ for (let i = 0; i < args.length; i++) {
3462
+ if (args[i] === "--version" || args[i] === "-v") {
3463
+ console.log(`atlisp-mcp v${version}`);
3464
+ process.exit(0);
3465
+ } else if (args[i] === "--help" || args[i] === "-h") {
3466
+ console.log(`
3467
+ @lisp MCP Server v${version}
3468
+
3469
+ Usage: atlisp-mcp [options]
3470
+
3471
+ Options:
3472
+ -v, --version Show version number
3473
+ --transport <type> Transport type: http or stdio (default: http)
3474
+ --port <port> HTTP port (default: 8110)
3475
+ --host <host> HTTP host (default: 0.0.0.0)
3476
+ --stdio Shorthand for --transport stdio
3477
+ -h, --help Show this help message
3478
+
3479
+ Examples:
3480
+ atlisp-mcp # Start HTTP server on port 8110
3481
+ atlisp-mcp --port 3000 # Start HTTP server on port 3000
3482
+ atlisp-mcp --stdio # Start in stdio mode for MCP clients
3483
+ atlisp-mcp --transport stdio # Same as --stdio
3484
+ `);
3485
+ process.exit(0);
3486
+ } else if (args[i] === "--transport" && args[i + 1]) {
3487
+ process.env.TRANSPORT = args[i + 1];
3488
+ i++;
3489
+ } else if (args[i] === "--stdio") {
3490
+ process.env.TRANSPORT = "stdio";
3491
+ } else if (args[i] === "--port" && args[i + 1]) {
3492
+ process.env.PORT = args[i + 1];
3493
+ i++;
3494
+ } else if (args[i] === "--host" && args[i + 1]) {
3495
+ process.env.HOST = args[i + 1];
3496
+ i++;
3497
+ }
3498
+ }
3499
+ }
3500
+ if (config_default.apiKey) log("API Key authentication enabled");
3501
+ CACHE_DIR2 = path7.join(os4.homedir(), ".atlisp", "cache");
3502
+ FUNCLIB_CACHE_FILE2 = path7.join(CACHE_DIR2, "functions.json");
3503
+ CACHE_TTL3 = config_default.functionLibCacheTtl || 5 * 60 * 1e3;
3504
+ FUNCTION_LIB_URL = config_default.functionLibUrl || "http://s3.atlisp.cn/json/functions.json";
3505
+ cachedFunctionLib = null;
3506
+ cachedAt2 = null;
3507
+ toolInputSchema = {
3508
+ connect_cad: { platform: "string?" },
3509
+ eval_lisp: { code: "string" },
3510
+ eval_lisp_with_result: { code: "string", encoding: "string?" },
3511
+ search_packages: { query: "string" },
3512
+ install_package: { packageName: "string" },
3513
+ at_command: { command: "string" },
3514
+ get_function_usage: { name: "string", package: "string?" },
3515
+ list_symbols: { package: "string?" },
3516
+ import_funlib: { format: "string?" },
3517
+ get_prompt: { name: "string", args: "object?" }
3518
+ };
3519
+ TOOL_HANDLERS = {
3520
+ connect_cad: (a) => connectCad(a?.platform),
3521
+ eval_lisp: (a) => evalLisp(a.code),
3522
+ eval_lisp_with_result: (a) => evalLisp(a.code, true, a.encoding),
3523
+ get_cad_info: () => getCadInfo(),
3524
+ list_packages: () => listPackages(),
3525
+ search_packages: (a) => searchPackages(a.query),
3526
+ install_package: (a) => installPackage(a.packageName),
3527
+ get_platform_info: () => ({ content: [{ type: "text", text: `\u652F\u6301\u7684 CAD \u5E73\u53F0:
3528
+ ${CAD_PLATFORMS.join("\n")}
3529
+ \u5F53\u524D\u8FDE\u63A5: ${cad.connected ? "\u5DF2\u8FDE\u63A5" : "\u672A\u8FDE\u63A5"}` }] }),
3530
+ at_command: (a) => atCommand(a.command),
3531
+ new_document: () => newDocument(),
3532
+ bring_to_front: () => bringToFront(),
3533
+ install_atlisp: () => installAtlisp(),
3534
+ init_atlisp: () => initAtlisp(),
3535
+ get_function_usage: (a) => getFunctionUsage(a.name, a.package),
3536
+ list_symbols: (a) => listSymbols(a.package),
3537
+ get_system_status: () => getSystemStatus(),
3538
+ list_prompts: async () => {
3539
+ const prompts = await listPrompts();
3540
+ return { content: [{ type: "text", text: JSON.stringify(prompts) }] };
3541
+ },
3542
+ get_prompt: async (a) => {
3543
+ const prompt = await getPrompt(a.name, a.args || {});
3544
+ return { content: prompt.messages.map((m) => ({ type: "text", text: m.content.text || m.content })) };
3545
+ },
3546
+ import_funlib: async (a) => {
3547
+ const data = await loadAtlibFunctionLib();
3548
+ if (!data) return { content: [{ type: "text", text: "\u52A0\u8F7D\u51FD\u6570\u5E93\u5931\u8D25" }], isError: true };
3549
+ if (a.format === "list") {
3550
+ const items = Object.values(data.all_functions || {}).map((f) => `${f.name}: ${f.description || ""}`);
3551
+ return { content: [{ type: "text", text: items.join("\n") }] };
3552
+ }
3553
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
3554
+ }
3555
+ };
3556
+ tools = [
3557
+ {
3558
+ name: "connect_cad",
3559
+ description: "\u8FDE\u63A5\u5230 CAD (AutoCAD/ZWCAD/GStarCAD/BricsCAD)",
3560
+ inputSchema: {
3561
+ type: "object",
3562
+ properties: {
3563
+ platform: { type: "string", description: "\u6307\u5B9A CAD \u5E73\u53F0: AutoCAD, ZWCAD, GStarCAD, BricsCAD\uFF08\u53EF\u9009\uFF0C\u81EA\u52A8\u68C0\u6D4B\uFF09" }
3564
+ }
3565
+ }
3566
+ },
3567
+ {
3568
+ name: "eval_lisp",
3569
+ description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\uFF08\u4E0D\u8FD4\u56DE\u7ED3\u679C\uFF09",
3570
+ inputSchema: {
3571
+ type: "object",
3572
+ properties: { code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" } },
3573
+ required: ["code"]
3574
+ }
3575
+ },
3576
+ {
3577
+ name: "eval_lisp_with_result",
3578
+ description: "\u5728 CAD \u4E2D\u6267\u884C AutoLISP \u4EE3\u7801\u5E76\u8FD4\u56DE\u7ED3\u679C",
3579
+ inputSchema: {
3580
+ type: "object",
3581
+ properties: {
3582
+ code: { type: "string", description: "\u8981\u6267\u884C\u7684 LISP \u4EE3\u7801" },
3583
+ encoding: { type: "string", description: "\u7ED3\u679C\u7F16\u7801\uFF0C\u5982 utf-8, gbk, gb2312, gb18030\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4\u81EA\u52A8\u68C0\u6D4B\uFF09" }
3584
+ },
3585
+ required: ["code"]
3586
+ }
3587
+ },
3588
+ {
3589
+ name: "get_cad_info",
3590
+ description: "\u83B7\u53D6\u5F53\u524D CAD \u4FE1\u606F",
3591
+ inputSchema: { type: "object", properties: {} }
3592
+ },
3593
+ {
3594
+ name: "list_packages",
3595
+ description: "\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 @lisp \u5305",
3596
+ inputSchema: { type: "object", properties: {} }
3597
+ },
3598
+ {
3599
+ name: "search_packages",
3600
+ description: "\u641C\u7D22 @lisp \u5305",
3601
+ inputSchema: {
3602
+ type: "object",
3603
+ properties: { query: { type: "string", description: "\u641C\u7D22\u5173\u952E\u8BCD" } },
3604
+ required: ["query"]
3605
+ }
3606
+ },
3607
+ {
3608
+ name: "install_package",
3609
+ description: "\u5B89\u88C5 @lisp \u5305\u5230 CAD",
3610
+ inputSchema: {
3611
+ type: "object",
3612
+ properties: { packageName: { type: "string", description: "\u5305\u540D\u79F0" } },
3613
+ required: ["packageName"]
3614
+ }
3615
+ },
3616
+ {
3617
+ name: "get_platform_info",
3618
+ description: "\u83B7\u53D6 CAD \u5E73\u53F0\u4FE1\u606F",
3619
+ inputSchema: { type: "object", properties: {} }
3620
+ },
3621
+ {
3622
+ name: "at_command",
3623
+ description: "\u6267\u884C @lisp \u547D\u4EE4",
3624
+ inputSchema: {
3625
+ type: "object",
3626
+ properties: { command: { type: "string", description: "@lisp \u547D\u4EE4" } },
3627
+ required: ["command"]
3628
+ }
3629
+ },
3630
+ {
3631
+ name: "new_document",
3632
+ description: "\u5728 CAD \u4E2D\u65B0\u5EFA\u7A7A\u767D\u6587\u6863",
3633
+ inputSchema: { type: "object", properties: {} }
3634
+ },
3635
+ {
3636
+ name: "bring_to_front",
3637
+ description: "\u5C06 CAD \u7A97\u53E3\u5207\u6362\u5230\u524D\u53F0\uFF08\u4ECE\u540E\u53F0\u8FD0\u884C\u72B6\u6001\u5524\u9192\uFF09",
3638
+ inputSchema: { type: "object", properties: {} }
3639
+ },
3640
+ {
3641
+ name: "install_atlisp",
3642
+ description: "\u5728 CAD \u4E2D\u5B89\u88C5 @lisp",
3643
+ inputSchema: { type: "object", properties: {} }
3644
+ },
3645
+ {
3646
+ name: "init_atlisp",
3647
+ description: "\u521D\u59CB\u5316 CAD \u4E2D\u7684 @lisp \u73AF\u5883\uFF0C\u52A0\u8F7D\u51FD\u6570\u5E93\u548C\u521D\u59CB\u53D8\u91CF",
3648
+ inputSchema: { type: "object", properties: {} }
3649
+ },
3650
+ {
3651
+ name: "get_function_usage",
3652
+ description: "\u83B7\u53D6 @lisp \u51FD\u6570\u7528\u6CD5",
3653
+ inputSchema: {
3654
+ type: "object",
3655
+ properties: {
3656
+ name: { type: "string", description: "\u51FD\u6570\u540D\uFF0C\u5982 string:length" },
3657
+ package: { type: "string", description: "\u5305\u540D\uFF0C\u5982 string\uFF08\u53EF\u9009\uFF0C\u4E0D\u4F20\u5219\u81EA\u52A8\u641C\u7D22\uFF09" }
3658
+ },
3659
+ required: ["name"]
3660
+ }
3661
+ },
3662
+ {
3663
+ name: "list_symbols",
3664
+ description: "\u5217\u51FA @lisp \u6240\u6709\u7B26\u53F7\uFF0C\u7528\u4E8E\u68C0\u67E5\u51FD\u6570\u548C\u53D8\u91CF",
3665
+ inputSchema: {
3666
+ type: "object",
3667
+ properties: {
3668
+ package: { type: "string", description: "\u5305\u540D\uFF08\u53EF\u9009\uFF09" }
3669
+ }
3670
+ }
3671
+ },
3672
+ {
3673
+ name: "import_funlib",
3674
+ description: "\u4ECE\u7F51\u7EDC\u5BFC\u5165 @lisp \u51FD\u6570\u5E93\u6570\u636E\u5230 AI Agent",
3675
+ inputSchema: {
3676
+ type: "object",
3677
+ properties: {
3678
+ 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" }
3679
+ }
3680
+ }
3681
+ },
3682
+ {
3683
+ name: "get_system_status",
3684
+ description: "\u83B7\u53D6\u5B8C\u6574\u7CFB\u7EDF\u8BCA\u65AD\u4FE1\u606F\uFF1AMCP \u72B6\u6001\u3001CAD \u8FDE\u63A5\u3001Lisp \u6267\u884C\u3001\u5305\u5217\u8868",
3685
+ inputSchema: { type: "object", properties: {} }
3686
+ },
3687
+ {
3688
+ name: "list_prompts",
3689
+ description: "\u5217\u51FA\u6240\u6709\u53EF\u7528\u7684 @lisp \u63D0\u793A\u6A21\u677F",
3690
+ inputSchema: { type: "object", properties: {} }
3691
+ },
3692
+ {
3693
+ name: "get_prompt",
3694
+ description: "\u83B7\u53D6\u6307\u5B9A\u63D0\u793A\u6A21\u677F\u7684\u5185\u5BB9",
3695
+ inputSchema: {
3696
+ type: "object",
3697
+ properties: {
3698
+ name: { type: "string", description: "\u63D0\u793A\u6A21\u677F\u540D\u79F0" },
3699
+ args: { type: "object", description: "\u6A21\u677F\u53C2\u6570\uFF08\u53EF\u9009\uFF09" }
3700
+ },
3701
+ required: ["name"]
3702
+ }
3703
+ }
3704
+ ];
3705
+ if (!process.env.VITEST) {
3706
+ await startServer();
3707
+ }
3708
+ }
3709
+ });
3710
+ await init_atlisp_mcp();
3433
3711
  export {
3434
3712
  CAD_PLATFORMS,
3435
3713
  FILE_EXTENSIONS,
3436
- MOCK_PACKAGES,
3437
- createMcpServer,
3438
3714
  handleToolCall,
3439
3715
  loadAtlibFunctionLib,
3440
3716
  startServer,