@atlisp/mcp 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/atlisp-mcp.js +199 -43
  2. package/package.json +1 -1
@@ -365,7 +365,7 @@ function sendMessage(msg) {
365
365
  }
366
366
  });
367
367
  }
368
- var MESSAGE_TIMEOUT, HEARTBEAT_INTERVAL, MAX_RESTART_ATTEMPTS, RESTART_BACKOFF_BASE, __dirname, workerPath, worker, _platform, heartbeatTimer, pendingRequests, stdoutHandlerSetup, MAX_BUFFER_SIZE, restartCount, restartTimer, PRIORITY_NORMAL, CommandQueue, commandQueue, CadConnection, cad, cad_default;
368
+ var MESSAGE_TIMEOUT, HEARTBEAT_INTERVAL, MAX_RESTART_ATTEMPTS, RESTART_BACKOFF_BASE, __dirname, workerPath, worker, _platform, heartbeatTimer, pendingRequests, stdoutHandlerSetup, MAX_BUFFER_SIZE, restartCount, restartTimer, PRIORITY_NORMAL, MAX_QUEUE_SIZE, CommandQueue, commandQueue, CadConnection, cad, cad_default;
369
369
  var init_cad = __esm({
370
370
  "src/cad.js"() {
371
371
  init_constants();
@@ -385,11 +385,17 @@ var init_cad = __esm({
385
385
  restartCount = 0;
386
386
  restartTimer = null;
387
387
  PRIORITY_NORMAL = 1;
388
+ MAX_QUEUE_SIZE = 500;
388
389
  CommandQueue = class {
389
390
  #queues = [[], [], []];
390
391
  #processing = false;
391
392
  #dedupMap = /* @__PURE__ */ new Map();
392
393
  enqueue(command, priority = PRIORITY_NORMAL) {
394
+ const total = this.#queues.reduce((s, q) => s + q.length, 0);
395
+ if (total >= MAX_QUEUE_SIZE) {
396
+ command.reject(new Error("Command queue full, try again later"));
397
+ return;
398
+ }
393
399
  const dedupKey = this._dedupKey(command);
394
400
  if (dedupKey) {
395
401
  const existing = this.#dedupMap.get(dedupKey);
@@ -689,6 +695,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
689
695
  // src/logger.js
690
696
  init_config();
691
697
  import fs2 from "fs";
698
+ import fsp from "fs/promises";
692
699
  import path3 from "path";
693
700
  import os2 from "os";
694
701
  var DEBUG_FILE = config_default.debugFile || path3.join(os2.tmpdir(), "mcp-server-debug.log");
@@ -696,28 +703,33 @@ var MAX_LOG_SIZE = 10 * 1024 * 1024;
696
703
  var MAX_LOG_FILES = 5;
697
704
  var stream = null;
698
705
  function rotateLog() {
699
- if (!fs2.existsSync(DEBUG_FILE))
700
- return;
701
- const stat = fs2.statSync(DEBUG_FILE);
702
- if (stat.size < MAX_LOG_SIZE)
703
- return;
704
- if (stream) {
705
- stream.end();
706
- stream = null;
707
- }
708
- for (let i = MAX_LOG_FILES - 1; i > 0; i--) {
709
- const oldPath = `${DEBUG_FILE}.${i}`;
710
- const newPath = `${DEBUG_FILE}.${i + 1}`;
711
- if (fs2.existsSync(oldPath)) {
712
- try {
713
- fs2.renameSync(oldPath, newPath);
714
- } catch {
706
+ try {
707
+ if (!fs2.existsSync(DEBUG_FILE))
708
+ return;
709
+ const stat = fs2.statSync(DEBUG_FILE);
710
+ if (stat.size < MAX_LOG_SIZE)
711
+ return;
712
+ if (stream) {
713
+ stream.end();
714
+ stream = null;
715
+ }
716
+ for (let i = MAX_LOG_FILES - 1; i > 0; i--) {
717
+ const oldPath = `${DEBUG_FILE}.${i}`;
718
+ if (fs2.existsSync(oldPath)) {
719
+ try {
720
+ fs2.renameSync(oldPath, `${DEBUG_FILE}.${i + 1}`);
721
+ } catch (e) {
722
+ console.error("log rotate rename error:", e.message);
723
+ }
715
724
  }
716
725
  }
717
- }
718
- try {
719
- fs2.renameSync(DEBUG_FILE, `${DEBUG_FILE}.1`);
720
- } catch {
726
+ try {
727
+ fs2.renameSync(DEBUG_FILE, `${DEBUG_FILE}.1`);
728
+ } catch (e) {
729
+ console.error("log rotate rename error:", e.message);
730
+ }
731
+ } catch (e) {
732
+ console.error("log rotate error:", e.message);
721
733
  }
722
734
  }
723
735
  function getStream() {
@@ -756,7 +768,90 @@ function closeLog() {
756
768
  stream = null;
757
769
  }
758
770
  }
759
- var REQUEST_LOG_FILE = path3.join(os2.hmpdir || os2.homedir(), "@lisp", "logs", "requests.log");
771
+ var requestStream = null;
772
+ var REQUEST_LOG_FILE = path3.join(os2.homedir(), "@lisp", "logs", "requests.log");
773
+ function ensureRequestLogDir() {
774
+ const dir = path3.dirname(REQUEST_LOG_FILE);
775
+ if (!fs2.existsSync(dir)) {
776
+ try {
777
+ fs2.mkdirSync(dir, { recursive: true });
778
+ } catch (e) {
779
+ console.error("request log mkdir error:", e.message);
780
+ }
781
+ }
782
+ }
783
+ function rotateRequestLog() {
784
+ try {
785
+ if (!fs2.existsSync(REQUEST_LOG_FILE))
786
+ return;
787
+ const stat = fs2.statSync(REQUEST_LOG_FILE);
788
+ if (stat.size < 10 * 1024 * 1024)
789
+ return;
790
+ if (requestStream) {
791
+ requestStream.end();
792
+ requestStream = null;
793
+ }
794
+ for (let i = 5; i > 0; i--) {
795
+ const oldPath = `${REQUEST_LOG_FILE}.${i}`;
796
+ if (fs2.existsSync(oldPath)) {
797
+ try {
798
+ fs2.renameSync(oldPath, `${REQUEST_LOG_FILE}.${i + 1}`);
799
+ } catch (e) {
800
+ console.error("request log rotate error:", e.message);
801
+ }
802
+ }
803
+ }
804
+ try {
805
+ fs2.renameSync(REQUEST_LOG_FILE, `${REQUEST_LOG_FILE}.1`);
806
+ } catch (e) {
807
+ console.error("request log rotate error:", e.message);
808
+ }
809
+ } catch (e) {
810
+ console.error("request log rotate error:", e.message);
811
+ }
812
+ }
813
+ function logRequest(req) {
814
+ if (!config_default.requestLogEnabled)
815
+ return;
816
+ try {
817
+ ensureRequestLogDir();
818
+ rotateRequestLog();
819
+ if (!requestStream) {
820
+ requestStream = fs2.createWriteStream(REQUEST_LOG_FILE, { flags: "a" });
821
+ }
822
+ const entry = {
823
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
824
+ method: req.method,
825
+ path: req.path,
826
+ query: req.query,
827
+ ip: req.ip || req.connection?.remoteAddress,
828
+ userAgent: req.get("user-agent")
829
+ };
830
+ requestStream.write(JSON.stringify(entry) + "\n");
831
+ } catch (e) {
832
+ console.error("request log error:", e.message);
833
+ }
834
+ }
835
+ function logResponse(req, res, duration) {
836
+ if (!config_default.requestLogEnabled)
837
+ return;
838
+ try {
839
+ ensureRequestLogDir();
840
+ if (!requestStream) {
841
+ requestStream = fs2.createWriteStream(REQUEST_LOG_FILE, { flags: "a" });
842
+ }
843
+ const entry = {
844
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
845
+ method: req.method,
846
+ path: req.path,
847
+ statusCode: res.statusCode,
848
+ duration: `${duration}ms`
849
+ };
850
+ requestStream.write(JSON.stringify(entry) + "\n");
851
+ } catch (e) {
852
+ console.error("request log error:", e.message);
853
+ }
854
+ }
760
855
 
761
856
  // src/handlers/resource-defs.js
762
857
  import path4 from "path";
@@ -862,20 +957,68 @@ init_config();
862
957
  import fs3 from "fs";
863
958
  import path5 from "path";
864
959
 
960
+ // src/errors.js
961
+ var ERROR_CODES = {
962
+ CAD_NOT_CONNECTED: "CAD_NOT_CONNECTED",
963
+ CAD_BUSY: "CAD_BUSY",
964
+ CAD_NO_DOCUMENT: "CAD_NO_DOCUMENT",
965
+ LISP_PAREN_MISMATCH: "LISP_PAREN_MISMATCH",
966
+ TIMEOUT: "TIMEOUT",
967
+ INVALID_PARAMS: "INVALID_PARAMS",
968
+ METHOD_NOT_FOUND: "METHOD_NOT_FOUND",
969
+ RESOURCE_NOT_FOUND: "RESOURCE_NOT_FOUND",
970
+ PACKAGE_NOT_FOUND: "PACKAGE_NOT_FOUND",
971
+ INTERNAL_ERROR: "INTERNAL_ERROR"
972
+ };
973
+ var ERROR_MESSAGES = {
974
+ [ERROR_CODES.CAD_NOT_CONNECTED]: "\u672A\u8FDE\u63A5 CAD\uFF0C\u8BF7\u5148\u8C03\u7528 connect_cad",
975
+ [ERROR_CODES.CAD_BUSY]: "CAD \u5FD9\u788C\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5",
976
+ [ERROR_CODES.CAD_NO_DOCUMENT]: "CAD \u4E2D\u6CA1\u6709\u6253\u5F00\u7684\u6587\u6863",
977
+ [ERROR_CODES.LISP_PAREN_MISMATCH]: "LISP \u4EE3\u7801\u62EC\u53F7\u4E0D\u5339\u914D",
978
+ [ERROR_CODES.TIMEOUT]: "\u64CD\u4F5C\u8D85\u65F6",
979
+ [ERROR_CODES.INVALID_PARAMS]: "\u65E0\u6548\u7684\u53C2\u6570",
980
+ [ERROR_CODES.METHOD_NOT_FOUND]: "\u65B9\u6CD5\u4E0D\u5B58\u5728",
981
+ [ERROR_CODES.RESOURCE_NOT_FOUND]: "\u8D44\u6E90\u4E0D\u5B58\u5728",
982
+ [ERROR_CODES.PACKAGE_NOT_FOUND]: "\u5305\u4E0D\u5B58\u5728",
983
+ [ERROR_CODES.INTERNAL_ERROR]: "\u5185\u90E8\u9519\u8BEF"
984
+ };
985
+ var MCPError = class extends Error {
986
+ constructor(code, message, details = {}) {
987
+ super(message);
988
+ this.code = code;
989
+ this.details = details;
990
+ this.name = "MCPError";
991
+ }
992
+ toJSON() {
993
+ return {
994
+ code: this.code,
995
+ message: this.message,
996
+ details: this.details
997
+ };
998
+ }
999
+ };
1000
+ function createError(code, details = {}) {
1001
+ const message = ERROR_MESSAGES[code] || ERROR_MESSAGES[ERROR_CODES.INTERNAL_ERROR];
1002
+ return new MCPError(code, message, details);
1003
+ }
1004
+ function mcpSuccessResponse(text) {
1005
+ return { content: [{ type: "text", text: String(text) }] };
1006
+ }
1007
+
865
1008
  // src/handler-utils.js
866
- init_cad();
867
1009
  function mcpSuccess(text) {
868
- return { content: [{ type: "text", text: String(text) }] };
1010
+ return mcpSuccessResponse(text);
869
1011
  }
870
1012
  function mcpError(text) {
871
1013
  return { content: [{ type: "text", text: String(text) }], isError: true };
872
1014
  }
873
1015
  async function ensureCadConnected() {
874
- if (!cad.connected) {
875
- await cad.connect();
1016
+ const { cad: cad2 } = await Promise.resolve().then(() => (init_cad(), cad_exports));
1017
+ if (!cad2.connected) {
1018
+ await cad2.connect();
876
1019
  }
877
- if (!cad.connected) {
878
- throw new Error("CAD \u672A\u8FDE\u63A5");
1020
+ if (!cad2.connected) {
1021
+ throw createError(ERROR_CODES.CAD_NOT_CONNECTED);
879
1022
  }
880
1023
  }
881
1024
  function escapeLispString(str) {
@@ -2610,7 +2753,9 @@ import {
2610
2753
  ListPromptsRequestSchema,
2611
2754
  GetPromptRequestSchema,
2612
2755
  ListRootsRequestSchema,
2613
- CreateMessageRequestSchema
2756
+ CreateMessageRequestSchema,
2757
+ CompleteRequestSchema,
2758
+ PingRequestSchema
2614
2759
  } from "@modelcontextprotocol/sdk/types.js";
2615
2760
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2616
2761
 
@@ -3122,12 +3267,11 @@ var RESOURCE_TEMPLATES = [
3122
3267
  }
3123
3268
  ];
3124
3269
  var SERVER_CAPABILITIES = {
3125
- tools: { completionNotification: true },
3126
- resources: { subscribe: true, listChanged: true, templates: true },
3270
+ tools: { listChanged: true },
3271
+ resources: { subscribe: true, listChanged: true },
3127
3272
  prompts: {},
3128
- roots: { listChanged: true },
3129
- sampling: {},
3130
- logging: {}
3273
+ logging: {},
3274
+ completions: {}
3131
3275
  };
3132
3276
  function createMcpServer(handlers = {}) {
3133
3277
  const { tools: tools18 = [], handleToolCall: handleToolCall2 = () => ({ content: [] }) } = handlers;
@@ -3202,15 +3346,27 @@ function createMcpServer(handlers = {}) {
3202
3346
  }));
3203
3347
  server.setRequestHandler(CreateMessageRequestSchema, async (request) => {
3204
3348
  const { message } = request.params;
3205
- logger.info("Sampling request received", { message: message.content?.[0]?.text });
3349
+ log("Sampling request received", { text: message.content?.[0]?.text });
3206
3350
  return {
3207
3351
  content: [{
3208
3352
  type: "text",
3209
- role: "user",
3210
- content: message.content[0]
3211
- }]
3353
+ text: "[sampling] LLM integration not configured; returning original message"
3354
+ }],
3355
+ model: "default",
3356
+ role: "assistant"
3357
+ };
3358
+ });
3359
+ server.setRequestHandler(CompleteRequestSchema, async (request) => {
3360
+ const { argument, ref } = request.params;
3361
+ return {
3362
+ completion: {
3363
+ values: [],
3364
+ hasMore: false,
3365
+ total: 0
3366
+ }
3212
3367
  };
3213
3368
  });
3369
+ server.setRequestHandler(PingRequestSchema, async () => ({ pong: true }));
3214
3370
  return server;
3215
3371
  }
3216
3372
 
@@ -8696,8 +8852,8 @@ function setupRoutes(app) {
8696
8852
  app.use((req, res, next) => {
8697
8853
  const start = Date.now();
8698
8854
  res.on("finish", () => {
8699
- log(req);
8700
- error(req, res, Date.now() - start);
8855
+ logRequest(req);
8856
+ logResponse(req, res, Date.now() - start);
8701
8857
  });
8702
8858
  next();
8703
8859
  });
@@ -8735,7 +8891,7 @@ function setupRoutes(app) {
8735
8891
  },
8736
8892
  mcp: {
8737
8893
  sessions: sessionServers.size,
8738
- tools: 60
8894
+ tools: tools17.length
8739
8895
  }
8740
8896
  });
8741
8897
  });
@@ -8791,7 +8947,7 @@ function setupRoutes(app) {
8791
8947
  <h1>@lisp MCP Server API</h1>
8792
8948
  <div class="info">
8793
8949
  <strong>Version:</strong> 1.6.0 |
8794
- <strong>Tools:</strong> 60 |
8950
+ <strong>Tools:</strong> ${tools17.length} |
8795
8951
  <strong>Resources:</strong> 11
8796
8952
  </div>
8797
8953
 
@@ -8917,7 +9073,7 @@ curl -X POST http://localhost:8110/mcp \\
8917
9073
  </table>
8918
9074
  </div>
8919
9075
 
8920
- <h2>Tools (${cad.getToolCount ? cad.getToolCount() : 60})</h2>
9076
+ <h2>Tools (${tools17.length})</h2>
8921
9077
  <div class="card">
8922
9078
  <p>Use <code>tools/list</code> MCP method to get full tool list.</p>
8923
9079
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlisp/mcp",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "MCP Server for @lisp on CAD,support AutoCAD/GstarCAD/ZWCAD/BricsCAD or CAD platform compatible with AutoLISP",
5
5
  "type": "module",
6
6
  "bin": {