converse-mcp-server 2.3.1 → 2.4.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 (42) hide show
  1. package/README.md +771 -738
  2. package/docs/API.md +10 -1
  3. package/docs/PROVIDERS.md +8 -4
  4. package/package.json +12 -12
  5. package/src/async/asyncJobStore.js +82 -52
  6. package/src/async/eventBus.js +25 -20
  7. package/src/async/fileCache.js +121 -40
  8. package/src/async/jobRunner.js +65 -39
  9. package/src/async/providerStreamNormalizer.js +203 -117
  10. package/src/config.js +374 -102
  11. package/src/continuationStore.js +32 -24
  12. package/src/index.js +45 -25
  13. package/src/prompts/helpPrompt.js +328 -305
  14. package/src/providers/anthropic.js +303 -119
  15. package/src/providers/codex.js +103 -45
  16. package/src/providers/deepseek.js +24 -8
  17. package/src/providers/google.js +337 -93
  18. package/src/providers/index.js +1 -1
  19. package/src/providers/interface.js +16 -11
  20. package/src/providers/mistral.js +179 -69
  21. package/src/providers/openai-compatible.js +231 -94
  22. package/src/providers/openai.js +1094 -914
  23. package/src/providers/openrouter-endpoints-client.js +220 -216
  24. package/src/providers/openrouter.js +426 -381
  25. package/src/providers/xai.js +153 -56
  26. package/src/resources/helpResource.js +70 -67
  27. package/src/router.js +95 -67
  28. package/src/services/summarizationService.js +51 -24
  29. package/src/systemPrompts.js +89 -89
  30. package/src/tools/cancelJob.js +31 -19
  31. package/src/tools/chat.js +997 -883
  32. package/src/tools/checkStatus.js +86 -65
  33. package/src/tools/consensus.js +400 -234
  34. package/src/tools/index.js +39 -16
  35. package/src/transport/httpTransport.js +82 -55
  36. package/src/utils/contextProcessor.js +54 -37
  37. package/src/utils/errorHandler.js +95 -45
  38. package/src/utils/fileValidator.js +107 -98
  39. package/src/utils/formatStatus.js +122 -64
  40. package/src/utils/logger.js +459 -449
  41. package/src/utils/pathUtils.js +2 -2
  42. package/src/utils/tokenLimiter.js +216 -216
@@ -106,7 +106,7 @@ class MemoryContinuationStore extends ContinuationStoreInterface {
106
106
  if (!continuationId || typeof continuationId !== 'string') {
107
107
  throw new ContinuationStoreError(
108
108
  'Invalid continuation ID: must be a non-empty string',
109
- 'INVALID_CONTINUATION_ID'
109
+ 'INVALID_CONTINUATION_ID',
110
110
  );
111
111
  }
112
112
 
@@ -114,7 +114,7 @@ class MemoryContinuationStore extends ContinuationStoreInterface {
114
114
  if (!state || typeof state !== 'object') {
115
115
  throw new ContinuationStoreError(
116
116
  'Invalid state: must be an object',
117
- 'INVALID_STATE'
117
+ 'INVALID_STATE',
118
118
  );
119
119
  }
120
120
  // Cleanup old conversations if we hit the limit
@@ -125,8 +125,13 @@ class MemoryContinuationStore extends ContinuationStoreInterface {
125
125
 
126
126
  // Limit messages per conversation to prevent memory issues
127
127
  const sanitizedState = { ...state };
128
- if (sanitizedState.messages && sanitizedState.messages.length > this.maxMessagesPerConversation) {
129
- sanitizedState.messages = sanitizedState.messages.slice(-this.maxMessagesPerConversation);
128
+ if (
129
+ sanitizedState.messages &&
130
+ sanitizedState.messages.length > this.maxMessagesPerConversation
131
+ ) {
132
+ sanitizedState.messages = sanitizedState.messages.slice(
133
+ -this.maxMessagesPerConversation,
134
+ );
130
135
  }
131
136
 
132
137
  // Store with metadata
@@ -137,14 +142,13 @@ class MemoryContinuationStore extends ContinuationStoreInterface {
137
142
  ? this.conversations.get(continuationId).createdAt
138
143
  : Date.now(),
139
144
  });
140
-
141
145
  } catch (error) {
142
146
  if (error instanceof ContinuationStoreError) {
143
147
  throw error;
144
148
  }
145
149
  throw new ContinuationStoreError(
146
150
  `Failed to store continuation: ${error.message}`,
147
- 'STORAGE_ERROR'
151
+ 'STORAGE_ERROR',
148
152
  );
149
153
  }
150
154
  }
@@ -161,7 +165,7 @@ class MemoryContinuationStore extends ContinuationStoreInterface {
161
165
  if (!continuationId || typeof continuationId !== 'string') {
162
166
  throw new ContinuationStoreError(
163
167
  'Invalid continuation ID: must be a non-empty string',
164
- 'INVALID_CONTINUATION_ID'
168
+ 'INVALID_CONTINUATION_ID',
165
169
  );
166
170
  }
167
171
 
@@ -173,18 +177,17 @@ class MemoryContinuationStore extends ContinuationStoreInterface {
173
177
  const { createdAt, lastAccessed, ...cleanState } = state;
174
178
  return {
175
179
  ...cleanState,
176
- _metadata: { createdAt, lastAccessed }
180
+ _metadata: { createdAt, lastAccessed },
177
181
  };
178
182
  }
179
183
  return null;
180
-
181
184
  } catch (error) {
182
185
  if (error instanceof ContinuationStoreError) {
183
186
  throw error;
184
187
  }
185
188
  throw new ContinuationStoreError(
186
189
  `Failed to retrieve continuation: ${error.message}`,
187
- 'RETRIEVAL_ERROR'
190
+ 'RETRIEVAL_ERROR',
188
191
  );
189
192
  }
190
193
  }
@@ -201,21 +204,20 @@ class MemoryContinuationStore extends ContinuationStoreInterface {
201
204
  if (!continuationId || typeof continuationId !== 'string') {
202
205
  throw new ContinuationStoreError(
203
206
  'Invalid continuation ID: must be a non-empty string',
204
- 'INVALID_CONTINUATION_ID'
207
+ 'INVALID_CONTINUATION_ID',
205
208
  );
206
209
  }
207
210
 
208
211
  const existed = this.conversations.has(continuationId);
209
212
  this.conversations.delete(continuationId);
210
213
  return existed;
211
-
212
214
  } catch (error) {
213
215
  if (error instanceof ContinuationStoreError) {
214
216
  throw error;
215
217
  }
216
218
  throw new ContinuationStoreError(
217
219
  `Failed to delete continuation: ${error.message}`,
218
- 'DELETION_ERROR'
220
+ 'DELETION_ERROR',
219
221
  );
220
222
  }
221
223
  }
@@ -274,16 +276,21 @@ export function getContinuationStore() {
274
276
  continuationStore = new MemoryContinuationStore();
275
277
 
276
278
  // Set up periodic cleanup (runs every hour)
277
- cleanupIntervalId = setInterval(async () => {
278
- try {
279
- const cleaned = await continuationStore.cleanup();
280
- if (cleaned > 0) {
281
- debugLog(`ContinuationStore: Cleaned up ${cleaned} old conversations`);
279
+ cleanupIntervalId = setInterval(
280
+ async () => {
281
+ try {
282
+ const cleaned = await continuationStore.cleanup();
283
+ if (cleaned > 0) {
284
+ debugLog(
285
+ `ContinuationStore: Cleaned up ${cleaned} old conversations`,
286
+ );
287
+ }
288
+ } catch (error) {
289
+ debugError('ContinuationStore cleanup failed:', error);
282
290
  }
283
- } catch (error) {
284
- debugError('ContinuationStore cleanup failed:', error);
285
- }
286
- }, 60 * 60 * 1000);
291
+ },
292
+ 60 * 60 * 1000,
293
+ );
287
294
 
288
295
  // Unref the interval so it doesn't keep the process alive
289
296
  if (cleanupIntervalId && typeof cleanupIntervalId.unref === 'function') {
@@ -301,7 +308,7 @@ export function setContinuationStore(store) {
301
308
  if (!(store instanceof ContinuationStoreInterface)) {
302
309
  throw new ContinuationStoreError(
303
310
  'Store must extend ContinuationStoreInterface',
304
- 'INVALID_STORE'
311
+ 'INVALID_STORE',
305
312
  );
306
313
  }
307
314
  continuationStore = store;
@@ -341,7 +348,8 @@ export function isValidContinuationId(continuationId) {
341
348
  const nanoidPattern = /^conv_[A-Za-z0-9_-]{10}$/;
342
349
 
343
350
  // Also accept legacy UUID format for backward compatibility
344
- const uuidPattern = /^conv_[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
351
+ const uuidPattern =
352
+ /^conv_[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
345
353
 
346
354
  return nanoidPattern.test(continuationId) || uuidPattern.test(continuationId);
347
355
  }
package/src/index.js CHANGED
@@ -10,7 +10,12 @@
10
10
  import { fileURLToPath, pathToFileURL } from 'url';
11
11
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
12
12
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
13
- import { loadConfig, validateRuntimeConfig, getMcpClientConfig, getHttpTransportConfig } from './config.js';
13
+ import {
14
+ loadConfig,
15
+ validateRuntimeConfig,
16
+ getMcpClientConfig,
17
+ getHttpTransportConfig,
18
+ } from './config.js';
14
19
  import { createRouter } from './router.js';
15
20
  import { createHTTPTransport } from './transport/httpTransport.js';
16
21
  import { createLogger, startTimer } from './utils/logger.js';
@@ -55,7 +60,7 @@ function getTransportType() {
55
60
  const args = process.argv.slice(2);
56
61
 
57
62
  // Support --transport=value format
58
- const transportEqualArg = args.find(arg => arg.startsWith('--transport='));
63
+ const transportEqualArg = args.find((arg) => arg.startsWith('--transport='));
59
64
  if (transportEqualArg) {
60
65
  const transport = transportEqualArg.split('=')[1];
61
66
  if (transport && ['http', 'stdio'].includes(transport)) {
@@ -64,7 +69,7 @@ function getTransportType() {
64
69
  }
65
70
 
66
71
  // Support --transport value format
67
- const transportIndex = args.findIndex(arg => arg === '--transport');
72
+ const transportIndex = args.findIndex((arg) => arg === '--transport');
68
73
  if (transportIndex >= 0 && transportIndex + 1 < args.length) {
69
74
  const transport = args[transportIndex + 1];
70
75
  if (transport && ['http', 'stdio'].includes(transport)) {
@@ -102,7 +107,7 @@ async function main() {
102
107
  const { configureLogger } = await import('./utils/logger.js');
103
108
  configureLogger({
104
109
  level: process.env.LOG_LEVEL || 'info',
105
- isDevelopment: process.env.NODE_ENV === 'development'
110
+ isDevelopment: process.env.NODE_ENV === 'development',
106
111
  });
107
112
  }
108
113
 
@@ -121,7 +126,7 @@ async function main() {
121
126
  logger.info('Using transport type', { data: { transport: transportType } });
122
127
 
123
128
  logger.debug('Creating MCP server instance', {
124
- data: { name: mcpConfig.name, version: mcpConfig.version }
129
+ data: { name: mcpConfig.name, version: mcpConfig.version },
125
130
  });
126
131
 
127
132
  // Create MCP server with configuration
@@ -130,7 +135,7 @@ async function main() {
130
135
  name: mcpConfig.name,
131
136
  version: mcpConfig.version,
132
137
  },
133
- mcpConfig
138
+ mcpConfig,
134
139
  );
135
140
 
136
141
  // Set up router with server and config
@@ -146,14 +151,17 @@ async function main() {
146
151
  const status = httpTransport.getStatus();
147
152
 
148
153
  const startupTime = serverTimer('completed');
149
- logger.info('Converse MCP Server started successfully with HTTP transport', {
150
- data: {
151
- startupTime: `${startupTime}ms`,
152
- endpoint: `http://${status.host}:${status.port}/mcp`,
153
- host: status.host,
154
- port: status.port
155
- }
156
- });
154
+ logger.info(
155
+ 'Converse MCP Server started successfully with HTTP transport',
156
+ {
157
+ data: {
158
+ startupTime: `${startupTime}ms`,
159
+ endpoint: `http://${status.host}:${status.port}/mcp`,
160
+ host: status.host,
161
+ port: status.port,
162
+ },
163
+ },
164
+ );
157
165
 
158
166
  // Store reference for shutdown
159
167
  process.httpTransport = httpTransport;
@@ -163,9 +171,12 @@ async function main() {
163
171
  await server.connect(transport);
164
172
 
165
173
  const startupTime = serverTimer('completed');
166
- logger.info('Converse MCP Server started successfully with stdio transport', {
167
- data: { startupTime: `${startupTime}ms` }
168
- });
174
+ logger.info(
175
+ 'Converse MCP Server started successfully with stdio transport',
176
+ {
177
+ data: { startupTime: `${startupTime}ms` },
178
+ },
179
+ );
169
180
  }
170
181
  } catch (error) {
171
182
  serverTimer('failed');
@@ -176,7 +187,7 @@ async function main() {
176
187
  debugError(error.message);
177
188
  if (error.details?.errors) {
178
189
  debugError('\nDetailed errors:');
179
- error.details.errors.forEach(err => debugError(` - ${err}`));
190
+ error.details.errors.forEach((err) => debugError(` - ${err}`));
180
191
  }
181
192
  process.exit(1);
182
193
  } else {
@@ -194,8 +205,12 @@ async function gracefulShutdown(signal) {
194
205
 
195
206
  // Stop all cleanup intervals
196
207
  try {
197
- const { stopContinuationStoreCleanup } = await import('./continuationStore.js');
198
- const { stopAsyncJobStoreCleanup } = await import('./async/asyncJobStore.js');
208
+ const { stopContinuationStoreCleanup } = await import(
209
+ './continuationStore.js'
210
+ );
211
+ const { stopAsyncJobStoreCleanup } = await import(
212
+ './async/asyncJobStore.js'
213
+ );
199
214
  const { stopFileCacheCleanup } = await import('./async/fileCache.js');
200
215
 
201
216
  stopContinuationStoreCleanup();
@@ -226,8 +241,12 @@ process.on('beforeExit', async (code) => {
226
241
  logger.info('Process beforeExit event', { data: { code } });
227
242
  // Cleanup intervals if not already done
228
243
  try {
229
- const { stopContinuationStoreCleanup } = await import('./continuationStore.js');
230
- const { stopAsyncJobStoreCleanup } = await import('./async/asyncJobStore.js');
244
+ const { stopContinuationStoreCleanup } = await import(
245
+ './continuationStore.js'
246
+ );
247
+ const { stopAsyncJobStoreCleanup } = await import(
248
+ './async/asyncJobStore.js'
249
+ );
231
250
  const { stopFileCacheCleanup } = await import('./async/fileCache.js');
232
251
 
233
252
  stopContinuationStoreCleanup();
@@ -251,7 +270,7 @@ process.on('uncaughtException', (error) => {
251
270
  process.on('unhandledRejection', (reason, promise) => {
252
271
  logger.error('Unhandled promise rejection', {
253
272
  error: reason,
254
- data: { promise: promise.toString() }
273
+ data: { promise: promise.toString() },
255
274
  });
256
275
  debugError('Unhandled promise rejection:', reason);
257
276
  process.exit(1);
@@ -262,8 +281,9 @@ export { main };
262
281
 
263
282
  // Check if this module is the main entry point
264
283
  // This works better across platforms and Node.js versions
265
- const isMainModule = import.meta.url === pathToFileURL(process.argv[1]).href ||
266
- process.argv[1] === fileURLToPath(import.meta.url);
284
+ const isMainModule =
285
+ import.meta.url === pathToFileURL(process.argv[1]).href ||
286
+ process.argv[1] === fileURLToPath(import.meta.url);
267
287
 
268
288
  if (isMainModule) {
269
289
  main().catch((error) => {