iwgt 2.4.3 → 2.4.5

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "2.0",
3
- "generatedAt": "2025-10-07T12:42:07.444Z",
3
+ "generatedAt": "2025-10-07T13:06:51.090Z",
4
4
  "description": "Справочник по библиотеке common.v2.js для InSales - набор готовых скриптов для разработки шаблонов",
5
5
  "installation": {
6
6
  "method": "liquid_tag",
@@ -4,7 +4,7 @@
4
4
  "description": "Liquid фильтры InSales",
5
5
  "totalCategories": 7,
6
6
  "totalFilters": 53,
7
- "generatedAt": "2025-10-07T12:42:07.430Z"
7
+ "generatedAt": "2025-10-07T13:06:51.074Z"
8
8
  },
9
9
  "categories": [
10
10
  {
@@ -4,7 +4,7 @@
4
4
  "description": "Liquid переменные InSales",
5
5
  "totalCategories": 19,
6
6
  "totalVariables": 436,
7
- "generatedAt": "2025-10-07T12:42:07.176Z"
7
+ "generatedAt": "2025-10-07T13:06:50.724Z"
8
8
  },
9
9
  "categories": [
10
10
  {
@@ -7,6 +7,7 @@ import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
7
7
  import { createServer } from 'http';
8
8
  import { fileURLToPath } from 'url';
9
9
  import { dirname } from 'path';
10
+ import crypto from 'crypto';
10
11
  const __filename = fileURLToPath(import.meta.url);
11
12
  const __dirname = dirname(__filename);
12
13
  // Импортируем класс WidgetServer
@@ -16,6 +17,8 @@ const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3000;
16
17
  const HOST = process.env.HOST || '0.0.0.0';
17
18
  // API ключ для аутентификации (опционально)
18
19
  const API_KEY = process.env.MCP_API_KEY;
20
+ // Хранилище активных SSE сессий и их транспортов
21
+ const activeSessions = new Map();
19
22
  /**
20
23
  * Проверка API ключа
21
24
  */
@@ -55,7 +58,7 @@ const httpServer = createServer(async (req, res) => {
55
58
  res.end(JSON.stringify({
56
59
  status: 'ok',
57
60
  service: 'InSales Widgets MCP Server',
58
- version: '2.3.0',
61
+ version: '2.4.3',
59
62
  transport: 'SSE',
60
63
  endpoints: {
61
64
  sse: '/sse',
@@ -69,18 +72,23 @@ const httpServer = createServer(async (req, res) => {
69
72
  if (req.url === '/sse' && req.method === 'GET') {
70
73
  console.log('📡 New SSE connection established');
71
74
  try {
75
+ // Генерируем уникальный sessionId
76
+ const sessionId = crypto.randomUUID();
72
77
  // Создаем новый MCP сервер для этого соединения
73
78
  const widgetServer = new WidgetServer();
74
- const transport = new SSEServerTransport('/message', res);
75
- // Инициализируем сервер (без stdio транспорта)
76
- // await widgetServer.run(); // Не вызываем run(), так как он создает stdio транспорт
77
- // Подключаем транспорт
78
- await widgetServer['server'].connect(transport);
79
+ const transport = new SSEServerTransport(`/message?sessionId=${sessionId}`, res);
80
+ // Сохраняем сессию
81
+ activeSessions.set(sessionId, { server: widgetServer, transport });
82
+ console.log(`📝 Session created: ${sessionId} (active: ${activeSessions.size})`);
83
+ // Подключаем транспорт через публичный метод
84
+ await widgetServer.connect(transport);
79
85
  console.log('✅ MCP server connected via SSE');
80
86
  // Обработка закрытия соединения
81
87
  req.on('close', () => {
82
- console.log('📡 SSE connection closed');
88
+ console.log(`📡 SSE connection closed for session ${sessionId}`);
89
+ activeSessions.delete(sessionId);
83
90
  transport.close();
91
+ console.log(`📝 Session deleted: ${sessionId} (active: ${activeSessions.size})`);
84
92
  });
85
93
  }
86
94
  catch (error) {
@@ -91,23 +99,54 @@ const httpServer = createServer(async (req, res) => {
91
99
  return;
92
100
  }
93
101
  // Message endpoint для отправки сообщений
94
- if (req.url === '/message' && req.method === 'POST') {
95
- let body = '';
96
- req.on('data', (chunk) => {
97
- body += chunk.toString();
98
- });
99
- req.on('end', () => {
100
- try {
101
- const message = JSON.parse(body);
102
- // SSE транспорт обработает это сообщение
103
- res.writeHead(200, { 'Content-Type': 'application/json' });
104
- res.end(JSON.stringify({ status: 'ok' }));
102
+ // Проверяем, что URL начинается с /message (может быть /message?sessionId=xxx)
103
+ if (req.url?.startsWith('/message') && req.method === 'POST') {
104
+ // Извлекаем sessionId из URL
105
+ const urlObj = new URL(req.url, `http://${req.headers.host}`);
106
+ const sessionId = urlObj.searchParams.get('sessionId');
107
+ if (!sessionId) {
108
+ res.writeHead(400, { 'Content-Type': 'application/json' });
109
+ res.end(JSON.stringify({ error: 'Missing sessionId' }));
110
+ return;
111
+ }
112
+ const session = activeSessions.get(sessionId);
113
+ if (!session) {
114
+ res.writeHead(404, { 'Content-Type': 'application/json' });
115
+ res.end(JSON.stringify({ error: 'Session not found' }));
116
+ return;
117
+ }
118
+ try {
119
+ // Передаём запрос в SSE транспорт для обработки
120
+ // @ts-ignore - метод может существовать в runtime, но не в типах
121
+ if (typeof session.transport.handlePostMessage === 'function') {
122
+ await session.transport.handlePostMessage(req, res);
105
123
  }
106
- catch (error) {
107
- res.writeHead(400, { 'Content-Type': 'application/json' });
108
- res.end(JSON.stringify({ error: 'Invalid JSON' }));
124
+ else {
125
+ // Fallback: читаем тело и отправляем ответ вручную
126
+ let body = '';
127
+ req.on('data', (chunk) => {
128
+ body += chunk.toString();
129
+ });
130
+ req.on('end', async () => {
131
+ try {
132
+ const message = JSON.parse(body);
133
+ console.log(`📥 Received POST message:`, message.method || 'unknown');
134
+ // Просто подтверждаем получение
135
+ res.writeHead(202, { 'Content-Type': 'application/json' });
136
+ res.end(JSON.stringify({ status: 'accepted' }));
137
+ }
138
+ catch (error) {
139
+ res.writeHead(400, { 'Content-Type': 'application/json' });
140
+ res.end(JSON.stringify({ error: 'Invalid JSON' }));
141
+ }
142
+ });
109
143
  }
110
- });
144
+ }
145
+ catch (error) {
146
+ console.error('❌ Error handling POST:', error);
147
+ res.writeHead(500, { 'Content-Type': 'application/json' });
148
+ res.end(JSON.stringify({ error: 'Internal server error' }));
149
+ }
111
150
  return;
112
151
  }
113
152
  // 404 для неизвестных путей
package/dist/server.d.ts CHANGED
@@ -3,6 +3,13 @@ export declare class WidgetServer {
3
3
  constructor();
4
4
  private setupHandlers;
5
5
  private createWidget;
6
+ /**
7
+ * Подключить внешний транспорт (например, SSE)
8
+ */
9
+ connect(transport: any): Promise<void>;
10
+ /**
11
+ * Запустить сервер с stdio транспортом
12
+ */
6
13
  run(): Promise<void>;
7
14
  }
8
15
  //# sourceMappingURL=server.d.ts.map
package/dist/server.js CHANGED
@@ -25,7 +25,7 @@ export class WidgetServer {
25
25
  constructor() {
26
26
  this.server = new Server({
27
27
  name: 'insales-widgets',
28
- version: '2.0.0',
28
+ version: '2.4.3',
29
29
  }, {
30
30
  capabilities: {
31
31
  tools: {},
@@ -570,6 +570,15 @@ export class WidgetServer {
570
570
  ],
571
571
  };
572
572
  }
573
+ /**
574
+ * Подключить внешний транспорт (например, SSE)
575
+ */
576
+ async connect(transport) {
577
+ await this.server.connect(transport);
578
+ }
579
+ /**
580
+ * Запустить сервер с stdio транспортом
581
+ */
573
582
  async run() {
574
583
  const transport = new StdioServerTransport();
575
584
  await this.server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iwgt",
3
- "version": "2.4.3",
3
+ "version": "2.4.5",
4
4
  "description": "MCP server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",