@atlisp/mcp 1.0.7 → 1.0.9

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/package.json +1 -1
  2. package/src/index.js +74 -46
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlisp/mcp",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "MCP Server for @lisp on CAD",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  import fs from 'fs';
9
9
  import path from 'path';
10
10
  import os from 'os';
11
+ import crypto from 'crypto';
11
12
  import { cad } from './cad.js';
12
13
 
13
14
  const DEBUG_FILE = path.join(os.tmpdir(), 'mcp-server-debug.log');
@@ -197,8 +198,8 @@ async function handleToolCall(name, args) {
197
198
 
198
199
  case 'at_command':
199
200
  if (!cad.connected) return { content: [{ type: 'text', text: '请先连接 CAD' }], isError: true };
200
- await cad.sendCommand(`@${args.command}\n`);
201
- return { content: [{ type: 'text', text: `已发送命令: @${args.command}` }] };
201
+ await cad.sendCommand(`${args.command}\n`);
202
+ return { content: [{ type: 'text', text: `已发送命令: ${args.command}` }] };
202
203
 
203
204
  case 'new_document':
204
205
  if (!cad.connected) { await cad.connect(); }
@@ -221,21 +222,6 @@ async function handleToolCall(name, args) {
221
222
  }
222
223
  }
223
224
 
224
- const mcpServer = new Server(
225
- { name: 'atlisp-mcp-server', version: '1.0.7' },
226
- { capabilities: { tools: {} } }
227
- );
228
-
229
- mcpServer.setRequestHandler(ListToolsRequestSchema, async () => {
230
- return { tools };
231
- });
232
-
233
- mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
234
- console.error('setRequestHandler called, name:', request.params.name);
235
- const { name, arguments: args } = request.params;
236
- return await handleToolCall(name, args || {});
237
- });
238
-
239
225
  async function initCadConnection() {
240
226
  log('Attempting to connect to CAD on startup...');
241
227
  try {
@@ -251,8 +237,25 @@ async function initCadConnection() {
251
237
  }
252
238
  }
253
239
 
240
+ function createMcpServer() {
241
+ const server = new Server(
242
+ { name: 'atlisp-mcp-server', version: '1.0.9' },
243
+ { capabilities: { tools: {} } }
244
+ );
245
+
246
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
247
+
248
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
249
+ const { name, arguments: args } = request.params;
250
+ return await handleToolCall(name, args || {});
251
+ });
252
+
253
+ return server;
254
+ }
255
+
254
256
  if (TRANSPORT === 'stdio') {
255
257
  await initCadConnection();
258
+ const mcpServer = createMcpServer();
256
259
  const transport = new StdioServerTransport();
257
260
  await mcpServer.connect(transport);
258
261
  console.error('@lisp MCP Server 运行在 stdio 模式');
@@ -264,56 +267,82 @@ if (TRANSPORT === 'stdio') {
264
267
  res.json({ status: 'ok', cad: cad.connected ? 'connected' : 'disconnected' });
265
268
  });
266
269
 
270
+ let mcpServer = null;
271
+ const sessionId = crypto.randomUUID();
272
+
267
273
  app.post('/mcp', async (req, res) => {
268
- log('POST /mcp called, body: ' + JSON.stringify(req.body));
269
- try {
270
- const message = req.body;
271
- const id = message.id;
274
+ if (!mcpServer) {
275
+ mcpServer = createMcpServer();
276
+ }
277
+
278
+ const { method, params, id } = req.body || {};
279
+ const accept = req.get('Accept') || '';
280
+ log('accept: "' + accept + '", wantsSSE: ' + accept.includes('text/event-stream'));
281
+
282
+ res.setHeader('mcp-session-id', sessionId);
272
283
 
273
- if (!id) {
274
- log('No id, returning 204');
275
- return res.status(204).end();
284
+ const sendResponse = (data) => {
285
+ const json = JSON.stringify(data);
286
+ if (accept.includes('text/event-stream')) {
287
+ res.setHeader('Content-Type', 'text/event-stream');
288
+ return res.end('data: ' + json + '\n\n');
289
+ } else {
290
+ res.setHeader('Content-Type', 'application/json');
291
+ return res.end(json);
276
292
  }
293
+ };
294
+
295
+ if (!id) {
296
+ return res.status(204).end();
297
+ }
277
298
 
278
- if (message.method === 'initialize') {
279
- return res.json({
299
+ try {
300
+ if (method === 'initialize') {
301
+ sendResponse({
280
302
  jsonrpc: '2.0',
281
- id: id,
303
+ id,
282
304
  result: {
283
305
  protocolVersion: '2024-11-05',
284
306
  capabilities: { tools: {} },
285
- serverInfo: { name: 'atlisp-mcp-server', version: '1.0.7' }
307
+ serverInfo: { name: 'atlisp-mcp-server', version: '1.0.9' }
286
308
  }
287
309
  });
288
310
  }
289
311
 
290
- if (message.method === 'tools/list') {
291
- return res.json({
312
+ if (method === 'tools/list') {
313
+ sendResponse({
292
314
  jsonrpc: '2.0',
293
- id: id,
315
+ id,
294
316
  result: { tools }
295
317
  });
296
318
  }
297
319
 
298
- if (message.method === 'tools/call') {
299
- log('tools/call called, name: ' + message.params.name);
300
- const result = await handleToolCall(message.params.name, message.params.arguments || {});
301
- log('tools/call result: ' + JSON.stringify(result));
302
- return res.json({
303
- jsonrpc: '2.0',
304
- id: id,
305
- result
306
- });
320
+ if (method === 'tools/call') {
321
+ const toolName = params?.name;
322
+ if (!toolName) {
323
+ sendResponse({
324
+ jsonrpc: '2.0',
325
+ id,
326
+ error: { code: -32602, message: 'Invalid params: missing tool name' }
327
+ });
328
+ return;
329
+ }
330
+ const toolArgs = params?.arguments || {};
331
+ const result = await handleToolCall(toolName, toolArgs);
332
+ sendResponse({ jsonrpc: '2.0', id, result });
333
+ return;
307
334
  }
308
335
 
309
- res.json({
336
+ sendResponse({
310
337
  jsonrpc: '2.0',
311
- id: id,
338
+ id,
312
339
  error: { code: -32601, message: 'Method not found' }
313
340
  });
314
341
  } catch (e) {
315
- res.status(500).json({
342
+ log('MCP error: ' + e.message);
343
+ return res.status(500).json({
316
344
  jsonrpc: '2.0',
345
+ id,
317
346
  error: { code: -32603, message: e.message }
318
347
  });
319
348
  }
@@ -321,7 +350,6 @@ if (TRANSPORT === 'stdio') {
321
350
 
322
351
  app.listen(PORT, HOST, async () => {
323
352
  await initCadConnection();
324
- const status = cad.connected ? '已连接 CAD' : '未连接 CAD';
325
- console.error(`@lisp MCP Server 启动 - http://${HOST}:${PORT} - ${status}`);
353
+ console.error(`@lisp MCP Server 启动 - http://${HOST}:${PORT} - Streamable HTTP`);
326
354
  });
327
- }
355
+ }