converse-mcp-server 2.5.0 → 2.5.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/bin/converse.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "converse-mcp-server",
3
- "version": "2.5.0",
3
+ "version": "2.5.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",
@@ -11,58 +11,6 @@
11
11
  "engines": {
12
12
  "node": ">=20.0.0"
13
13
  },
14
- "keywords": [
15
- "mcp",
16
- "server",
17
- "ai",
18
- "chat",
19
- "consensus",
20
- "openai",
21
- "google",
22
- "gemini",
23
- "grok"
24
- ],
25
- "author": "Converse MCP Server",
26
- "license": "MIT",
27
- "homepage": "https://github.com/FallDownTheSystem/converse#readme",
28
- "repository": {
29
- "type": "git",
30
- "url": "git+https://github.com/FallDownTheSystem/converse.git"
31
- },
32
- "bugs": {
33
- "url": "https://github.com/FallDownTheSystem/converse/issues"
34
- },
35
- "files": [
36
- "src/",
37
- "bin/",
38
- "docs/",
39
- "README.md",
40
- ".env.example"
41
- ],
42
- "dependencies": {
43
- "@anthropic-ai/sdk": "^0.70.0",
44
- "@google/genai": "^1.30.0",
45
- "@mistralai/mistralai": "^1.10.0",
46
- "@modelcontextprotocol/sdk": "^1.22.0",
47
- "@openai/codex-sdk": "^0.58.0",
48
- "ai": "^5.0.101",
49
- "ai-sdk-provider-gemini-cli": "^1.4.0",
50
- "cors": "^2.8.5",
51
- "dotenv": "^17.2.3",
52
- "express": "^5.1.0",
53
- "lru-cache": "^11.2.2",
54
- "openai": "^6.9.1",
55
- "p-limit": "^7.2.0",
56
- "vite": "^7.2.2"
57
- },
58
- "devDependencies": {
59
- "@vitest/coverage-v8": "^4.0.10",
60
- "cross-env": "^10.1.0",
61
- "eslint": "^9.39.1",
62
- "prettier": "^3.6.2",
63
- "rimraf": "^6.1.0",
64
- "vitest": "^4.0.10"
65
- },
66
14
  "scripts": {
67
15
  "kill-server": "node scripts/kill-server.js",
68
16
  "start": "npm run kill-server && node src/index.js",
@@ -116,5 +64,57 @@
116
64
  "validate:fix": "node scripts/validate.js --fix",
117
65
  "validate:fast": "node scripts/validate.js --skip-tests --skip-lint",
118
66
  "precommit": "npm run validate"
67
+ },
68
+ "keywords": [
69
+ "mcp",
70
+ "server",
71
+ "ai",
72
+ "chat",
73
+ "consensus",
74
+ "openai",
75
+ "google",
76
+ "gemini",
77
+ "grok"
78
+ ],
79
+ "author": "Converse MCP Server",
80
+ "license": "MIT",
81
+ "homepage": "https://github.com/FallDownTheSystem/converse#readme",
82
+ "repository": {
83
+ "type": "git",
84
+ "url": "git+https://github.com/FallDownTheSystem/converse.git"
85
+ },
86
+ "bugs": {
87
+ "url": "https://github.com/FallDownTheSystem/converse/issues"
88
+ },
89
+ "files": [
90
+ "src/",
91
+ "bin/",
92
+ "docs/",
93
+ "README.md",
94
+ ".env.example"
95
+ ],
96
+ "dependencies": {
97
+ "@anthropic-ai/sdk": "^0.70.0",
98
+ "@google/genai": "^1.30.0",
99
+ "@mistralai/mistralai": "^1.10.0",
100
+ "@modelcontextprotocol/sdk": "^1.22.0",
101
+ "@openai/codex-sdk": "^0.58.0",
102
+ "ai": "^5.0.101",
103
+ "ai-sdk-provider-gemini-cli": "^1.4.0",
104
+ "cors": "^2.8.5",
105
+ "dotenv": "^17.2.3",
106
+ "express": "^5.1.0",
107
+ "lru-cache": "^11.2.2",
108
+ "openai": "^6.9.1",
109
+ "p-limit": "^7.2.0",
110
+ "vite": "^7.2.2"
111
+ },
112
+ "devDependencies": {
113
+ "@vitest/coverage-v8": "^4.0.10",
114
+ "cross-env": "^10.1.0",
115
+ "eslint": "^9.39.1",
116
+ "prettier": "^3.6.2",
117
+ "rimraf": "^6.1.0",
118
+ "vitest": "^4.0.10"
119
119
  }
120
- }
120
+ }
@@ -24,8 +24,8 @@ import { ProviderError, ErrorCodes, StopReasons } from './interface.js';
24
24
 
25
25
  // Supported Gemini CLI models with their configurations
26
26
  const SUPPORTED_MODELS = {
27
- 'gemini-3-pro-preview': {
28
- modelName: 'gemini-3-pro-preview',
27
+ gemini: {
28
+ modelName: 'gemini',
29
29
  friendlyName: 'Gemini 3.0 Pro Preview (via CLI)',
30
30
  contextWindow: 1048576, // 1M tokens
31
31
  maxOutputTokens: 64000,
@@ -37,6 +37,9 @@ const SUPPORTED_MODELS = {
37
37
  timeout: 300000, // 5 minutes
38
38
  description:
39
39
  'Gemini 3.0 Pro Preview via OAuth - requires Gemini CLI authentication',
40
+ aliases: ['gemini-cli'],
41
+ // Internal SDK model name (user-facing "gemini" maps to SDK's "gemini-3-pro-preview")
42
+ sdkModelName: 'gemini-3-pro-preview',
40
43
  },
41
44
  };
42
45
 
@@ -103,16 +106,17 @@ async function getAISDK() {
103
106
  * Yields normalized events compatible with ProviderStreamNormalizer
104
107
  */
105
108
  async function* createStreamingGenerator(
106
- model,
109
+ modelInstance,
107
110
  messages,
108
111
  options,
109
112
  signal,
113
+ userFacingModelName = 'gemini',
110
114
  ) {
111
115
  const { streamText } = await getAISDK();
112
116
 
113
117
  try {
114
118
  const streamOptions = {
115
- model,
119
+ model: modelInstance,
116
120
  messages,
117
121
  ...options,
118
122
  };
@@ -127,7 +131,7 @@ async function* createStreamingGenerator(
127
131
  yield {
128
132
  type: 'start',
129
133
  provider: 'gemini-cli',
130
- model: options.model || 'gemini-3-pro-preview',
134
+ model: userFacingModelName,
131
135
  };
132
136
 
133
137
  // Stream text chunks
@@ -137,10 +141,12 @@ async function* createStreamingGenerator(
137
141
  throw new GeminiCliProviderError('Request cancelled', 'CANCELLED');
138
142
  }
139
143
 
140
- // Yield delta event with content chunk
144
+ // Yield delta event with content chunk (normalized format)
141
145
  yield {
142
146
  type: 'delta',
143
- content: chunk,
147
+ data: {
148
+ textDelta: chunk,
149
+ },
144
150
  };
145
151
  }
146
152
 
@@ -196,6 +202,68 @@ function mapFinishReason(finishReason) {
196
202
  }
197
203
  }
198
204
 
205
+ /**
206
+ * Convert messages from Converse internal format to Gemini CLI SDK format
207
+ *
208
+ * Converse format (used by other providers like Anthropic):
209
+ * - Images: { type: 'image', source: { type: 'base64', media_type: '...', data: '...' } }
210
+ *
211
+ * Gemini CLI SDK format (from SDK guide):
212
+ * - Images: { type: 'image', data: '...' } (base64 string)
213
+ * - Text: { type: 'text', text: '...' }
214
+ *
215
+ * @param {Array} messages - Messages in Converse internal format
216
+ * @returns {Array} Messages in Gemini CLI SDK format
217
+ */
218
+ function convertToGeminiCliMessages(messages) {
219
+ return messages.map((message) => {
220
+ // If content is a string, no conversion needed
221
+ if (typeof message.content === 'string') {
222
+ return message;
223
+ }
224
+
225
+ // If content is an array, convert each part
226
+ if (Array.isArray(message.content)) {
227
+ const convertedContent = message.content.map((part) => {
228
+ // Text parts are already in correct format
229
+ if (part.type === 'text') {
230
+ return part;
231
+ }
232
+
233
+ // Convert image from Converse format to Gemini CLI SDK format
234
+ if (part.type === 'image' && part.source) {
235
+ return {
236
+ type: 'image',
237
+ data: part.source.data, // Extract base64 data (use 'data' not 'image')
238
+ };
239
+ }
240
+
241
+ // If already in Gemini CLI format, return as-is
242
+ if (part.type === 'image' && part.data) {
243
+ return part;
244
+ }
245
+
246
+ // Handle file parts (future-proofing)
247
+ if (part.type === 'file' && part.data) {
248
+ return part;
249
+ }
250
+
251
+ // Unknown part type, return as-is and let SDK handle it
252
+ debugLog(`[Gemini CLI] Unknown content part type: ${part.type}`);
253
+ return part;
254
+ });
255
+
256
+ return {
257
+ ...message,
258
+ content: convertedContent,
259
+ };
260
+ }
261
+
262
+ // Unknown content type, return as-is
263
+ return message;
264
+ });
265
+ }
266
+
199
267
  /**
200
268
  * Gemini CLI Provider Implementation
201
269
  */
@@ -208,7 +276,7 @@ export const geminiCliProvider = {
208
276
  */
209
277
  async invoke(messages, options = {}) {
210
278
  const {
211
- model = 'gemini-3-pro-preview',
279
+ model = 'gemini',
212
280
  config,
213
281
  stream = false,
214
282
  signal,
@@ -234,6 +302,18 @@ export const geminiCliProvider = {
234
302
  }
235
303
 
236
304
  try {
305
+ // Get model configuration to map user-facing name to SDK model name
306
+ const modelConfig = this.getModelConfig(model);
307
+ if (!modelConfig) {
308
+ throw new GeminiCliProviderError(
309
+ `Model ${model} not supported by Gemini CLI provider`,
310
+ ErrorCodes.MODEL_NOT_FOUND,
311
+ );
312
+ }
313
+
314
+ // Get the SDK model name (e.g., "gemini" -> "gemini-3-pro-preview")
315
+ const sdkModelName = modelConfig.sdkModelName || model;
316
+
237
317
  // Get SDKs
238
318
  const createGeminiProvider = await getGeminiCliSDK();
239
319
  const { generateText } = await getAISDK();
@@ -243,12 +323,15 @@ export const geminiCliProvider = {
243
323
  authType: 'oauth-personal',
244
324
  });
245
325
 
246
- // Create model instance
247
- const modelInstance = gemini(model);
326
+ // Create model instance with SDK model name
327
+ const modelInstance = gemini(sdkModelName);
328
+
329
+ // Convert messages from Converse format to Gemini CLI SDK format
330
+ const convertedMessages = convertToGeminiCliMessages(messages);
248
331
 
249
332
  // Build AI SDK options
250
333
  const aiOptions = {
251
- messages,
334
+ messages: convertedMessages,
252
335
  };
253
336
 
254
337
  // Add optional parameters
@@ -271,7 +354,13 @@ export const geminiCliProvider = {
271
354
 
272
355
  // Streaming mode
273
356
  if (stream) {
274
- return createStreamingGenerator(modelInstance, messages, aiOptions, signal);
357
+ return createStreamingGenerator(
358
+ modelInstance,
359
+ convertedMessages,
360
+ aiOptions,
361
+ signal,
362
+ model, // Pass user-facing model name for metadata
363
+ );
275
364
  }
276
365
 
277
366
  // Synchronous mode
@@ -382,7 +471,17 @@ export const geminiCliProvider = {
382
471
  return SUPPORTED_MODELS[modelNameLower];
383
472
  }
384
473
 
385
- // No aliases for Gemini CLI models currently
474
+ // Check aliases
475
+ for (const [supportedModel, config] of Object.entries(SUPPORTED_MODELS)) {
476
+ if (config.aliases) {
477
+ for (const alias of config.aliases) {
478
+ if (alias.toLowerCase() === modelNameLower) {
479
+ return config;
480
+ }
481
+ }
482
+ }
483
+ }
484
+
386
485
  return null;
387
486
  },
388
487
  };
@@ -144,7 +144,6 @@ const SUPPORTED_MODELS = {
144
144
  'gemini3',
145
145
  'gemini-3-pro',
146
146
  '3-pro',
147
- 'gemini', // Moving from 2.5 Pro
148
147
  'gemini pro', // Moving from 2.5 Pro
149
148
  'gemini-pro', // Moving from 2.5 Pro
150
149
  'pro', // Moving from 2.5 Pro
@@ -26,13 +26,13 @@ import { geminiCliProvider } from './gemini-cli.js';
26
26
  const providers = {
27
27
  openai: openaiProvider,
28
28
  xai: xaiProvider,
29
+ 'gemini-cli': geminiCliProvider,
29
30
  google: googleProvider,
30
31
  anthropic: anthropicProvider,
31
32
  mistral: mistralProvider,
32
33
  deepseek: deepseekProvider,
33
34
  openrouter: openrouterProvider,
34
35
  codex: codexProvider,
35
- 'gemini-cli': geminiCliProvider,
36
36
  };
37
37
 
38
38
  /**
package/src/tools/chat.js CHANGED
@@ -416,6 +416,8 @@ function resolveAutoModel(model, providerName) {
416
416
  }
417
417
 
418
418
  const defaults = {
419
+ codex: 'codex',
420
+ 'gemini-cli': 'gemini',
419
421
  openai: 'gpt-5',
420
422
  xai: 'grok-4-0709',
421
423
  google: 'gemini-pro',
@@ -431,8 +433,15 @@ function resolveAutoModel(model, providerName) {
431
433
  export function mapModelToProvider(model, providers) {
432
434
  const modelLower = model.toLowerCase();
433
435
 
434
- // Handle "auto" - default to OpenAI
436
+ // Handle "auto" - prioritize: codex > gemini-cli > openai
435
437
  if (modelLower === 'auto') {
438
+ // Check availability in priority order
439
+ if (providers['codex']) {
440
+ return 'codex';
441
+ }
442
+ if (providers['gemini-cli']) {
443
+ return 'gemini-cli';
444
+ }
436
445
  return 'openai';
437
446
  }
438
447
 
@@ -442,7 +451,7 @@ export function mapModelToProvider(model, providers) {
442
451
  }
443
452
 
444
453
  // Check Gemini CLI (exact match only - routes to CLI provider instead of Google API)
445
- if (modelLower === 'gemini') {
454
+ if (modelLower === 'gemini' || modelLower === 'gemini-cli') {
446
455
  return 'gemini-cli';
447
456
  }
448
457
 
@@ -495,7 +504,6 @@ export function mapModelToProvider(model, providers) {
495
504
 
496
505
  // Google models
497
506
  if (
498
- modelLower.includes('gemini') ||
499
507
  modelLower.includes('flash') ||
500
508
  modelLower.includes('pro') ||
501
509
  modelLower === 'google'
@@ -939,7 +947,7 @@ chatTool.inputSchema = {
939
947
  model: {
940
948
  type: 'string',
941
949
  description:
942
- 'AI model to use. Examples: "auto" (recommended), "gpt-5", "gemini-pro", "grok-4-0709". Defaults to auto-selection.',
950
+ 'AI model to use. Examples: "auto" (recommended), "codex", "gemini", "gpt-5", "grok-4-0709". Defaults to auto-selection.',
943
951
  },
944
952
  files: {
945
953
  type: 'array',
@@ -653,6 +653,8 @@ Please provide your refined response:`;
653
653
  */
654
654
  function getDefaultModelForProvider(providerName) {
655
655
  const defaults = {
656
+ codex: 'codex',
657
+ 'gemini-cli': 'gemini',
656
658
  openai: 'gpt-5',
657
659
  xai: 'grok-4-0709',
658
660
  google: 'gemini-pro',
@@ -679,8 +681,15 @@ function resolveAutoModel(model, providerName) {
679
681
  function mapModelToProvider(model, providers) {
680
682
  const modelLower = model.toLowerCase();
681
683
 
682
- // Handle "auto" - default to OpenAI
684
+ // Handle "auto" - prioritize: codex > gemini-cli > openai
683
685
  if (modelLower === 'auto') {
686
+ // Check availability in priority order
687
+ if (providers['codex']) {
688
+ return 'codex';
689
+ }
690
+ if (providers['gemini-cli']) {
691
+ return 'gemini-cli';
692
+ }
684
693
  return 'openai';
685
694
  }
686
695
 
@@ -690,7 +699,7 @@ function mapModelToProvider(model, providers) {
690
699
  }
691
700
 
692
701
  // Check Gemini CLI (exact match only - routes to CLI provider instead of Google API)
693
- if (modelLower === 'gemini') {
702
+ if (modelLower === 'gemini' || modelLower === 'gemini-cli') {
694
703
  return 'gemini-cli';
695
704
  }
696
705
 
@@ -743,7 +752,6 @@ function mapModelToProvider(model, providers) {
743
752
 
744
753
  // Google models
745
754
  if (
746
- modelLower.includes('gemini') ||
747
755
  modelLower.includes('flash') ||
748
756
  modelLower.includes('pro') ||
749
757
  modelLower === 'google'