converse-mcp-server 2.4.2 → 2.5.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/docs/API.md CHANGED
@@ -331,16 +331,16 @@ MCP_TRANSPORT=stdio npm start
331
331
  | `gpt-4o` | 128K | 16K | Multimodal | Vision, general chat |
332
332
  | `gpt-4o-mini` | 128K | 16K | Fast multimodal | Quick responses, images |
333
333
 
334
- ### Google/Gemini Models
334
+ ### Google/Gemini Models (API-based)
335
335
 
336
336
  | Model | Alias | Context | Tokens | Features | Use Cases |
337
337
  |-------|-------|---------|--------|----------|-----------|
338
- | `gemini-3-pro-preview` | `pro`, `gemini` | 1M | 64K | Thinking levels, enhanced reasoning | Complex problems, deep analysis |
338
+ | `gemini-3-pro-preview` | `pro` | 1M | 64K | Thinking levels, enhanced reasoning | Complex problems, deep analysis |
339
339
  | `gemini-2.5-flash` | `flash` | 1M | 65K | Ultra-fast | Quick analysis, simple queries |
340
340
  | `gemini-2.5-pro` | `pro 2.5` | 1M | 65K | Thinking mode | Deep reasoning, architecture |
341
341
  | `gemini-2.0-flash` | `flash2` | 1M | 65K | Latest | Experimental thinking |
342
342
 
343
- **Note:** Default aliases `gemini`, `pro`, and `gemini-pro` now point to Gemini 3.0 Pro. Use `gemini-2.5-pro` explicitly if you need the 2.5 version.
343
+ **Note:** The short model name `gemini` now routes to **Gemini CLI** (OAuth-based). For Google API access, use specific model names like `gemini-2.5-pro` or `gemini-2.0-flash`.
344
344
 
345
345
  ### X.AI/Grok Models
346
346
 
@@ -398,6 +398,42 @@ MCP_TRANSPORT=stdio npm start
398
398
  - **Response times**: 6-20 seconds typical (complex tasks may take minutes)
399
399
  - **Authentication**: Requires ChatGPT login OR `CODEX_API_KEY` environment variable
400
400
 
401
+ ### Gemini CLI Models (OAuth-based)
402
+
403
+ **Gemini CLI** provides subscription-based access to Gemini models through OAuth:
404
+
405
+ - **Model**: `gemini` (routes to gemini-3-pro-preview)
406
+ - **Authentication**: OAuth via Gemini CLI (requires one-time setup)
407
+ - **Setup**: Install `@google/gemini-cli` globally and run `gemini` to authenticate
408
+ - **Billing**: Uses Google subscription (Google One AI Premium or Gemini Advanced) instead of API credits
409
+ - **Credentials**: Stored in `~/.gemini/oauth_creds.json`
410
+ - **Features**: Access to enhanced agentic features available through CLI
411
+ - **Context**: 1M tokens (inherited from gemini-3-pro-preview)
412
+ - **Output**: 64K tokens
413
+
414
+ **Authentication Setup:**
415
+ ```bash
416
+ # Install Gemini CLI globally
417
+ npm install -g @google/gemini-cli
418
+
419
+ # Run interactive authentication
420
+ gemini
421
+
422
+ # Follow prompts to authenticate via browser
423
+ # Credentials are saved to ~/.gemini/oauth_creds.json
424
+ ```
425
+
426
+ **Usage Example:**
427
+ ```json
428
+ {
429
+ "name": "chat",
430
+ "arguments": {
431
+ "prompt": "Explain the event loop in JavaScript",
432
+ "model": "gemini"
433
+ }
434
+ }
435
+ ```
436
+
401
437
  **Codex-Specific Behavior:**
402
438
  - `continuation_id` - Required for thread continuation (maintains full conversation history)
403
439
  - `files` parameter - Files accessed directly from working directory, not passed as message content
package/docs/PROVIDERS.md CHANGED
@@ -20,11 +20,11 @@ This guide documents all supported AI providers in the Converse MCP Server and t
20
20
  - **Get Key**: [makersuite.google.com/app/apikey](https://makersuite.google.com/app/apikey)
21
21
  - **Environment Variable**: `GOOGLE_API_KEY`
22
22
  - **Supported Models**:
23
- - `gemini-3-pro-preview` (aliases: `pro`, `gemini`) - Enhanced reasoning with thinking levels (1M context, 64K output)
23
+ - `gemini-3-pro-preview` (alias: `pro`) - Enhanced reasoning with thinking levels (1M context, 64K output)
24
24
  - `gemini-2.5-pro` (alias: `pro 2.5`) - Deep reasoning with thinking budget (1M context, 65K output)
25
25
  - `gemini-2.5-flash` (alias: `flash`) - Ultra-fast model with thinking budget (1M context, 65K output)
26
26
  - `gemini-2.0-flash`, `gemini-2.0-flash-lite` - Latest generation (1M context, 65K output)
27
- - **Note**: Default aliases (`gemini`, `pro`, `gemini-pro`) now point to Gemini 3.0 Pro. Use `gemini-2.5-pro` explicitly if you need version 2.5.
27
+ - **Note**: The short model name `gemini` now routes to **Gemini CLI** (OAuth-based access). For Google API access, use specific model names like `gemini-2.5-pro` or `gemini-2.0-flash`.
28
28
 
29
29
  ### X.AI (Grok)
30
30
  - **API Key Format**: `xai-...` (starts with `xai-`)
@@ -114,6 +114,73 @@ This guide documents all supported AI providers in the Converse MCP Server and t
114
114
  - Use `CODEX_APPROVAL_POLICY=never` for headless server deployments
115
115
  - Always use `continuation_id` for thread continuation
116
116
 
117
+ ### Gemini CLI
118
+ - **Authentication**: OAuth via Gemini CLI (no API key needed)
119
+ - **Setup Required**:
120
+ 1. Install Gemini CLI globally: `npm install -g @google/gemini-cli`
121
+ 2. Authenticate: Run `gemini` command and follow interactive prompts
122
+ 3. Credentials stored in `~/.gemini/oauth_creds.json`
123
+ - **Environment Variables**: None (uses OAuth credentials file)
124
+ - **Supported Models**:
125
+ - `gemini` - Routes to gemini-3-pro-preview via CLI
126
+ - Provides access to Gemini 3.0 Pro Preview through Google subscription (Google One AI Premium or Gemini Advanced)
127
+
128
+ **Key Features:**
129
+ - **OAuth Authentication**: Uses Google account login instead of API keys
130
+ - **Subscription Access**: Leverage Google subscription instead of paying per API call
131
+ - **Enhanced Features**: Access to agentic features available through CLI that aren't in standard API
132
+ - **Model Support**: Currently supports gemini-3-pro-preview only
133
+
134
+ **Authentication Setup:**
135
+ ```bash
136
+ # Install Gemini CLI globally
137
+ npm install -g @google/gemini-cli
138
+
139
+ # Run interactive authentication (one-time setup)
140
+ gemini
141
+
142
+ # Follow prompts to:
143
+ # 1. Select authentication method (Personal OAuth recommended)
144
+ # 2. Authorize via browser
145
+ # 3. Credentials are saved to ~/.gemini/oauth_creds.json
146
+ ```
147
+
148
+ **Usage Examples:**
149
+
150
+ *Chat Tool:*
151
+ ```json
152
+ {
153
+ "name": "chat",
154
+ "arguments": {
155
+ "prompt": "Explain async/await in JavaScript",
156
+ "model": "gemini"
157
+ }
158
+ }
159
+ ```
160
+
161
+ *Consensus Tool:*
162
+ ```json
163
+ {
164
+ "name": "consensus",
165
+ "arguments": {
166
+ "prompt": "Should we use TypeScript for this component?",
167
+ "models": ["gemini", "gpt-5", "claude-sonnet-4"]
168
+ }
169
+ }
170
+ ```
171
+
172
+ **Best Practices:**
173
+ - Authenticate before first use (run `gemini` CLI command)
174
+ - Use specific model names for Google API access (e.g., `gemini-2.5-pro`)
175
+ - Model name `gemini` is reserved for CLI-based access
176
+ - Check credentials file exists at `~/.gemini/oauth_creds.json` if authentication fails
177
+
178
+ **Differences from Google API Provider:**
179
+ - **Authentication**: OAuth (CLI) vs API Key (Google API)
180
+ - **Billing**: Google subscription vs pay-per-use API
181
+ - **Model Routing**: `gemini` → CLI provider, specific names (e.g., `gemini-2.5-pro`) → API provider
182
+ - **Models**: Only gemini-3-pro-preview vs full Gemini model family
183
+
117
184
  ## Configuration Examples
118
185
 
119
186
  ### Basic Configuration (.env file)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "converse-mcp-server",
3
- "version": "2.4.2",
3
+ "version": "2.5.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",
@@ -45,6 +45,8 @@
45
45
  "@mistralai/mistralai": "^1.10.0",
46
46
  "@modelcontextprotocol/sdk": "^1.22.0",
47
47
  "@openai/codex-sdk": "^0.58.0",
48
+ "ai": "^5.0.101",
49
+ "ai-sdk-provider-gemini-cli": "^1.4.0",
48
50
  "cors": "^2.8.5",
49
51
  "dotenv": "^17.2.3",
50
52
  "express": "^5.1.0",
@@ -0,0 +1,388 @@
1
+ /**
2
+ * Gemini CLI Provider
3
+ *
4
+ * Provider implementation for Google's Gemini models using the ai-sdk-provider-gemini-cli package.
5
+ * Implements the unified interface: async invoke(messages, options) => { content, stop_reason, rawResponse }
6
+ *
7
+ * Key features:
8
+ * - Uses OAuth authentication from Gemini CLI (no API keys needed)
9
+ * - Supports gemini-3-pro-preview model via Google Cloud Code endpoints
10
+ * - Uses AI SDK v5 standard interfaces (generateText/streamText)
11
+ * - Compatible with both chat and consensus tools
12
+ *
13
+ * Authentication:
14
+ * - Requires global Gemini CLI installation: npm install -g @google/gemini-cli
15
+ * - User must authenticate once via: gemini (interactive CLI)
16
+ * - Credentials stored in ~/.gemini/oauth_creds.json
17
+ */
18
+
19
+ import { existsSync } from 'node:fs';
20
+ import { homedir } from 'node:os';
21
+ import { join } from 'node:path';
22
+ import { debugLog, debugError } from '../utils/console.js';
23
+ import { ProviderError, ErrorCodes, StopReasons } from './interface.js';
24
+
25
+ // Supported Gemini CLI models with their configurations
26
+ const SUPPORTED_MODELS = {
27
+ 'gemini-3-pro-preview': {
28
+ modelName: 'gemini-3-pro-preview',
29
+ friendlyName: 'Gemini 3.0 Pro Preview (via CLI)',
30
+ contextWindow: 1048576, // 1M tokens
31
+ maxOutputTokens: 64000,
32
+ supportsStreaming: true,
33
+ supportsImages: true, // Base64 only (no URLs)
34
+ supportsTemperature: true,
35
+ supportsThinking: true,
36
+ supportsWebSearch: true,
37
+ timeout: 300000, // 5 minutes
38
+ description:
39
+ 'Gemini 3.0 Pro Preview via OAuth - requires Gemini CLI authentication',
40
+ },
41
+ };
42
+
43
+ /**
44
+ * Custom error class for Gemini CLI provider errors
45
+ */
46
+ class GeminiCliProviderError extends ProviderError {
47
+ constructor(message, code, originalError = null) {
48
+ super(message, code, originalError);
49
+ this.name = 'GeminiCliProviderError';
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Check if OAuth credentials file exists
55
+ * @returns {boolean} True if credentials file exists
56
+ */
57
+ function hasOAuthCredentials() {
58
+ try {
59
+ const credsPath = join(homedir(), '.gemini', 'oauth_creds.json');
60
+ return existsSync(credsPath);
61
+ } catch (error) {
62
+ debugError('[Gemini CLI] Error checking OAuth credentials', error);
63
+ return false;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Dynamically import Gemini CLI SDK (lazy loading)
69
+ * This keeps the SDK as an optional dependency
70
+ */
71
+ async function getGeminiCliSDK() {
72
+ try {
73
+ // Use dynamic import to load SDK only when needed
74
+ const { createGeminiProvider } = await import('ai-sdk-provider-gemini-cli');
75
+ return createGeminiProvider;
76
+ } catch (error) {
77
+ throw new GeminiCliProviderError(
78
+ 'Gemini CLI SDK not installed. Install with: npm install ai-sdk-provider-gemini-cli',
79
+ 'GEMINI_CLI_NOT_INSTALLED',
80
+ error,
81
+ );
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Dynamically import AI SDK (lazy loading)
87
+ */
88
+ async function getAISDK() {
89
+ try {
90
+ const { generateText, streamText } = await import('ai');
91
+ return { generateText, streamText };
92
+ } catch (error) {
93
+ throw new GeminiCliProviderError(
94
+ 'AI SDK not installed. Install with: npm install ai',
95
+ 'AI_SDK_NOT_INSTALLED',
96
+ error,
97
+ );
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Create stream generator for Gemini CLI streaming responses
103
+ * Yields normalized events compatible with ProviderStreamNormalizer
104
+ */
105
+ async function* createStreamingGenerator(
106
+ model,
107
+ messages,
108
+ options,
109
+ signal,
110
+ ) {
111
+ const { streamText } = await getAISDK();
112
+
113
+ try {
114
+ const streamOptions = {
115
+ model,
116
+ messages,
117
+ ...options,
118
+ };
119
+
120
+ if (signal) {
121
+ streamOptions.abortSignal = signal;
122
+ }
123
+
124
+ const result = await streamText(streamOptions);
125
+
126
+ // Yield start event
127
+ yield {
128
+ type: 'start',
129
+ provider: 'gemini-cli',
130
+ model: options.model || 'gemini-3-pro-preview',
131
+ };
132
+
133
+ // Stream text chunks
134
+ for await (const chunk of result.textStream) {
135
+ // Check for cancellation
136
+ if (signal?.aborted) {
137
+ throw new GeminiCliProviderError('Request cancelled', 'CANCELLED');
138
+ }
139
+
140
+ // Yield delta event with content chunk
141
+ yield {
142
+ type: 'delta',
143
+ content: chunk,
144
+ };
145
+ }
146
+
147
+ // Get final usage stats and metadata
148
+ const usage = await result.usage;
149
+ const finishReason = await result.finishReason;
150
+
151
+ // Yield usage event
152
+ if (usage) {
153
+ yield {
154
+ type: 'usage',
155
+ usage: {
156
+ input_tokens: usage.promptTokens || 0,
157
+ output_tokens: usage.completionTokens || 0,
158
+ total_tokens: usage.totalTokens || 0,
159
+ cached_input_tokens: 0,
160
+ },
161
+ };
162
+ }
163
+
164
+ // Yield end event
165
+ yield {
166
+ type: 'end',
167
+ stop_reason: mapFinishReason(finishReason),
168
+ finish_reason: finishReason,
169
+ };
170
+ } catch (error) {
171
+ if (signal?.aborted) {
172
+ throw new GeminiCliProviderError('Request cancelled', 'CANCELLED');
173
+ }
174
+ throw error;
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Map AI SDK finish reasons to our StopReasons enum
180
+ */
181
+ function mapFinishReason(finishReason) {
182
+ switch (finishReason) {
183
+ case 'stop':
184
+ return StopReasons.STOP;
185
+ case 'length':
186
+ case 'max-tokens':
187
+ return StopReasons.LENGTH;
188
+ case 'content-filter':
189
+ return StopReasons.CONTENT_FILTER;
190
+ case 'tool-calls':
191
+ return StopReasons.TOOL_USE;
192
+ case 'error':
193
+ return StopReasons.ERROR;
194
+ default:
195
+ return StopReasons.OTHER;
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Gemini CLI Provider Implementation
201
+ */
202
+ export const geminiCliProvider = {
203
+ /**
204
+ * Invoke Gemini CLI with messages and options
205
+ * @param {Array} messages - Message array (Converse format)
206
+ * @param {Object} options - Invocation options
207
+ * @returns {Promise<Object>|AsyncGenerator} Response or stream generator
208
+ */
209
+ async invoke(messages, options = {}) {
210
+ const {
211
+ model = 'gemini-3-pro-preview',
212
+ config,
213
+ stream = false,
214
+ signal,
215
+ reasoning_effort,
216
+ temperature,
217
+ use_websearch,
218
+ } = options;
219
+
220
+ // Validate configuration
221
+ if (!config) {
222
+ throw new GeminiCliProviderError(
223
+ 'Configuration is required',
224
+ ErrorCodes.MISSING_API_KEY,
225
+ );
226
+ }
227
+
228
+ // Check OAuth credentials
229
+ if (!hasOAuthCredentials()) {
230
+ throw new GeminiCliProviderError(
231
+ 'Gemini CLI authentication required. Run: gemini (interactive CLI) to authenticate',
232
+ ErrorCodes.INVALID_API_KEY,
233
+ );
234
+ }
235
+
236
+ try {
237
+ // Get SDKs
238
+ const createGeminiProvider = await getGeminiCliSDK();
239
+ const { generateText } = await getAISDK();
240
+
241
+ // Create provider instance with OAuth authentication
242
+ const gemini = createGeminiProvider({
243
+ authType: 'oauth-personal',
244
+ });
245
+
246
+ // Create model instance
247
+ const modelInstance = gemini(model);
248
+
249
+ // Build AI SDK options
250
+ const aiOptions = {
251
+ messages,
252
+ };
253
+
254
+ // Add optional parameters
255
+ if (temperature !== undefined) {
256
+ aiOptions.temperature = temperature;
257
+ }
258
+
259
+ // Note: reasoning_effort and use_websearch are not directly supported by AI SDK
260
+ // These would need to be handled at the API level if the provider supports them
261
+ if (reasoning_effort !== undefined) {
262
+ debugLog(
263
+ '[Gemini CLI] Parameter "reasoning_effort" not directly supported (ignored)',
264
+ );
265
+ }
266
+ if (use_websearch) {
267
+ debugLog(
268
+ '[Gemini CLI] Parameter "use_websearch" not directly supported (ignored)',
269
+ );
270
+ }
271
+
272
+ // Streaming mode
273
+ if (stream) {
274
+ return createStreamingGenerator(modelInstance, messages, aiOptions, signal);
275
+ }
276
+
277
+ // Synchronous mode
278
+ const startTime = Date.now();
279
+
280
+ const result = await generateText({
281
+ model: modelInstance,
282
+ ...aiOptions,
283
+ ...(signal && { abortSignal: signal }),
284
+ });
285
+
286
+ const responseTime = Date.now() - startTime;
287
+
288
+ // Extract content from AI SDK v5 response format
289
+ const content = result.content?.[0]?.text || result.text || '';
290
+
291
+ return {
292
+ content,
293
+ stop_reason: mapFinishReason(result.finishReason),
294
+ rawResponse: result,
295
+ metadata: {
296
+ provider: 'gemini-cli',
297
+ model,
298
+ usage: result.usage
299
+ ? {
300
+ input_tokens: result.usage.promptTokens || 0,
301
+ output_tokens: result.usage.completionTokens || 0,
302
+ total_tokens: result.usage.totalTokens || 0,
303
+ cached_input_tokens: 0,
304
+ }
305
+ : null,
306
+ response_time_ms: responseTime,
307
+ finish_reason: result.finishReason || 'stop',
308
+ },
309
+ };
310
+ } catch (error) {
311
+ debugError('[Gemini CLI] Execution error', error);
312
+
313
+ // Map common errors to standard error codes
314
+ if (
315
+ error.message?.includes('authentication') ||
316
+ error.message?.includes('oauth') ||
317
+ error.message?.includes('credentials')
318
+ ) {
319
+ throw new GeminiCliProviderError(
320
+ 'Gemini CLI authentication failed. Run: gemini (interactive CLI) to authenticate',
321
+ ErrorCodes.INVALID_API_KEY,
322
+ error,
323
+ );
324
+ }
325
+
326
+ if (error.message?.includes('rate limit')) {
327
+ throw new GeminiCliProviderError(
328
+ 'Rate limit exceeded',
329
+ ErrorCodes.RATE_LIMIT_EXCEEDED,
330
+ error,
331
+ );
332
+ }
333
+
334
+ if (error.message?.includes('timeout')) {
335
+ throw new GeminiCliProviderError(
336
+ 'Request timeout',
337
+ ErrorCodes.TIMEOUT_ERROR,
338
+ error,
339
+ );
340
+ }
341
+
342
+ // Re-throw as Gemini CLI error
343
+ throw new GeminiCliProviderError(
344
+ error.message || 'Gemini CLI execution failed',
345
+ ErrorCodes.API_ERROR,
346
+ error,
347
+ );
348
+ }
349
+ },
350
+
351
+ /**
352
+ * Validate Gemini CLI configuration
353
+ * Gemini CLI uses OAuth authentication (no API keys needed)
354
+ */
355
+ validateConfig(_config) {
356
+ // Check if OAuth credentials file exists
357
+ return hasOAuthCredentials();
358
+ },
359
+
360
+ /**
361
+ * Check if Gemini CLI provider is available
362
+ */
363
+ isAvailable(config) {
364
+ return this.validateConfig(config);
365
+ },
366
+
367
+ /**
368
+ * Get supported Gemini CLI models
369
+ */
370
+ getSupportedModels() {
371
+ return SUPPORTED_MODELS;
372
+ },
373
+
374
+ /**
375
+ * Get model configuration for specific model
376
+ */
377
+ getModelConfig(modelName) {
378
+ const modelNameLower = modelName.toLowerCase();
379
+
380
+ // Check exact match
381
+ if (SUPPORTED_MODELS[modelNameLower]) {
382
+ return SUPPORTED_MODELS[modelNameLower];
383
+ }
384
+
385
+ // No aliases for Gemini CLI models currently
386
+ return null;
387
+ },
388
+ };
@@ -14,6 +14,7 @@ import { mistralProvider } from './mistral.js';
14
14
  import { deepseekProvider } from './deepseek.js';
15
15
  import { openrouterProvider } from './openrouter.js';
16
16
  import { codexProvider } from './codex.js';
17
+ import { geminiCliProvider } from './gemini-cli.js';
17
18
 
18
19
  /**
19
20
  * Provider registry map
@@ -31,6 +32,7 @@ const providers = {
31
32
  deepseek: deepseekProvider,
32
33
  openrouter: openrouterProvider,
33
34
  codex: codexProvider,
35
+ 'gemini-cli': geminiCliProvider,
34
36
  };
35
37
 
36
38
  /**
package/src/tools/chat.js CHANGED
@@ -441,6 +441,11 @@ export function mapModelToProvider(model, providers) {
441
441
  return 'codex';
442
442
  }
443
443
 
444
+ // Check Gemini CLI (exact match only - routes to CLI provider instead of Google API)
445
+ if (modelLower === 'gemini') {
446
+ return 'gemini-cli';
447
+ }
448
+
444
449
  // Check OpenRouter-specific patterns first
445
450
  if (
446
451
  modelLower === 'openrouter auto' ||
@@ -684,6 +684,16 @@ function mapModelToProvider(model, providers) {
684
684
  return 'openai';
685
685
  }
686
686
 
687
+ // Check Codex (exact match only - don't route "gpt-5-codex" etc to Codex provider)
688
+ if (modelLower === 'codex') {
689
+ return 'codex';
690
+ }
691
+
692
+ // Check Gemini CLI (exact match only - routes to CLI provider instead of Google API)
693
+ if (modelLower === 'gemini') {
694
+ return 'gemini-cli';
695
+ }
696
+
687
697
  // Check OpenRouter-specific patterns first
688
698
  if (
689
699
  modelLower === 'openrouter auto' ||