converse-mcp-server 3.3.0 → 3.4.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/.env.example CHANGED
@@ -80,9 +80,9 @@ OPENROUTER_API_KEY=your_openrouter_api_key_here
80
80
  # WARNING: Interactive policies may cause hangs in server/headless mode
81
81
  # CODEX_APPROVAL_POLICY=never
82
82
 
83
- # Default Codex model (default: gpt-5.6-sol)
84
- # Options: gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex-spark
85
- # CODEX_MODEL=gpt-5.6-sol
83
+ # Default Codex backend model (default: gpt-6-astra). Per-request override: models: ["codex:<model>"]
84
+ # Options: gpt-6-astra, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.3-codex-spark
85
+ # CODEX_MODEL=gpt-6-astra
86
86
 
87
87
  # ============================================
88
88
  # Server Configuration
package/README.md CHANGED
@@ -281,7 +281,9 @@ Any other model works via its full `provider/model` slug or the `openrouter:` na
281
281
 
282
282
  ### Codex Models
283
283
 
284
- - **codex**: OpenAI Codex agentic coding assistant
284
+ - **codex**: OpenAI Codex agentic coding assistant (GPT-6 Astra by default)
285
+ - Pick another backend per request with `codex:<model>` (e.g. `codex:sol`, `codex:gpt-5.6-terra`) or globally with `CODEX_MODEL`; backends: `gpt-6-astra` (alias `astra`), `gpt-5.6-sol` (`sol`), `gpt-5.6-terra` (`terra`), `gpt-5.6-luna` (`luna`), `gpt-5.5`, `gpt-5.3-codex-spark` (`spark`)
286
+ - `reasoning_effort` maps onto the tiers the chosen backend accepts (GPT-6 Astra: `low` through `max`, no `none`)
285
287
  - Thread-based sessions with persistent context
286
288
  - Direct filesystem access from working directory
287
289
  - Typical response time: 6-20 seconds (longer for complex tasks)
@@ -357,6 +359,7 @@ CODEX_API_KEY=your_codex_api_key_here # Optional if ChatGPT login availabl
357
359
  CODEX_SANDBOX_MODE=read-only # read-only (default), workspace-write, danger-full-access
358
360
  CODEX_SKIP_GIT_CHECK=true # true (default), false
359
361
  CODEX_APPROVAL_POLICY=never # never (default), untrusted, on-failure, on-request
362
+ CODEX_MODEL=gpt-6-astra # gpt-6-astra (default), gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5
360
363
  ```
361
364
 
362
365
  ### Configuration Options
package/docs/API.md CHANGED
@@ -456,12 +456,13 @@ Any other model works via its full `provider/model` slug (e.g. `anthropic/claude
456
456
 
457
457
  **Codex** is an agentic coding assistant with direct filesystem access:
458
458
 
459
- - **Model**: `codex` (underlying model: GPT-5.6)
459
+ - **Model**: `codex` (underlying model: GPT-6 Astra by default)
460
+ - **Backend selection**: `codex:<model>` per request (e.g. `codex:astra`, `codex:sol`, `codex:gpt-5.6-terra`), or `CODEX_MODEL` globally; unknown names pass through to the CLI verbatim
460
461
  - **Thread-based sessions**: persistent conversation history via `continuation_id` in `chat` mode
461
462
  - **Direct file access**: reads files from the working directory (paths relative to `CLIENT_CWD`)
462
463
  - **Response times**: 6-20 seconds typical (complex tasks may take minutes)
463
464
  - **Authentication**: ChatGPT login OR `CODEX_API_KEY` (NOT `OPENAI_API_KEY`)
464
- - `reasoning_effort` and web search are not applicable — Codex manages its own execution
465
+ - `reasoning_effort` is clamped onto the tiers the chosen backend accepts (GPT-6 Astra: `low`–`max`, no `none`; GPT-5.6: `none`–`max`); web search is not applicable — Codex manages its own execution
465
466
 
466
467
  ### Claude Agent SDK (subscription)
467
468
 
package/docs/PROVIDERS.md CHANGED
@@ -101,9 +101,11 @@ This guide documents all supported AI providers in the Converse MCP Server and t
101
101
  - `CODEX_SANDBOX_MODE` - Filesystem access control (default: read-only)
102
102
  - `CODEX_SKIP_GIT_CHECK` - Skip Git repository validation (default: true)
103
103
  - `CODEX_APPROVAL_POLICY` - Command approval behavior (default: never)
104
- - `CODEX_MODEL` - Underlying model for Codex sessions (default: gpt-5.6-sol; e.g. gpt-5.6-terra, gpt-5.6-luna, gpt-5.5)
104
+ - `CODEX_MODEL` - Underlying model for Codex sessions (default: gpt-6-astra; e.g. gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5)
105
105
  - **Supported Models**:
106
- - `codex` - OpenAI Codex agentic coding assistant (GPT-5.6 by default)
106
+ - `codex` - OpenAI Codex agentic coding assistant (GPT-6 Astra by default)
107
+ - `codex:<model>` - Same, with an explicit backend: `codex:astra`, `codex:sol`, `codex:terra`, `codex:luna`, `codex:gpt-5.5`, `codex:spark`, or any slug the Codex CLI knows
108
+ - `reasoning_effort` is clamped onto what the backend accepts (GPT-6 Astra: `low`–`max`, no `none`)
107
109
  - Thread-based sessions with persistent context
108
110
  - Direct filesystem access from working directory
109
111
  - Typical response time: 6-20 seconds (longer for complex tasks)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "converse-mcp-server",
3
- "version": "3.3.0",
3
+ "version": "3.4.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",
@@ -93,28 +93,28 @@
93
93
  ".env.example"
94
94
  ],
95
95
  "dependencies": {
96
- "@anthropic-ai/claude-agent-sdk": "^0.3.258",
96
+ "@anthropic-ai/claude-agent-sdk": "^0.3.261",
97
97
  "@anthropic-ai/sdk": "^0.123.0",
98
98
  "@github/copilot-sdk": "^1.0.11",
99
- "@google/genai": "^2.20.0",
99
+ "@google/genai": "^2.21.0",
100
100
  "@lydell/node-pty": "1.2.0-beta.15",
101
101
  "@mistralai/mistralai": "^2.6.4",
102
102
  "@modelcontextprotocol/sdk": "^1.30.0",
103
- "@openai/codex-sdk": "^0.152.1",
103
+ "@openai/codex-sdk": "^0.153.3",
104
104
  "cors": "^2.8.6",
105
105
  "dotenv": "^17.4.2",
106
106
  "express": "^5.2.1",
107
107
  "lru-cache": "^11.5.2",
108
108
  "nanoid": "^6.0.1",
109
- "openai": "^7.9.0",
109
+ "openai": "^7.10.0",
110
110
  "p-limit": "^7.3.2",
111
111
  "vite": "^8.2.2"
112
112
  },
113
113
  "devDependencies": {
114
- "@vitest/coverage-v8": "^4.1.11",
114
+ "@vitest/coverage-v8": "^5.0.0",
115
115
  "cross-env": "^10.1.0",
116
- "eslint": "^10.9.1",
116
+ "eslint": "^10.10.0",
117
117
  "rimraf": "^6.1.3",
118
- "vitest": "^4.1.11"
118
+ "vitest": "^5.0.0"
119
119
  }
120
120
  }
package/src/config.js CHANGED
@@ -280,9 +280,9 @@ const CONFIG_SCHEMA = {
280
280
  },
281
281
  CODEX_MODEL: {
282
282
  type: 'string',
283
- default: 'gpt-5.6-sol',
283
+ default: 'gpt-6-astra',
284
284
  description:
285
- 'Default Codex model (e.g., gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5)',
285
+ 'Default Codex backend model (e.g., gpt-6-astra, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5)',
286
286
  },
287
287
 
288
288
  // Copilot configuration
@@ -17,35 +17,75 @@ import { debugLog, debugError } from '../utils/console.js';
17
17
  import { ProviderError, ErrorCodes, StopReasons } from './interface.js';
18
18
  import { normalizeExtendedPath } from '../utils/pathUtils.js';
19
19
 
20
- // Supported Codex models with their configurations
20
+ /**
21
+ * Every Codex reasoning tier, weakest to strongest. Used to clamp a requested
22
+ * tier onto the set a given backend model accepts.
23
+ *
24
+ * Codex also exposes 'ultra' above 'max', but that tier turns on automatic
25
+ * sub-agent delegation — a change in how the run executes, not just how deep
26
+ * it reasons — so nothing at the tool level maps to it and it is kept off the
27
+ * ladder so the clamp can never select it.
28
+ */
29
+ const EFFORT_LADDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
30
+
31
+ /**
32
+ * Backend models Codex can run, keyed by the slug passed to the CLI as
33
+ * --model. The reasoning tiers are the ones each model's API accepts, verified
34
+ * against the API's own rejection messages (gpt-6-astra: "Supported values
35
+ * are: 'low', 'medium', 'high', 'xhigh', and 'max'"). The SDK's
36
+ * ModelReasoningEffort type is the union across models, so the backend is the
37
+ * authority and requests are clamped per model.
38
+ */
39
+ const CODEX_BACKEND_MODELS = {
40
+ 'gpt-6-astra': {
41
+ aliases: ['astra', 'gpt-6', 'gpt6', 'gpt6-astra'],
42
+ contextWindow: 272000,
43
+ supportedEfforts: ['low', 'medium', 'high', 'xhigh', 'max'],
44
+ },
45
+ 'gpt-5.6-sol': {
46
+ aliases: ['sol', 'gpt-5.6', 'gpt5.6', 'gpt-5.6-codex'],
47
+ contextWindow: 272000,
48
+ supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
49
+ },
50
+ 'gpt-5.6-terra': {
51
+ aliases: ['terra'],
52
+ contextWindow: 272000,
53
+ supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
54
+ },
55
+ 'gpt-5.6-luna': {
56
+ aliases: ['luna'],
57
+ contextWindow: 272000,
58
+ supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh', 'max'],
59
+ },
60
+ 'gpt-5.5': {
61
+ aliases: ['gpt5.5'],
62
+ contextWindow: 272000,
63
+ supportedEfforts: ['low', 'medium', 'high', 'xhigh'],
64
+ },
65
+ 'gpt-5.3-codex-spark': {
66
+ aliases: ['spark', 'codex-spark'],
67
+ contextWindow: 128000,
68
+ supportedEfforts: ['low', 'medium', 'high', 'xhigh'],
69
+ },
70
+ };
71
+
72
+ const DEFAULT_BACKEND_MODEL = 'gpt-6-astra';
73
+
74
+ // The single user-facing model the router exposes. The backend model behind it
75
+ // comes from CODEX_MODEL, or from a `codex:<model>` spec.
21
76
  const SUPPORTED_MODELS = {
22
77
  codex: {
23
78
  modelName: 'codex',
24
- friendlyName: 'OpenAI Codex (GPT-5.6)',
25
- contextWindow: 400000,
79
+ friendlyName: 'OpenAI Codex (GPT-6 Astra)',
80
+ contextWindow: CODEX_BACKEND_MODELS[DEFAULT_BACKEND_MODEL].contextWindow,
26
81
  maxOutputTokens: 128000,
27
82
  supportsStreaming: true,
28
83
  supportsImages: true, // Codex SDK 0.118+ supports images via --image (local_image input)
29
84
  supportsWebSearch: false, // Codex accesses files directly, not web
30
- // Reasoning tiers this model's backend actually accepts. GPT-5.6 dropped
31
- // 'minimal' and added 'none', while the SDK's ModelReasoningEffort type
32
- // still advertises the pre-5.6 set — the backend is the authority, so the
33
- // accepted tiers are declared per model and requests are clamped onto them.
34
- supportedEfforts: ['none', 'low', 'medium', 'high', 'xhigh'],
35
85
  timeout: 1800000, // 30 minutes
36
86
  description:
37
- 'OpenAI Codex agentic coding assistant with local file access and tool execution (GPT-5.6)',
38
- aliases: [
39
- 'gpt-5-codex',
40
- 'gpt5-codex',
41
- 'gpt-5.2-codex',
42
- 'gpt-5.3-codex',
43
- 'gpt5.3-codex',
44
- 'gpt-5.5',
45
- 'gpt5.5',
46
- 'gpt-5.6-codex',
47
- 'gpt5.6-codex',
48
- ],
87
+ 'OpenAI Codex agentic coding assistant with local file access and tool execution (GPT-6 Astra by default; pick another backend with codex:<model> or CODEX_MODEL)',
88
+ aliases: [],
49
89
  },
50
90
  };
51
91
 
@@ -195,6 +235,57 @@ function extractPromptText(input) {
195
235
  .join('\n\n');
196
236
  }
197
237
 
238
+ /**
239
+ * Resolve a backend slug or alias (case-insensitive) to its catalog slug.
240
+ * @param {string} name
241
+ * @returns {string|null}
242
+ */
243
+ function findBackendSlug(name) {
244
+ const lower = String(name || '').trim().toLowerCase();
245
+ if (!lower) {
246
+ return null;
247
+ }
248
+ if (CODEX_BACKEND_MODELS[lower]) {
249
+ return lower;
250
+ }
251
+ return (
252
+ Object.keys(CODEX_BACKEND_MODELS).find((slug) =>
253
+ CODEX_BACKEND_MODELS[slug].aliases.includes(lower),
254
+ ) || null
255
+ );
256
+ }
257
+
258
+ /**
259
+ * Catalog entry for a backend model, or null when the slug is not catalogued.
260
+ * @param {string} name - Backend slug or alias
261
+ * @returns {{ slug: string, aliases: string[], contextWindow: number, supportedEfforts: string[] }|null}
262
+ */
263
+ export function getBackendModelConfig(name) {
264
+ const slug = findBackendSlug(name);
265
+ return slug ? { slug, ...CODEX_BACKEND_MODELS[slug] } : null;
266
+ }
267
+
268
+ /**
269
+ * Resolve the requested model spec to the backend slug passed to the CLI.
270
+ *
271
+ * `codex` uses CODEX_MODEL (default gpt-6-astra); `codex:<model>` names a
272
+ * backend directly, by slug or alias. Unknown names pass through verbatim so a
273
+ * newly released model works before it is catalogued here — the CLI rejects
274
+ * anything the backend does not know.
275
+ *
276
+ * @param {string} spec - Requested model, e.g. 'codex' or 'codex:sol'
277
+ * @param {Object} [config] - Loaded configuration
278
+ * @returns {string} Backend slug for the SDK's `model` option
279
+ */
280
+ export function resolveBackendModel(spec, config) {
281
+ const raw = String(spec || '').trim();
282
+ const requested = raw.toLowerCase().startsWith('codex:')
283
+ ? raw.slice('codex:'.length).trim()
284
+ : '';
285
+ const name = requested || config?.providers?.codexmodel || DEFAULT_BACKEND_MODEL;
286
+ return findBackendSlug(name) || name;
287
+ }
288
+
198
289
  /**
199
290
  * Get thread ID from continuation metadata.
200
291
  * Codex thread IDs are stored per call-plan in `providerThreads`, keyed by a
@@ -216,12 +307,6 @@ async function getThreadIdFromContinuation(
216
307
  }
217
308
  }
218
309
 
219
- /**
220
- * Every Codex reasoning tier, weakest to strongest. Used to clamp a requested
221
- * tier onto the set a given model actually accepts.
222
- */
223
- const EFFORT_LADDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh'];
224
-
225
310
  /**
226
311
  * Tool-level reasoning_effort values translated to their Codex equivalent.
227
312
  * Tool enum: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'max'
@@ -232,7 +317,7 @@ const EFFORT_ALIASES = {
232
317
  low: 'low',
233
318
  medium: 'medium',
234
319
  high: 'high',
235
- max: 'xhigh',
320
+ max: 'max',
236
321
  };
237
322
 
238
323
  /**
@@ -403,8 +488,9 @@ export const codexProvider = {
403
488
  const approvalPolicy = config.providers?.codexapprovalpolicy || 'never';
404
489
 
405
490
  // Create or resume thread
491
+ const backendModel = resolveBackendModel(model, config);
406
492
  const threadOptions = {
407
- model: config.providers?.codexmodel,
493
+ model: backendModel,
408
494
  workingDirectory,
409
495
  sandboxMode,
410
496
  skipGitRepoCheck,
@@ -413,13 +499,12 @@ export const codexProvider = {
413
499
 
414
500
  if (reasoning_effort) {
415
501
  const supportedEfforts =
416
- findModelConfig(model)?.supportedEfforts ||
417
- SUPPORTED_MODELS.codex.supportedEfforts;
502
+ getBackendModelConfig(backendModel)?.supportedEfforts || EFFORT_LADDER;
418
503
  const mappedEffort = mapReasoningEffort(reasoning_effort, supportedEfforts);
419
504
  threadOptions.modelReasoningEffort = mappedEffort;
420
505
  if (mappedEffort !== EFFORT_ALIASES[reasoning_effort]) {
421
506
  debugLog(
422
- `[Codex] reasoning_effort "${reasoning_effort}" not supported by ${model} — using "${mappedEffort}"`,
507
+ `[Codex] reasoning_effort "${reasoning_effort}" not supported by ${backendModel} — using "${mappedEffort}"`,
423
508
  );
424
509
  }
425
510
  }
@@ -470,6 +555,7 @@ export const codexProvider = {
470
555
  metadata: {
471
556
  provider: 'codex',
472
557
  model,
558
+ backendModel,
473
559
  threadId: threadIdFromStream || thread.id,
474
560
  usage: usage
475
561
  ? {
@@ -138,9 +138,10 @@ function classifyModelSpec(spec, providers) {
138
138
  }
139
139
 
140
140
  // Other explicit namespaces pass the spec through unchanged; the target
141
- // provider strips its own prefix (preserves current copilot/claude/gemini-cli
141
+ // provider strips its own prefix (preserves current codex/copilot/claude/gemini-cli
142
142
  // behavior).
143
143
  if (
144
+ lower.startsWith('codex:') ||
144
145
  lower.startsWith('copilot:') ||
145
146
  lower.startsWith('claude:') ||
146
147
  lower.startsWith('gemini:')
@@ -308,8 +309,9 @@ export function mapModelToProvider(model, providers) {
308
309
  return 'openai';
309
310
  }
310
311
 
311
- // Check Codex (exact match only - don't route "gpt-5-codex" etc to Codex provider)
312
- if (modelLower === 'codex') {
312
+ // Check Codex: bare `codex` or the `codex:<backend>` namespace (e.g. codex:astra,
313
+ // codex:gpt-5.6-sol). Bare "gpt-*" names never route here — they are OpenAI API models.
314
+ if (modelLower === 'codex' || modelLower.startsWith('codex:')) {
313
315
  return 'codex';
314
316
  }
315
317