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.
- package/README.md +771 -738
- package/docs/API.md +10 -1
- package/docs/PROVIDERS.md +8 -4
- package/package.json +12 -12
- package/src/async/asyncJobStore.js +82 -52
- package/src/async/eventBus.js +25 -20
- package/src/async/fileCache.js +121 -40
- package/src/async/jobRunner.js +65 -39
- package/src/async/providerStreamNormalizer.js +203 -117
- package/src/config.js +374 -102
- package/src/continuationStore.js +32 -24
- package/src/index.js +45 -25
- package/src/prompts/helpPrompt.js +328 -305
- package/src/providers/anthropic.js +303 -119
- package/src/providers/codex.js +103 -45
- package/src/providers/deepseek.js +24 -8
- package/src/providers/google.js +337 -93
- package/src/providers/index.js +1 -1
- package/src/providers/interface.js +16 -11
- package/src/providers/mistral.js +179 -69
- package/src/providers/openai-compatible.js +231 -94
- package/src/providers/openai.js +1094 -914
- package/src/providers/openrouter-endpoints-client.js +220 -216
- package/src/providers/openrouter.js +426 -381
- package/src/providers/xai.js +153 -56
- package/src/resources/helpResource.js +70 -67
- package/src/router.js +95 -67
- package/src/services/summarizationService.js +51 -24
- package/src/systemPrompts.js +89 -89
- package/src/tools/cancelJob.js +31 -19
- package/src/tools/chat.js +997 -883
- package/src/tools/checkStatus.js +86 -65
- package/src/tools/consensus.js +400 -234
- package/src/tools/index.js +39 -16
- package/src/transport/httpTransport.js +82 -55
- package/src/utils/contextProcessor.js +54 -37
- package/src/utils/errorHandler.js +95 -45
- package/src/utils/fileValidator.js +107 -98
- package/src/utils/formatStatus.js +122 -64
- package/src/utils/logger.js +459 -449
- package/src/utils/pathUtils.js +2 -2
- package/src/utils/tokenLimiter.js +216 -216
package/src/continuationStore.js
CHANGED
|
@@ -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 (
|
|
129
|
-
sanitizedState.messages
|
|
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(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
}
|
|
284
|
-
|
|
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 =
|
|
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 {
|
|
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(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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(
|
|
167
|
-
|
|
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(
|
|
198
|
-
|
|
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(
|
|
230
|
-
|
|
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 =
|
|
266
|
-
|
|
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) => {
|