converse-mcp-server 2.16.0 → 2.17.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "converse-mcp-server",
3
- "version": "2.16.0",
3
+ "version": "2.17.1",
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,14 +94,14 @@
94
94
  ".env.example"
95
95
  ],
96
96
  "dependencies": {
97
- "@anthropic-ai/claude-agent-sdk": "^0.2.49",
97
+ "@anthropic-ai/claude-agent-sdk": "^0.2.50",
98
98
  "@anthropic-ai/sdk": "^0.74.0",
99
99
  "@github/copilot-sdk": "^0.1.25",
100
100
  "@google/genai": "^1.42.0",
101
101
  "@mistralai/mistralai": "^1.14.0",
102
102
  "@modelcontextprotocol/sdk": "^1.26.0",
103
103
  "@openai/codex-sdk": "^0.101.0",
104
- "ai": "^6.0.94",
104
+ "ai": "^6.0.97",
105
105
  "ai-sdk-provider-gemini-cli": "^2.0.1",
106
106
  "cors": "^2.8.6",
107
107
  "dotenv": "^17.3.1",
@@ -115,7 +115,7 @@
115
115
  "devDependencies": {
116
116
  "@vitest/coverage-v8": "^4.0.18",
117
117
  "cross-env": "^10.1.0",
118
- "eslint": "^10.0.0",
118
+ "eslint": "^10.0.1",
119
119
  "prettier": "^3.8.1",
120
120
  "rimraf": "^6.1.3",
121
121
  "vitest": "^4.0.18"
@@ -27,9 +27,236 @@ const SUPPORTED_MODELS = {
27
27
  supportsWebSearch: false,
28
28
  timeout: 120000,
29
29
  description:
30
- 'GitHub Copilot via CLI SDK - requires copilot auth login authentication',
30
+ 'GitHub Copilot via CLI SDK - uses default or env-configured model',
31
31
  aliases: ['copilot-sdk', 'github-copilot'],
32
32
  },
33
+
34
+ // OpenAI models
35
+ 'gpt-4.1': {
36
+ modelName: 'gpt-4.1',
37
+ friendlyName: 'GPT-4.1 (via Copilot)',
38
+ contextWindow: 1047576,
39
+ maxOutputTokens: 32768,
40
+ supportsStreaming: true,
41
+ supportsImages: false,
42
+ supportsTemperature: false,
43
+ supportsWebSearch: false,
44
+ timeout: 120000,
45
+ description: 'OpenAI GPT-4.1 via Copilot subscription',
46
+ aliases: [],
47
+ },
48
+ 'gpt-5-mini': {
49
+ modelName: 'gpt-5-mini',
50
+ friendlyName: 'GPT-5 Mini (via Copilot)',
51
+ contextWindow: 1047576,
52
+ maxOutputTokens: 16384,
53
+ supportsStreaming: true,
54
+ supportsImages: false,
55
+ supportsTemperature: false,
56
+ supportsWebSearch: false,
57
+ timeout: 120000,
58
+ description: 'OpenAI GPT-5 Mini via Copilot subscription',
59
+ aliases: [],
60
+ },
61
+ 'gpt-5.1': {
62
+ modelName: 'gpt-5.1',
63
+ friendlyName: 'GPT-5.1 (via Copilot)',
64
+ contextWindow: 1047576,
65
+ maxOutputTokens: 32768,
66
+ supportsStreaming: true,
67
+ supportsImages: false,
68
+ supportsTemperature: false,
69
+ supportsWebSearch: false,
70
+ timeout: 120000,
71
+ description: 'OpenAI GPT-5.1 via Copilot subscription',
72
+ aliases: [],
73
+ },
74
+ 'gpt-5.1-codex': {
75
+ modelName: 'gpt-5.1-codex',
76
+ friendlyName: 'GPT-5.1 Codex (via Copilot)',
77
+ contextWindow: 192000,
78
+ maxOutputTokens: 16384,
79
+ supportsStreaming: true,
80
+ supportsImages: false,
81
+ supportsTemperature: false,
82
+ supportsWebSearch: false,
83
+ timeout: 300000,
84
+ description: 'OpenAI GPT-5.1 Codex via Copilot subscription',
85
+ aliases: [],
86
+ },
87
+ 'gpt-5.1-codex-mini': {
88
+ modelName: 'gpt-5.1-codex-mini',
89
+ friendlyName: 'GPT-5.1 Codex Mini (via Copilot)',
90
+ contextWindow: 192000,
91
+ maxOutputTokens: 16384,
92
+ supportsStreaming: true,
93
+ supportsImages: false,
94
+ supportsTemperature: false,
95
+ supportsWebSearch: false,
96
+ timeout: 300000,
97
+ description: 'OpenAI GPT-5.1 Codex Mini via Copilot subscription',
98
+ aliases: [],
99
+ },
100
+ 'gpt-5.1-codex-max': {
101
+ modelName: 'gpt-5.1-codex-max',
102
+ friendlyName: 'GPT-5.1 Codex Max (via Copilot)',
103
+ contextWindow: 192000,
104
+ maxOutputTokens: 16384,
105
+ supportsStreaming: true,
106
+ supportsImages: false,
107
+ supportsTemperature: false,
108
+ supportsWebSearch: false,
109
+ timeout: 600000,
110
+ description: 'OpenAI GPT-5.1 Codex Max via Copilot subscription',
111
+ aliases: [],
112
+ },
113
+ 'gpt-5.2': {
114
+ modelName: 'gpt-5.2',
115
+ friendlyName: 'GPT-5.2 (via Copilot)',
116
+ contextWindow: 1047576,
117
+ maxOutputTokens: 32768,
118
+ supportsStreaming: true,
119
+ supportsImages: false,
120
+ supportsTemperature: false,
121
+ supportsWebSearch: false,
122
+ timeout: 120000,
123
+ description: 'OpenAI GPT-5.2 via Copilot subscription',
124
+ aliases: ['gpt-5'],
125
+ },
126
+ 'gpt-5.2-codex': {
127
+ modelName: 'gpt-5.2-codex',
128
+ friendlyName: 'GPT-5.2 Codex (via Copilot)',
129
+ contextWindow: 192000,
130
+ maxOutputTokens: 16384,
131
+ supportsStreaming: true,
132
+ supportsImages: false,
133
+ supportsTemperature: false,
134
+ supportsWebSearch: false,
135
+ timeout: 300000,
136
+ description: 'OpenAI GPT-5.2 Codex via Copilot subscription',
137
+ aliases: [],
138
+ },
139
+ 'gpt-5.3-codex': {
140
+ modelName: 'gpt-5.3-codex',
141
+ friendlyName: 'GPT-5.3 Codex (via Copilot)',
142
+ contextWindow: 192000,
143
+ maxOutputTokens: 16384,
144
+ supportsStreaming: true,
145
+ supportsImages: false,
146
+ supportsTemperature: false,
147
+ supportsWebSearch: false,
148
+ timeout: 300000,
149
+ description: 'OpenAI GPT-5.3 Codex via Copilot subscription',
150
+ aliases: ['codex'],
151
+ },
152
+
153
+ // Anthropic models
154
+ 'claude-haiku-4.5': {
155
+ modelName: 'claude-haiku-4.5',
156
+ friendlyName: 'Claude Haiku 4.5 (via Copilot)',
157
+ contextWindow: 200000,
158
+ maxOutputTokens: 8192,
159
+ supportsStreaming: true,
160
+ supportsImages: false,
161
+ supportsTemperature: false,
162
+ supportsWebSearch: false,
163
+ timeout: 120000,
164
+ description: 'Anthropic Claude Haiku 4.5 via Copilot subscription',
165
+ aliases: ['haiku'],
166
+ },
167
+ 'claude-sonnet-4': {
168
+ modelName: 'claude-sonnet-4',
169
+ friendlyName: 'Claude Sonnet 4 (via Copilot)',
170
+ contextWindow: 200000,
171
+ maxOutputTokens: 16384,
172
+ supportsStreaming: true,
173
+ supportsImages: false,
174
+ supportsTemperature: false,
175
+ supportsWebSearch: false,
176
+ timeout: 120000,
177
+ description: 'Anthropic Claude Sonnet 4 via Copilot subscription',
178
+ aliases: [],
179
+ },
180
+ 'claude-sonnet-4.5': {
181
+ modelName: 'claude-sonnet-4.5',
182
+ friendlyName: 'Claude Sonnet 4.5 (via Copilot)',
183
+ contextWindow: 200000,
184
+ maxOutputTokens: 16384,
185
+ supportsStreaming: true,
186
+ supportsImages: false,
187
+ supportsTemperature: false,
188
+ supportsWebSearch: false,
189
+ timeout: 120000,
190
+ description: 'Anthropic Claude Sonnet 4.5 via Copilot subscription',
191
+ aliases: [],
192
+ },
193
+ 'claude-sonnet-4.6': {
194
+ modelName: 'claude-sonnet-4.6',
195
+ friendlyName: 'Claude Sonnet 4.6 (via Copilot)',
196
+ contextWindow: 200000,
197
+ maxOutputTokens: 16384,
198
+ supportsStreaming: true,
199
+ supportsImages: false,
200
+ supportsTemperature: false,
201
+ supportsWebSearch: false,
202
+ timeout: 120000,
203
+ description: 'Anthropic Claude Sonnet 4.6 via Copilot subscription',
204
+ aliases: ['sonnet'],
205
+ },
206
+ 'claude-opus-4.5': {
207
+ modelName: 'claude-opus-4.5',
208
+ friendlyName: 'Claude Opus 4.5 (via Copilot)',
209
+ contextWindow: 200000,
210
+ maxOutputTokens: 32768,
211
+ supportsStreaming: true,
212
+ supportsImages: false,
213
+ supportsTemperature: false,
214
+ supportsWebSearch: false,
215
+ timeout: 300000,
216
+ description: 'Anthropic Claude Opus 4.5 via Copilot subscription',
217
+ aliases: [],
218
+ },
219
+ 'claude-opus-4.6': {
220
+ modelName: 'claude-opus-4.6',
221
+ friendlyName: 'Claude Opus 4.6 (via Copilot)',
222
+ contextWindow: 200000,
223
+ maxOutputTokens: 32768,
224
+ supportsStreaming: true,
225
+ supportsImages: false,
226
+ supportsTemperature: false,
227
+ supportsWebSearch: false,
228
+ timeout: 300000,
229
+ description: 'Anthropic Claude Opus 4.6 via Copilot subscription',
230
+ aliases: ['opus'],
231
+ },
232
+
233
+ // Google models
234
+ 'gemini-3-pro-preview': {
235
+ modelName: 'gemini-3-pro-preview',
236
+ friendlyName: 'Gemini 3 Pro Preview (via Copilot)',
237
+ contextWindow: 1048576,
238
+ maxOutputTokens: 65536,
239
+ supportsStreaming: true,
240
+ supportsImages: false,
241
+ supportsTemperature: false,
242
+ supportsWebSearch: false,
243
+ timeout: 300000,
244
+ description: 'Google Gemini 3 Pro Preview via Copilot subscription',
245
+ aliases: ['gemini-3-pro'],
246
+ },
247
+ 'gemini-3.1-pro-preview': {
248
+ modelName: 'gemini-3.1-pro-preview',
249
+ friendlyName: 'Gemini 3.1 Pro Preview (via Copilot)',
250
+ contextWindow: 1048576,
251
+ maxOutputTokens: 65536,
252
+ supportsStreaming: true,
253
+ supportsImages: false,
254
+ supportsTemperature: false,
255
+ supportsWebSearch: false,
256
+ timeout: 300000,
257
+ description: 'Google Gemini 3.1 Pro Preview via Copilot subscription',
258
+ aliases: ['gemini', 'gemini-3.1-pro'],
259
+ },
33
260
  };
34
261
 
35
262
  class CopilotProviderError extends ProviderError {
@@ -196,28 +423,76 @@ function createPermissionHandler(accessLevel) {
196
423
  };
197
424
  }
198
425
 
426
+ /**
427
+ * Resolve a friendly alias to its SDK model identifier (case-insensitive)
428
+ * Returns the resolved model name, or null if no alias matches
429
+ */
430
+ function resolveModelAlias(name) {
431
+ if (typeof name !== 'string') return null;
432
+ const lower = name.toLowerCase().trim();
433
+ if (!lower) return null;
434
+
435
+ // Direct key match
436
+ if (SUPPORTED_MODELS[lower] && lower !== 'copilot') {
437
+ return SUPPORTED_MODELS[lower].modelName;
438
+ }
439
+
440
+ // Alias match
441
+ for (const config of Object.values(SUPPORTED_MODELS)) {
442
+ if (config.modelName === 'copilot') continue;
443
+ if (
444
+ config.aliases &&
445
+ config.aliases.some((alias) => alias.toLowerCase() === lower)
446
+ ) {
447
+ return config.modelName;
448
+ }
449
+ }
450
+
451
+ return null;
452
+ }
453
+
199
454
  /**
200
455
  * Resolve model to pass to SDK session
201
456
  * Precedence: explicit model param > config COPILOT_MODEL > omit (SDK default)
202
457
  *
458
+ * Handles copilot: prefix stripping, alias resolution, and env var fallback.
203
459
  * Note: "copilot" is a Converse routing alias, not a valid SDK model ID.
204
- * Only pass through model names that are actual SDK model IDs.
205
460
  */
206
461
  function resolveSessionModel(requestModel, config) {
207
462
  const converseAliases = ['copilot', 'copilot-sdk', 'github-copilot'];
208
463
 
209
- // If user specified a non-alias model name, pass it to SDK
210
- if (requestModel && !converseAliases.includes(requestModel.toLowerCase())) {
211
- return requestModel;
464
+ // Guard non-string inputs
465
+ if (typeof requestModel !== 'string') {
466
+ requestModel = '';
212
467
  }
213
468
 
214
- // Fall back to config value
215
- if (config?.providers?.copilotmodel) {
216
- return config.providers.copilotmodel;
469
+ // Strip copilot: prefix (case-insensitive)
470
+ let effectiveModel = requestModel;
471
+ if (effectiveModel.toLowerCase().startsWith('copilot:')) {
472
+ effectiveModel = effectiveModel.slice('copilot:'.length).trim();
217
473
  }
218
474
 
219
- // Omit let SDK use its default
220
- return undefined;
475
+ // Empty suffix or converse alias → use env/default
476
+ if (
477
+ !effectiveModel ||
478
+ converseAliases.includes(effectiveModel.toLowerCase())
479
+ ) {
480
+ const envModel = config?.providers?.copilotmodel;
481
+ if (envModel) {
482
+ let resolved = typeof envModel === 'string' ? envModel : '';
483
+ if (resolved.toLowerCase().startsWith('copilot:')) {
484
+ resolved = resolved.slice('copilot:'.length).trim();
485
+ }
486
+ if (!resolved || converseAliases.includes(resolved.toLowerCase())) {
487
+ return undefined;
488
+ }
489
+ return resolveModelAlias(resolved) || resolved;
490
+ }
491
+ return undefined;
492
+ }
493
+
494
+ // Resolve alias or passthrough unknown models to SDK
495
+ return resolveModelAlias(effectiveModel) || effectiveModel;
221
496
  }
222
497
 
223
498
  /**
@@ -376,6 +651,8 @@ async function* createStreamingGenerator(client, prompt, options, signal, config
376
651
  }
377
652
  }
378
653
 
654
+ export { resolveModelAlias, resolveSessionModel };
655
+
379
656
  /**
380
657
  * Copilot SDK Provider Implementation
381
658
  */
@@ -419,6 +696,7 @@ export const copilotProvider = {
419
696
  const client = await getCopilotClient(cwd);
420
697
  const prompt = convertMessagesToPrompt(messages);
421
698
 
699
+ const sessionModel = resolveSessionModel(model, config);
422
700
  const modelConfig = SUPPORTED_MODELS.copilot;
423
701
  const invokeOptions = {
424
702
  model,
@@ -458,13 +736,13 @@ export const copilotProvider = {
458
736
  rawResponse: { content, usage },
459
737
  metadata: {
460
738
  provider: 'copilot',
461
- model,
739
+ model: sessionModel || 'copilot',
462
740
  usage: usage
463
741
  ? {
464
742
  input_tokens: usage.input_tokens || 0,
465
743
  output_tokens: usage.output_tokens || 0,
466
744
  total_tokens:
467
- (usage.input_tokens || 0) + (usage.output_tokens || 0),
745
+ (usage.input_tokens || 0) + (usage.output_tokens || 0),
468
746
  cached_input_tokens: usage.cached_input_tokens || 0,
469
747
  }
470
748
  : null,
@@ -533,16 +811,24 @@ export const copilotProvider = {
533
811
  },
534
812
 
535
813
  getModelConfig(modelName) {
536
- const modelNameLower = modelName.toLowerCase();
814
+ if (typeof modelName !== 'string') return null;
815
+
816
+ let name = modelName;
817
+ if (name.toLowerCase().startsWith('copilot:')) {
818
+ name = name.slice('copilot:'.length).trim();
819
+ }
820
+ if (!name) return SUPPORTED_MODELS.copilot;
821
+
822
+ const nameLower = name.toLowerCase();
537
823
 
538
- if (SUPPORTED_MODELS[modelNameLower]) {
539
- return SUPPORTED_MODELS[modelNameLower];
824
+ if (SUPPORTED_MODELS[nameLower]) {
825
+ return SUPPORTED_MODELS[nameLower];
540
826
  }
541
827
 
542
- for (const [_name, config] of Object.entries(SUPPORTED_MODELS)) {
828
+ for (const config of Object.values(SUPPORTED_MODELS)) {
543
829
  if (
544
830
  config.aliases &&
545
- config.aliases.some((alias) => alias.toLowerCase() === modelNameLower)
831
+ config.aliases.some((alias) => alias.toLowerCase() === nameLower)
546
832
  ) {
547
833
  return config;
548
834
  }
package/src/tools/chat.js CHANGED
@@ -584,6 +584,12 @@ export function mapModelToProvider(model, providers) {
584
584
  return 'copilot';
585
585
  }
586
586
 
587
+ // Check copilot: prefix (e.g., copilot:gpt-5.2, copilot:claude-sonnet-4.6)
588
+ // Must be before slash-format and keyword matching to prevent misrouting
589
+ if (modelLower.startsWith('copilot:')) {
590
+ return 'copilot';
591
+ }
592
+
587
593
  // Check OpenRouter-specific patterns first
588
594
  if (
589
595
  modelLower === 'openrouter auto' ||
@@ -787,6 +787,12 @@ function mapModelToProvider(model, providers) {
787
787
  return 'copilot';
788
788
  }
789
789
 
790
+ // Check copilot: prefix (e.g., copilot:gpt-5.2, copilot:claude-sonnet-4.6)
791
+ // Must be before slash-format and keyword matching to prevent misrouting
792
+ if (modelLower.startsWith('copilot:')) {
793
+ return 'copilot';
794
+ }
795
+
790
796
  // Check OpenRouter-specific patterns first
791
797
  if (
792
798
  modelLower === 'openrouter auto' ||