converse-mcp-server 2.18.0 → 2.19.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "converse-mcp-server",
3
- "version": "2.18.0",
3
+ "version": "2.19.0",
4
4
  "description": "Converse MCP Server - Converse with other LLMs with chat and consensus tools",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/tools/chat.js CHANGED
@@ -13,7 +13,9 @@ import {
13
13
  import {
14
14
  generateContinuationId,
15
15
  addMessageToHistory,
16
+ isValidContinuationId,
16
17
  } from '../continuationStore.js';
18
+ import { isSafeIdSegment } from '../utils/idValidation.js';
17
19
  import { debugLog, debugError } from '../utils/console.js';
18
20
  import { createLogger } from '../utils/logger.js';
19
21
  import { CHAT_PROMPT } from '../systemPrompts.js';
@@ -72,10 +74,28 @@ export async function chatTool(args, dependencies) {
72
74
  );
73
75
  }
74
76
 
77
+ // Validate custom continuation ID for async safety (used as filesystem path segment)
78
+ if (continuation_id && !isSafeIdSegment(continuation_id)) {
79
+ return createToolError(
80
+ `Invalid continuation_id for async mode: "${continuation_id}". Async IDs must contain only letters, numbers, hyphens, and underscores (max 128 chars).`,
81
+ );
82
+ }
83
+
75
84
  // Generate or use existing continuation ID for the conversation
76
85
  const conversationContinuationId =
77
86
  continuation_id || generateContinuationId();
78
87
 
88
+ // Determine if this is a custom ID (non-standard format AND not found in store)
89
+ let isCustomId = false;
90
+ if (continuation_id && !isValidContinuationId(continuation_id)) {
91
+ try {
92
+ const existing = await continuationStore.get(continuation_id);
93
+ isCustomId = !existing;
94
+ } catch {
95
+ isCustomId = true;
96
+ }
97
+ }
98
+
79
99
  // Get provider and model info for the job
80
100
  const providerName = mapModelToProvider(args.model || 'auto', providers);
81
101
  const resolvedModel =
@@ -119,6 +139,7 @@ export async function chatTool(args, dependencies) {
119
139
  {
120
140
  ...dependencies,
121
141
  continuationId: conversationContinuationId,
142
+ isCustomId,
122
143
  title, // Pass title to execution context
123
144
  },
124
145
  context,
@@ -147,6 +168,7 @@ export async function chatTool(args, dependencies) {
147
168
  continuation: {
148
169
  id: conversationContinuationId, // Use continuation_id as the primary ID
149
170
  status: 'processing',
171
+ ...(isCustomId && { custom_id: true }),
150
172
  },
151
173
  async_execution: true,
152
174
  });
@@ -158,6 +180,7 @@ export async function chatTool(args, dependencies) {
158
180
 
159
181
  let conversationHistory = [];
160
182
  let continuationId = continuation_id;
183
+ let isCustomId = false;
161
184
 
162
185
  // Load existing conversation if continuation_id provided
163
186
  if (continuationId) {
@@ -166,13 +189,13 @@ export async function chatTool(args, dependencies) {
166
189
  if (existingState) {
167
190
  conversationHistory = existingState.messages || [];
168
191
  } else {
169
- // Invalid continuation ID - start fresh with new ID
170
- continuationId = generateContinuationId();
192
+ // Preserve user-provided ID and start fresh conversation
193
+ isCustomId = !isValidContinuationId(continuationId);
171
194
  }
172
195
  } catch (error) {
173
196
  logger.error('Error loading conversation', { error });
174
- // Continue with fresh conversation on error
175
- continuationId = generateContinuationId();
197
+ // Preserve user-provided ID on error
198
+ isCustomId = !isValidContinuationId(continuationId);
176
199
  }
177
200
  } else {
178
201
  // Generate new continuation ID for new conversation
@@ -450,6 +473,7 @@ export async function chatTool(args, dependencies) {
450
473
  model,
451
474
  messageCount: updatedMessages.filter((msg) => msg.role !== 'system')
452
475
  .length,
476
+ ...(isCustomId && { custom_id: true }),
453
477
  },
454
478
  };
455
479
 
@@ -700,6 +724,7 @@ async function executeChatWithStreaming(args, dependencies, context) {
700
724
  contextProcessor,
701
725
  providerStreamNormalizer,
702
726
  continuationId,
727
+ isCustomId,
703
728
  title: passedTitle, // Title passed from initial submission
704
729
  } = dependencies;
705
730
 
@@ -1103,6 +1128,7 @@ async function executeChatWithStreaming(args, dependencies, context) {
1103
1128
  model,
1104
1129
  messageCount: updatedMessages.filter((msg) => msg.role !== 'system')
1105
1130
  .length,
1131
+ ...(isCustomId && { custom_id: true }),
1106
1132
  },
1107
1133
  metadata: {
1108
1134
  provider: providerName,
@@ -1140,7 +1166,7 @@ chatTool.inputSchema = {
1140
1166
  continuation_id: {
1141
1167
  type: 'string',
1142
1168
  description:
1143
- 'Continuation ID for persistent conversation. Example: "chat_1703123456789_abc123"',
1169
+ 'Continuation ID for persistent conversation. Example: "chat_1703123456789_abc123". Custom IDs are accepted — an unrecognized ID starts a new conversation under that ID. In async mode, IDs must contain only letters, numbers, hyphens, and underscores (max 128 chars).',
1144
1170
  },
1145
1171
  temperature: {
1146
1172
  type: 'number',
@@ -17,7 +17,9 @@ import {
17
17
  import {
18
18
  generateContinuationId,
19
19
  addMessageToHistory,
20
+ isValidContinuationId,
20
21
  } from '../continuationStore.js';
22
+ import { isSafeIdSegment } from '../utils/idValidation.js';
21
23
  import { debugLog, debugError } from '../utils/console.js';
22
24
  import { createLogger } from '../utils/logger.js';
23
25
  import { CONSENSUS_PROMPT } from '../systemPrompts.js';
@@ -86,9 +88,27 @@ export async function consensusTool(args, dependencies) {
86
88
  );
87
89
  }
88
90
 
91
+ // Validate custom continuation ID for async safety (used as filesystem path segment)
92
+ if (continuation_id && !isSafeIdSegment(continuation_id)) {
93
+ return createToolError(
94
+ `Invalid continuation_id for async mode: "${continuation_id}". Async IDs must contain only letters, numbers, hyphens, and underscores (max 128 chars).`,
95
+ );
96
+ }
97
+
89
98
  // Generate continuation ID for background execution result
90
99
  const bgContinuationId = continuation_id || generateContinuationId();
91
100
 
101
+ // Determine if this is a custom ID (non-standard format AND not found in store)
102
+ let isCustomId = false;
103
+ if (continuation_id && !isValidContinuationId(continuation_id)) {
104
+ try {
105
+ const existing = await continuationStore.get(continuation_id);
106
+ isCustomId = !existing;
107
+ } catch {
108
+ isCustomId = true;
109
+ }
110
+ }
111
+
92
112
  // Create models list for status display
93
113
  const modelsList = args.models.join(', ');
94
114
 
@@ -128,6 +148,7 @@ export async function consensusTool(args, dependencies) {
128
148
  {
129
149
  ...dependencies,
130
150
  continuationId: bgContinuationId,
151
+ isCustomId,
131
152
  title, // Pass title to execution context
132
153
  },
133
154
  context,
@@ -156,6 +177,7 @@ export async function consensusTool(args, dependencies) {
156
177
  continuation: {
157
178
  id: bgContinuationId, // Use continuation_id as the primary ID
158
179
  status: 'processing',
180
+ ...(isCustomId && { custom_id: true }),
159
181
  },
160
182
  async_execution: true,
161
183
  });
@@ -167,6 +189,7 @@ export async function consensusTool(args, dependencies) {
167
189
 
168
190
  let conversationHistory = [];
169
191
  let continuationId = continuation_id;
192
+ let isCustomId = false;
170
193
 
171
194
  // Load existing conversation if continuation_id provided
172
195
  if (continuationId) {
@@ -176,13 +199,13 @@ export async function consensusTool(args, dependencies) {
176
199
  if (existingState) {
177
200
  conversationHistory = existingState.messages || [];
178
201
  } else {
179
- // Invalid continuation ID - start fresh
180
- continuationId = generateContinuationId();
202
+ // Preserve user-provided ID and start fresh conversation
203
+ isCustomId = !isValidContinuationId(continuationId);
181
204
  }
182
205
  } catch (error) {
183
206
  logger.error('Error loading conversation', { error });
184
- // Continue with fresh conversation on error
185
- continuationId = generateContinuationId();
207
+ // Preserve user-provided ID on error
208
+ isCustomId = !isValidContinuationId(continuationId);
186
209
  }
187
210
  } else {
188
211
  // Generate new continuation ID for new conversation
@@ -661,6 +684,7 @@ Please provide your refined response:`;
661
684
  continuation: {
662
685
  id: continuationId,
663
686
  messageCount: messages.length + 1,
687
+ ...(isCustomId && { custom_id: true }),
664
688
  },
665
689
  settings: {
666
690
  enable_cross_feedback,
@@ -690,6 +714,7 @@ Please provide your refined response:`;
690
714
  continuation: {
691
715
  id: continuationId,
692
716
  messageCount: messages.length + 1,
717
+ ...(isCustomId && { custom_id: true }),
693
718
  },
694
719
  });
695
720
  } catch (error) {
@@ -903,6 +928,7 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
903
928
  contextProcessor,
904
929
  providerStreamNormalizer,
905
930
  continuationId,
931
+ isCustomId,
906
932
  title: passedTitle, // Title passed from initial submission
907
933
  } = dependencies;
908
934
 
@@ -1420,6 +1446,7 @@ Please provide your refined response:`;
1420
1446
  continuation: {
1421
1447
  id: continuationId,
1422
1448
  messageCount: messages.length + 1,
1449
+ ...(isCustomId && { custom_id: true }),
1423
1450
  },
1424
1451
  settings: {
1425
1452
  enable_cross_feedback,
@@ -1695,7 +1722,7 @@ consensusTool.inputSchema = {
1695
1722
  continuation_id: {
1696
1723
  type: 'string',
1697
1724
  description:
1698
- 'Thread continuation ID for multi-turn conversations. Example: "consensus_1703123456789_xyz789"',
1725
+ 'Thread continuation ID for multi-turn conversations. Example: "consensus_1703123456789_xyz789". Custom IDs are accepted — an unrecognized ID starts a new conversation under that ID. In async mode, IDs must contain only letters, numbers, hyphens, and underscores (max 128 chars).',
1699
1726
  },
1700
1727
  enable_cross_feedback: {
1701
1728
  type: 'boolean',