Skip to content

Fix Codex initialize compatibility in the CLI bridge - #261

Merged
mattt merged 2 commits into
mattt:mainfrom
barissglc:fix/codex-initialize-capability
Oct 7, 2026
Merged

mattt merged 2 commits into
mattt:mainfrom
barissglc:fix/codex-initialize-capability

Conversation

@barissglc

@barissglc barissglc commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Codex 0.160.0 sends an object-valued codex/auth-change capability during MCP initialization. The Swift MCP SDK 0.12.0 pinned by iMCP decodes experimental capabilities as strings, so the original bridge returns -32603 and Codex cannot discover tools. A simpler client handshake can still succeed, which makes this look like a chat-routing problem.

This adds a narrow compatibility workaround to imcp-server: assemble complete newline-delimited stdin frames and remove only the unsupported object-valued params.capabilities.experimental["codex/auth-change"] entry from initialize requests. Normalized initialization uses .sortedKeys so repeated calls emit identical bytes. Client identity, other capabilities and subsequent requests are preserved. Oversized frames terminate the proxy instead of triggering the reconnect loop.

Closes #258.

Validation

  • imcp-serverTests: 26 tests passed in each of 10 separately relaunched test processes (260 executions, zero failures), including 11 new compatibility/framing regression tests.
  • Strict Swift formatting passed for all 44 repository Swift files, including the new files.
  • Project file syntax and git diff --check passed.

The 1.6.2 local installation was also verified end to end: the original bridge failed the Codex-shaped initialize request, the patched bridge listed 19 tools, and a real public-place maps_search succeeded in Tinycast's Codex chat route. This PR is rebased onto current main (8d232819, iMCP 1.6.3). It does not replace the original iMCP GUI or alter connection approvals, macOS permissions, Codex configuration or Tinycast configuration.

Scope

This is an interim Codex-specific workaround, not a general decoder fix for arbitrary experimental capabilities. The SDK-level issue is tracked in swift-sdk #287. An upstream SDK correction and subsequent dependency update remain the long-term solution. Validation was performed with Xcode 27 locally; the repository's Xcode 26 CI is a separate check.

Deterministic-output regression verification

Before the .sortedKeys change, the two reported framing tests ran five times in separately relaunched processes: 4 of 10 test executions failed. With the change, all 26 tests passed in each of 10 separately relaunched processes. The new canonical-output regression additionally checks the full normalized JSON bytes 100 times per process (1,000 comparisons total), without deriving its expected output from another normalization call.

@mattt
mattt requested a balanced review from Copilot October 7, 2026 11:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The workaround is narrowly scoped, preserves unrelated traffic, and has comprehensive regression coverage.

Review effort: Balanced
Findings: None

What changed in this PR

Adds a focused CLI compatibility workaround for Codex initialization while preserving standard MCP traffic.

Changes:

  • Buffers complete newline-delimited stdin frames with a 10 MiB limit.
  • Removes only Codex’s unsupported object-valued capability.
  • Adds regression coverage and terminates on oversized frames.
File Description
CLI/​MCPInitializeCompatibility.swift Implements normalization and framing.
CLI/​StdioProxy.swift Forwards complete normalized frames.
CLI/​MCPServiceLoop.swift Terminates after framing failures.
CLITests/​MCPInitializeCompatibilityTests.swift Covers normalization, framing, and size limits.
iMCP.xcodeproj/​project.pbxproj Adds compatibility tests to the test target.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@mattt

mattt commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Thanks for opening this PR, @barissglc! When I ran the tests locally, testFragmentedInitializeIsNormalizedOnceComplete and testBatchedRequestsPreserveOrderAndOtherBytes failed in three of four runs. JSONSerialization doesn't keep the same key order from one call to the next, so two calls to normalize with the same input can return different bytes. Passing options: [.sortedKeys] in normalize fixed it for me (five of five runs). Could you make that change?

@barissglc

Copy link
Copy Markdown
Contributor Author

Thanks for catching this, @mattt! Fixed in 23382cb by adding options: [.sortedKeys]. I also added a regression test for stable output.

I reproduced the issue before the fix: 4 of 10 executions of the two reported tests failed. After the change, all 26 tests passed in each of 10 separately relaunched test processes (260 executions, zero failures). The PR is updated.

@mattt
mattt requested a balanced review from Copilot October 7, 2026 17:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The workaround is narrowly scoped, preserves unrelated traffic, and has comprehensive regression coverage.

0 open findings

🧠 Review effort: Balanced

@mattt
mattt merged commit 51a432f into mattt:main Oct 7, 2026
1 check passed
@mattt

mattt commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Thanks for the fix, and for adding the regression test, @barissglc! This is now available in 1.6.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex initialize fails on object-valued experimental capability (Swift SDK 0.12.0)

3 participants