converse-mcp-server 2.8.0 → 2.8.2
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 +3 -2
- package/src/prompts/helpPrompt.js +1 -1
- package/src/providers/claude.js +107 -20
- package/src/tools/chat.js +24 -9
- package/src/tools/consensus.js +9 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "converse-mcp-server",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.2",
|
|
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",
|
|
@@ -94,11 +94,12 @@
|
|
|
94
94
|
".env.example"
|
|
95
95
|
],
|
|
96
96
|
"dependencies": {
|
|
97
|
+
"@anthropic-ai/claude-agent-sdk": "^0.1.51",
|
|
97
98
|
"@anthropic-ai/sdk": "^0.70.0",
|
|
98
99
|
"@google/genai": "^1.30.0",
|
|
99
100
|
"@mistralai/mistralai": "^1.10.0",
|
|
100
101
|
"@modelcontextprotocol/sdk": "^1.22.0",
|
|
101
|
-
"@openai/codex-sdk": "^0.
|
|
102
|
+
"@openai/codex-sdk": "^0.63.0",
|
|
102
103
|
"ai": "^5.0.101",
|
|
103
104
|
"ai-sdk-provider-gemini-cli": "^1.4.0",
|
|
104
105
|
"cors": "^2.8.5",
|
|
@@ -95,7 +95,7 @@ export function generateHelpContent(config = null) {
|
|
|
95
95
|
return `\`\`\`json
|
|
96
96
|
{
|
|
97
97
|
"prompt": "Should we use microservices architecture for our new project?",
|
|
98
|
-
"models": ["
|
|
98
|
+
"models": ["codex", "gemini", "claude"],
|
|
99
99
|
"files": ["./requirements.md", "C:\\\\Users\\\\username\\\\architecture.md"],
|
|
100
100
|
"enable_cross_feedback": true,
|
|
101
101
|
"temperature": 0.3
|
package/src/providers/claude.js
CHANGED
|
@@ -24,7 +24,7 @@ const SUPPORTED_MODELS = {
|
|
|
24
24
|
contextWindow: 200000,
|
|
25
25
|
maxOutputTokens: 8192,
|
|
26
26
|
supportsStreaming: true,
|
|
27
|
-
supportsImages:
|
|
27
|
+
supportsImages: true, // Supported via streaming input mode
|
|
28
28
|
supportsTemperature: false, // SDK manages temperature internally
|
|
29
29
|
supportsWebSearch: false, // SDK accesses files directly, not web
|
|
30
30
|
timeout: 120000, // 2 minutes
|
|
@@ -83,14 +83,19 @@ async function getClaudeSDK() {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
|
-
* Convert message array to
|
|
87
|
-
* Claude SDK
|
|
86
|
+
* Convert message array to SDK input format
|
|
87
|
+
* Claude SDK supports two modes:
|
|
88
|
+
* 1. Single message mode (string) - simpler, but no image support
|
|
89
|
+
* 2. Streaming input mode (AsyncGenerator) - supports images
|
|
88
90
|
*
|
|
89
91
|
* Strategy:
|
|
90
|
-
* - Extract last user message
|
|
91
|
-
* -
|
|
92
|
+
* - Extract last user message
|
|
93
|
+
* - If message contains images, use streaming input mode
|
|
94
|
+
* - Otherwise, return string prompt for single message mode
|
|
95
|
+
*
|
|
96
|
+
* @returns {Object} { prompt: string | null, sdkMessage: Object | null, hasImages: boolean }
|
|
92
97
|
*/
|
|
93
|
-
function
|
|
98
|
+
function convertMessagesToSdkInput(messages) {
|
|
94
99
|
if (!Array.isArray(messages)) {
|
|
95
100
|
throw new ClaudeProviderError(
|
|
96
101
|
'Messages must be an array',
|
|
@@ -117,26 +122,66 @@ function convertMessagesToPrompt(messages) {
|
|
|
117
122
|
|
|
118
123
|
// Extract text content from message
|
|
119
124
|
if (typeof lastUserMessage.content === 'string') {
|
|
120
|
-
return
|
|
125
|
+
return {
|
|
126
|
+
prompt: lastUserMessage.content,
|
|
127
|
+
sdkMessage: null,
|
|
128
|
+
hasImages: false,
|
|
129
|
+
};
|
|
121
130
|
}
|
|
122
131
|
|
|
123
132
|
// Handle array content (multimodal format)
|
|
124
133
|
if (Array.isArray(lastUserMessage.content)) {
|
|
125
|
-
|
|
126
|
-
.filter((item) => item.type === 'text')
|
|
127
|
-
.map((item) => item.text);
|
|
128
|
-
|
|
129
|
-
// Log warning if images present (Claude SDK has limited image support)
|
|
134
|
+
// Check if message contains images
|
|
130
135
|
const hasImages = lastUserMessage.content.some(
|
|
131
136
|
(item) => item.type === 'image',
|
|
132
137
|
);
|
|
138
|
+
|
|
133
139
|
if (hasImages) {
|
|
140
|
+
// Use streaming input mode for images
|
|
141
|
+
// Convert to SDK message format
|
|
142
|
+
const sdkContent = lastUserMessage.content.map((item) => {
|
|
143
|
+
if (item.type === 'text') {
|
|
144
|
+
return {
|
|
145
|
+
type: 'text',
|
|
146
|
+
text: item.text,
|
|
147
|
+
};
|
|
148
|
+
} else if (item.type === 'image') {
|
|
149
|
+
// SDK expects Anthropic image format
|
|
150
|
+
return {
|
|
151
|
+
type: 'image',
|
|
152
|
+
source: item.source,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return item;
|
|
156
|
+
});
|
|
157
|
+
|
|
134
158
|
debugLog(
|
|
135
|
-
|
|
159
|
+
`[Claude SDK] Using streaming input mode for multimodal content (${lastUserMessage.content.filter((i) => i.type === 'image').length} images)`,
|
|
136
160
|
);
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
prompt: null,
|
|
164
|
+
sdkMessage: {
|
|
165
|
+
type: 'user',
|
|
166
|
+
message: {
|
|
167
|
+
role: 'user',
|
|
168
|
+
content: sdkContent,
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
hasImages: true,
|
|
172
|
+
};
|
|
137
173
|
}
|
|
138
174
|
|
|
139
|
-
|
|
175
|
+
// No images - extract text only
|
|
176
|
+
const textParts = lastUserMessage.content
|
|
177
|
+
.filter((item) => item.type === 'text')
|
|
178
|
+
.map((item) => item.text);
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
prompt: textParts.join('\n'),
|
|
182
|
+
sdkMessage: null,
|
|
183
|
+
hasImages: false,
|
|
184
|
+
};
|
|
140
185
|
}
|
|
141
186
|
|
|
142
187
|
throw new ClaudeProviderError(
|
|
@@ -145,6 +190,14 @@ function convertMessagesToPrompt(messages) {
|
|
|
145
190
|
);
|
|
146
191
|
}
|
|
147
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Create an async generator that yields a single SDK user message
|
|
195
|
+
* This is required for streaming input mode (image support)
|
|
196
|
+
*/
|
|
197
|
+
async function* createSdkMessageGenerator(sdkMessage) {
|
|
198
|
+
yield sdkMessage;
|
|
199
|
+
}
|
|
200
|
+
|
|
148
201
|
/**
|
|
149
202
|
* Create stream generator for Claude SDK streaming responses
|
|
150
203
|
* Yields normalized events compatible with ProviderStreamNormalizer
|
|
@@ -153,12 +206,25 @@ function convertMessagesToPrompt(messages) {
|
|
|
153
206
|
* - system (subtype: init): Session initialization
|
|
154
207
|
* - assistant: Model responses with message.content
|
|
155
208
|
* - result (subtype: success/error_*): Final results with usage
|
|
209
|
+
*
|
|
210
|
+
* @param {Function} queryFn - The SDK query function
|
|
211
|
+
* @param {string|null} prompt - String prompt for single message mode, or null for streaming input mode
|
|
212
|
+
* @param {Object|null} sdkMessage - SDK user message for streaming input mode (with images)
|
|
213
|
+
* @param {Object} options - SDK options (cwd, etc.)
|
|
214
|
+
* @param {AbortSignal} signal - Abort signal for cancellation
|
|
156
215
|
*/
|
|
157
|
-
async function* createStreamingGenerator(
|
|
216
|
+
async function* createStreamingGenerator(
|
|
217
|
+
queryFn,
|
|
218
|
+
prompt,
|
|
219
|
+
sdkMessage,
|
|
220
|
+
options,
|
|
221
|
+
signal,
|
|
222
|
+
) {
|
|
158
223
|
try {
|
|
159
224
|
// Build query options
|
|
225
|
+
// Use higher maxTurns to allow for file reading operations
|
|
160
226
|
const queryOptions = {
|
|
161
|
-
maxTurns:
|
|
227
|
+
maxTurns: 10, // Allow multiple turns for file operations
|
|
162
228
|
permissionMode: 'bypassPermissions', // Don't prompt for permissions
|
|
163
229
|
};
|
|
164
230
|
|
|
@@ -179,9 +245,16 @@ async function* createStreamingGenerator(queryFn, prompt, options, signal) {
|
|
|
179
245
|
});
|
|
180
246
|
}
|
|
181
247
|
|
|
248
|
+
// Determine input mode based on whether we have an SDK message (with images) or plain prompt
|
|
249
|
+
// - Streaming input mode: prompt is AsyncGenerator<SDKUserMessage> - required for images
|
|
250
|
+
// - Single message mode: prompt is string - simpler but no image support
|
|
251
|
+
const queryInput = sdkMessage
|
|
252
|
+
? createSdkMessageGenerator(sdkMessage) // Streaming input mode for images
|
|
253
|
+
: prompt; // Single message mode for text-only
|
|
254
|
+
|
|
182
255
|
// Create query generator
|
|
183
256
|
const response = queryFn({
|
|
184
|
-
prompt,
|
|
257
|
+
prompt: queryInput,
|
|
185
258
|
options: queryOptions,
|
|
186
259
|
});
|
|
187
260
|
|
|
@@ -330,8 +403,15 @@ export const claudeProvider = {
|
|
|
330
403
|
// Get Claude SDK
|
|
331
404
|
const query = await getClaudeSDK();
|
|
332
405
|
|
|
333
|
-
// Convert messages to
|
|
334
|
-
|
|
406
|
+
// Convert messages to SDK input format
|
|
407
|
+
// Returns { prompt, sdkMessage, hasImages }
|
|
408
|
+
// - prompt: string for single message mode (text-only)
|
|
409
|
+
// - sdkMessage: SDK user message for streaming input mode (with images)
|
|
410
|
+
const { prompt, sdkMessage, hasImages } = convertMessagesToSdkInput(messages);
|
|
411
|
+
|
|
412
|
+
if (hasImages) {
|
|
413
|
+
debugLog('[Claude SDK] Using streaming input mode for image support');
|
|
414
|
+
}
|
|
335
415
|
|
|
336
416
|
// Build SDK options
|
|
337
417
|
const sdkOptions = {
|
|
@@ -340,7 +420,13 @@ export const claudeProvider = {
|
|
|
340
420
|
|
|
341
421
|
// Streaming mode
|
|
342
422
|
if (stream) {
|
|
343
|
-
return createStreamingGenerator(
|
|
423
|
+
return createStreamingGenerator(
|
|
424
|
+
query,
|
|
425
|
+
prompt,
|
|
426
|
+
sdkMessage,
|
|
427
|
+
sdkOptions,
|
|
428
|
+
signal,
|
|
429
|
+
);
|
|
344
430
|
}
|
|
345
431
|
|
|
346
432
|
// Synchronous mode: consume streaming internally and return complete response
|
|
@@ -348,6 +434,7 @@ export const claudeProvider = {
|
|
|
348
434
|
const generator = createStreamingGenerator(
|
|
349
435
|
query,
|
|
350
436
|
prompt,
|
|
437
|
+
sdkMessage,
|
|
351
438
|
sdkOptions,
|
|
352
439
|
signal,
|
|
353
440
|
);
|
package/src/tools/chat.js
CHANGED
|
@@ -270,20 +270,35 @@ export async function chatTool(args, dependencies) {
|
|
|
270
270
|
let providerName;
|
|
271
271
|
|
|
272
272
|
if (model === 'auto') {
|
|
273
|
-
// Auto-select first available provider
|
|
274
|
-
|
|
273
|
+
// Auto-select first available provider in priority order
|
|
274
|
+
// Prioritize subscription-based providers (codex, gemini-cli, claude) over API-key providers
|
|
275
|
+
const providerOrder = [
|
|
276
|
+
'codex',
|
|
277
|
+
'gemini-cli',
|
|
278
|
+
'claude',
|
|
279
|
+
'openai',
|
|
280
|
+
'google',
|
|
281
|
+
'xai',
|
|
282
|
+
'anthropic',
|
|
283
|
+
'mistral',
|
|
284
|
+
'deepseek',
|
|
285
|
+
'openrouter',
|
|
286
|
+
];
|
|
287
|
+
|
|
288
|
+
for (const name of providerOrder) {
|
|
275
289
|
const provider = providers[name];
|
|
276
|
-
|
|
277
|
-
|
|
290
|
+
if (provider && provider.isAvailable && provider.isAvailable(config)) {
|
|
291
|
+
providerName = name;
|
|
292
|
+
selectedProvider = provider;
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
278
296
|
|
|
279
|
-
if (
|
|
297
|
+
if (!providerName) {
|
|
280
298
|
return createToolError(
|
|
281
299
|
'No providers available. Please configure at least one API key.',
|
|
282
300
|
);
|
|
283
301
|
}
|
|
284
|
-
|
|
285
|
-
providerName = availableProviders[0];
|
|
286
|
-
selectedProvider = providers[providerName];
|
|
287
302
|
} else {
|
|
288
303
|
// Use specified provider/model
|
|
289
304
|
// Try to map model to provider
|
|
@@ -998,7 +1013,7 @@ chatTool.inputSchema = {
|
|
|
998
1013
|
model: {
|
|
999
1014
|
type: 'string',
|
|
1000
1015
|
description:
|
|
1001
|
-
'AI model to use. Examples: "auto" (recommended), "codex", "gemini", "gpt-5", "grok-4-0709". Defaults to auto-selection.',
|
|
1016
|
+
'AI model to use. Examples: "auto" (recommended), "codex", "gemini", "claude", "gpt-5", "grok-4-0709". Defaults to auto-selection.',
|
|
1002
1017
|
},
|
|
1003
1018
|
files: {
|
|
1004
1019
|
type: 'array',
|
package/src/tools/consensus.js
CHANGED
|
@@ -275,8 +275,12 @@ export async function consensusTool(args, dependencies) {
|
|
|
275
275
|
let modelsToProcess = models;
|
|
276
276
|
if (models.length === 1 && models[0].toLowerCase() === 'auto') {
|
|
277
277
|
// Find first 3 available providers
|
|
278
|
+
// Prioritize subscription-based providers (codex, gemini-cli, claude) over API-key providers
|
|
278
279
|
const availableProviders = [];
|
|
279
280
|
const providerOrder = [
|
|
281
|
+
'codex',
|
|
282
|
+
'gemini-cli',
|
|
283
|
+
'claude',
|
|
280
284
|
'openai',
|
|
281
285
|
'google',
|
|
282
286
|
'xai',
|
|
@@ -980,8 +984,12 @@ async function executeConsensusWithStreaming(args, dependencies, context) {
|
|
|
980
984
|
// Special handling for single "auto" model - expand to first 3 available providers
|
|
981
985
|
let modelsToProcess = models;
|
|
982
986
|
if (models.length === 1 && models[0].toLowerCase() === 'auto') {
|
|
987
|
+
// Prioritize subscription-based providers (codex, gemini-cli, claude) over API-key providers
|
|
983
988
|
const availableProviders = [];
|
|
984
989
|
const providerOrder = [
|
|
990
|
+
'codex',
|
|
991
|
+
'gemini-cli',
|
|
992
|
+
'claude',
|
|
985
993
|
'openai',
|
|
986
994
|
'google',
|
|
987
995
|
'xai',
|
|
@@ -1609,7 +1617,7 @@ consensusTool.inputSchema = {
|
|
|
1609
1617
|
items: { type: 'string' },
|
|
1610
1618
|
minItems: 1,
|
|
1611
1619
|
description:
|
|
1612
|
-
'List of models to consult. Example: ["
|
|
1620
|
+
'List of models to consult. Example: ["codex", "gemini", "claude"]',
|
|
1613
1621
|
},
|
|
1614
1622
|
files: {
|
|
1615
1623
|
type: 'array',
|