Skip to content

fix: support Streamable HTTP MCP servers for Codex CLI (closes #1260)#1262

Open
masaishi wants to merge 10 commits into
microsoft:mainfrom
masaishi:fix/codex-streamable-http-mcp
Open

fix: support Streamable HTTP MCP servers for Codex CLI (closes #1260)#1262
masaishi wants to merge 10 commits into
microsoft:mainfrom
masaishi:fix/codex-streamable-http-mcp

Conversation

@masaishi
Copy link
Copy Markdown

@masaishi masaishi commented May 11, 2026

Description

Codex CLI supports Streamable HTTP MCP servers, but apm install was skipping Codex for every remote MCP entry, and README.md documented this as intended behavior.

This PR aligns the Codex adapter with the official Codex MCP spec:

  • Emit Streamable HTTP remote MCPs to ~/.codex/config.toml as mcp_servers.<name> entries with url = "..." (and http_headers when provided).
  • Keep SSE skipped, but update the notice to point users to transport: streamable-http (SSE is deprecated by the MCP spec and absent from the Codex config schema).
  • Extend the conflict detector to recognize flat-key mcp_servers.<name> entries that use url (previously only command / args were matched).
  • Remove the misleading “Codex CLI does not support remote MCP servers” line from README.md.

Fixes #1260

Type of change

  • Bug fix
  • Documentation
  • Maintenance / refactor

Testing

  • Tested locally

  • All existing tests pass

  • Added tests for new functionality (if applicable)

    • Streamable HTTP server config generation and SSE-skip behavior in test_mcp_client_factory.py
    • Codex flat-key remote URL detection in test_conflict_detection.py
    • Streamable-HTTP self-defined transport handling in _build_self_defined_info (test_mcp_integrator.py)

Copilot AI review requested due to automatic review settings May 11, 2026 01:45
@masaishi
Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Codex CLI adapter so apm install can emit Streamable HTTP (remote) MCP server entries into Codex config.toml, while continuing to skip SSE remotes with an updated warning message. It also expands conflict detection to recognize Codex TOML “flat-key” server entries that are configured via url, and removes a README statement claiming Codex cannot use remote MCP servers.

Changes:

  • Codex adapter: generate mcp_servers.<name> TOML entries for remote streamable-http MCP servers (including http_headers), and skip SSE remotes via formatter signaling.
  • Conflict detector: treat mcp_servers.<name> flat-key configs containing url as existing servers (not just command/args).
  • Tests + README: add unit coverage for streamable-http + conflict detection, and remove misleading README wording about Codex remote MCP support.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/apm_cli/adapters/client/codex.py Adds remote Streamable HTTP config emission for Codex and SSE-skip path via _format_server_config() returning None.
src/apm_cli/core/conflict_detector.py Extends Codex flat-key server detection to include url-based configs.
tests/unit/test_mcp_client_factory.py Updates SSE skip test to assert _rich_warning content; adds streamable-http formatting + install tests.
tests/unit/test_conflict_detection.py Adds coverage for detecting Codex flat-key remote url entries.
tests/unit/integration/test_mcp_integrator.py Adds coverage ensuring self-defined streamable-http builds a remotes entry.
README.md Removes the statement that Codex CLI does not support remote MCP servers.

Comment on lines +223 to +227
remote = self._select_remote_with_url(remotes) or remotes[0]
server_name = server_info.get("name", "")
if (remote.get("transport_type") or "").strip() == "sse":
_rich_warning(
f"Skipping MCP server '{server_name}' for Codex CLI: SSE transport "
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

APM always builds a single-element remotes list (mcp_integrator.py:216: info["remotes"] = [remote]), so the proposed “first SSE, later streamable-http” scenario cannot occur.

Additionally, the _select_remote_with_url(remotes) or remotes[0] pattern is already identical across the other adapters:

  • copilot.py:541
  • gemini.py:131
  • vscode.py:362

The recommendation to “mirror the other adapters’ validation” is therefore self-defeating, because the referenced implementations use the exact same logic.

Comment on lines +234 to +237
remote_config = {
"url": (remote.get("url") or "").strip(),
"id": server_info.get("id", ""),
}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

codex.py:617-627’s _select_remote_with_url contractually never returns a remote with an empty URL.

Writing id as an empty string is intentional and consistent with copilot.py:565. This follows the conflict_detector schema convention (introduced in commit 6a44d74).

Omitting the key would break conflict detection behavior.

Comment on lines 172 to +177
# Generate server configuration with environment variable resolution
server_config = self._format_server_config(server_info, env_overrides, runtime_vars)

# Skip if formatter signaled "unsupported" (e.g. SSE remote on Codex)
if server_config is None:
return False
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fix it
1a75308

Comment on lines +297 to +301
"headers": [
{"name": "Authorization", "value": "Bearer ghp_xxx"},
{"name": "X-Figma-Region", "value": "us-east-1"},
],
}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

GitHub’s PAT format requires:

ghp_ + 36 alphanumeric characters

@danielmeppiel danielmeppiel added panel-review Trigger the apm-review-panel gh-aw workflow and removed panel-review Trigger the apm-review-panel gh-aw workflow labels May 14, 2026
@github-actions
Copy link
Copy Markdown

APM Review Panel: needs_rework

Codex adapter now speaks streamable-HTTP remote MCP -- real capability unlock, one concrete security gap (non-HTTPS URL write) must close before merge.

cc @danielmeppiel -- a fresh advisory pass is ready for your review.

This PR delivers the last adapter in the harness matrix for remote MCP transport: Codex users can now run apm install --mcp <server> --transport http and reach any hosted MCP endpoint (Figma, GitHub MCP, etc.) without manual TOML surgery. The OSS story -- "one command, any harness, any transport" -- is now structurally true. That is a meaningful milestone worth shipping.

The panel converged on one concrete blocker (supply-chain-security) and two reinforcing recommended findings that share a root cause. The blocker is real: the url field from the registry is written verbatim to config.toml with no scheme validation. A compromised or typosquatted registry entry can write (attacker.com/redacted) (redacted) or a localhost SSRF pivot URL to a file Codex reads at runtime. The fix is a single guard (if not url.startswith('https://'): raise ValueError) that closes the persistent write vector before any network request is made. This must land before merge -- the capability is useless if a user can be silently redirected to a plaintext endpoint. Auth-expert and supply-chain-security converged independently on the resolved-token disclosure gap: if the registry supplies a static Authorization: Bearer ghp_xxxx header, the resolved value is written to TOML with no user-facing disclosure. This is not a blocker -- it is a recommended pre-merge hardening -- but given the convergence from two distinct lenses it should be treated as near-blocking and paired with the URL guard in the same diff.

The remaining panel signal decomposes into two tiers. Tier 1 (in-PR): DevX and CLI-logging both flag a silent happy path -- the streamable-HTTP success branch emits a bare print() while the SSE deprecation branch fires _rich_warning. This is a one-line fix that belongs in this PR. The empty-URL fallback (test-coverage + devx convergence) writes url='' to TOML and returns True; a guard here is also a one-liner. Tier 2 (follow-up): doc drift on targets-matrix.md and install-mcp-servers.md, the missing CHANGELOG entry, the remotes+packages silent precedence, and the missing GitHub-server detection parity with Cursor can all ship post-merge as standalone issues.

Dissent. No material disagreement between panelists. Python-architect and devx-ux both flagged the remotes+packages silent fallthrough; python-architect called it recommended, devx called it a nit. CEO weights it as recommended -- a precedence rule with a comment is cheap and the silent ignore of a remote endpoint is surprising. This does not affect the ship stance.

Aligned with: Portable by manifest (apm.yml transport field now routes correctly for all four harnesses; Codex remote MCP is no longer a manual exception); Secure by default (FAILS on this PR as submitted -- non-HTTPS URLs from the registry are written to disk without validation, must be fixed before merge); Governed by policy (conflict detection updated to handle url-keyed entries; id='' empty-string fallback is a minor gap); Multi-harness / multi-host (Codex joins Copilot, Claude, and Cursor on streamable-HTTP, completing the matrix); OSS community driven (disclaimer removal removes friction for Codex-primary contributors; CHANGELOG entry still missing); Pragmatic as npm (SSE deprecation warning with a migration message is exactly the right pattern: clear, actionable, no silent breakage).

Growth signal. The oss-growth-hacker correctly identified the angle: "One command installs Figma MCP into every agent -- Copilot, Claude, Cursor, and now Codex." Once the URL guard and token disclosure warning land, this PR earns a CHANGELOG entry and a short launch post. The SSE deprecation message also positions APM as the authoritative migration guide for the MCP transport transition -- worth mirroring in a docs FAQ so users who hit the warning can find it via search.

Panel summary

Persona B R N Takeaway
Python Architect 0 1 2 Solid feature addition; one correctness gap (remotes+packages silently falls through to package path) and a missing type hint are the main items. None-as-sentinel is acceptable at this scope but worth noting.
CLI Logging Expert 0 1 1 SSE warning migration is correct and well-formed; one recommended follow-up on the adjacent success path, one nit on symbol= consistency.
DevX UX Expert 0 2 2 Silent success on streamable-HTTP install and URL-less fallback are the two real gaps; SSE deprecation message is good; remotes+packages ambiguity is low risk but worth a nit.
Supply Chain Security Expert 1 2 1 No URL scheme validation lets a compromised registry write non-HTTPS/localhost URLs to Codex config; resolved auth tokens in http_headers land on disk without explicit user consent warning.
OSS Growth Hacker 0 2 2 Unblocking Codex remote-MCP is a genuine "works with" expansion worth amplifying, but the README silently removes the disclaimer instead of adding a positive claim -- a missed conversion moment.
Auth Expert 0 2 2 Resolved Authorization headers are written plaintext to config.toml with no user-facing disclosure; static registry tokens pass through verbatim; otherwise no credential-leak vectors found.
Doc Writer 0 2 2 README removal is accurate but purely subtractive; two doc pages have stale or incomplete Codex remote-MCP coverage that will mislead users trying --transport http with Codex.
Test Coverage Expert 0 1 1 TOML write/read round-trip is covered at fixture tier; two unit-tier gaps remain: all-empty-URL fallback silently writes url='' and unknown transport_type silently falls through to streamable-HTTP path.

B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.

Top 5 follow-ups

  1. [Supply Chain Security Expert] (blocking-severity) Enforce HTTPS-only scheme before writing url to Codex TOML; raise a hard error for any other scheme. -- A compromised registry entry can write (redacted) (redacted) or localhost URLs to a config file Codex reads at runtime. This is a persistent write vector with no mitigation today. Must close before merge.
  2. [Auth Expert] Emit an explicit named warning when a resolved Authorization / X-Api-Key header is about to be written to disk in plaintext. -- Auth-expert and supply-chain-security converged independently: static or fully-resolved tokens from the registry land in config.toml silently. Near-blocking given dual-lens convergence.
  3. [DevX UX Expert] Guard the empty-URL fallback: raise ValueError when every remote has an empty URL instead of writing url='' and returning True. -- Test-coverage-expert confirmed no test asserts this path. The silent write of url='' produces an unusable Codex config with a false-success return.
  4. [CLI Logging Expert] Replace bare print() on the streamable-HTTP success path with _rich_success(); add _rich_info() when remotes+packages silently routes to packages. -- The SSE path was just migrated to _rich_warning; the adjacent success branch still uses bare print(), breaking the traffic-light contract on the same code path.
  5. [OSS Growth Hacker] Add a CHANGELOG entry for the Codex + streamable-HTTP unlock and add an affirmative README line where the disclaimer was removed. -- The disclaimer removal is purely subtractive. A CHANGELOG bullet seeds external mentions and upgrade motivation; a positive README claim converts Codex users who scan before trusting --transport http.

Architecture

classDiagram
    direction LR
    class MCPClientAdapter {
        <<Abstract>>
        +target_name: str
        +mcp_servers_key: str
        +get_config_path() str
        +update_config(updates) bool
        +configure_mcp_server(...) bool
    }
    class CodexClientAdapter {
        <<ConcreteAdapter>>
        +configure_mcp_server(...) bool
        +_format_server_config(info, env, vars) dict | None
        +_select_remote_with_url(remotes) dict | None
        +_select_best_package(packages) dict
        +update_config(updates) bool
    }
    class CopilotClientAdapter {
        <<ConcreteAdapter>>
        +_format_server_config(info, env, vars) dict
    }
    class CursorClientAdapter {
        <<ConcreteAdapter>>
        +_format_server_config(info, env, vars) dict
    }
    class MCPConflictDetector {
        <<Collaborator>>
        +get_existing_server_configs() dict
    }
    class SimpleRegistryClient {
        <<Collaborator>>
        +find_server_by_reference(ref) dict
    }
    MCPClientAdapter <|-- CodexClientAdapter : extends
    MCPClientAdapter <|-- CopilotClientAdapter : extends
    MCPClientAdapter <|-- CursorClientAdapter : extends
    CodexClientAdapter *-- SimpleRegistryClient : owns
    CodexClientAdapter ..> MCPConflictDetector : reads via
    class CodexClientAdapter:::touched
    class MCPConflictDetector:::touched
    classDef touched fill:#fff3b0,stroke:#d47600
Loading
flowchart TD
    A(["apm install --transport http"]) --> B["configure_mcp_server()\ncodex.py:120"]
    B --> C{"server_info cached?"}
    C -- no --> D["[NET] registry_client.find_server_by_reference()"]
    C -- yes --> E["use cached server_info"]
    D --> E
    E --> F["resolve config_key from server_name / server_url"]
    F --> G["_format_server_config(server_info, env, vars)\ncodex.py:190"]
    G --> H{"_raw_stdio present?"}
    H -- yes --> I["return stdio config dict"]
    H -- no --> J{"remotes and NOT packages?"}
    J -- no --> K{"packages empty?"}
    K -- yes --> L["raise ValueError (incomplete config)"]
    K -- no --> M["_select_best_package() -> package dict"]
    M --> N["build command/args/env config"]
    N --> I
    J -- yes --> O["_select_remote_with_url(remotes)"]
    O --> P{"transport_type == 'sse'?"}
    P -- yes --> Q["_rich_warning() + return None"]
    P -- no --> R["build {url, id} remote_config"]
    R --> S{"headers present?"}
    S -- yes --> T["_resolve_variable_placeholders() for each header"]
    T --> U["remote_config['http_headers'] = headers"]
    S -- no --> V["return remote_config"]
    U --> V
    G --> W{"result is None?"}
    I --> W
    Q --> W
    V --> W
    W -- yes --> X["return False (skip, warning already emitted)"]
    W -- no --> Y["[FS] update_config({config_key: server_config})\nwrites .codex/config.toml"]
    Y --> Z["[I/O] MCPConflictDetector reads url/command/args keys\nconflict_detector.py:118-120"]
    Z --> AA(["return True"])
Loading

Recommendation

Hold for the HTTPS scheme guard (supply-chain-security blocking finding) and pair it with the auth-disclosure warning (auth-expert + supply-chain-security convergence). Both are small diffs -- likely a single function and a one-line pre-write check. Once those two land, the empty-URL guard and the bare-print fix (each a one-liner) should come along in the same revision since they are already identified and trivially cheap. With those four items in the diff, this PR is clean to merge and the follow-up issue queue (doc updates, CHANGELOG, GitHub-server parity, remotes+packages comment) can be tracked as a post-merge milestone.


Full per-persona findings

Python Architect

  • [recommended] Mixed remotes+packages server silently ignores the streamable-HTTP remote and installs as stdio at src/apm_cli/adapters/client/codex.py:222
    The guard if remotes and not packages only enters the remote-config branch when there are no packages. A server that ships both a remote endpoint and a package falls through to the package path without any warning. If the operator intended a streamable-HTTP connection, they will silently get a local install instead.
    Suggested: Add a precedence rule with a comment, or add _rich_warning when falling through to packages path when remotes also exists.

  • [nit] _select_remote_with_url lacks a type annotation on its return value at src/apm_cli/adapters/client/codex.py:616
    The docstring says dict or None but no -> dict | None hint is present. All other helpers on this class carry return-type hints.
    Suggested: def _select_remote_with_url(remotes: list[dict]) -> dict | None:

  • [nit] None-as-sentinel from _format_server_config diverges from other adapters which return {} for skip
    Copilot and Cursor return {} (empty dict) as the nothing-to-do signal; Codex now returns None for the SSE case. Two conventions for the same concept in one inheritance tree.
    Suggested: Add a one-line docstring note to MCPClientAdapter._format_server_config clarifying the sentinel contract.

CLI Logging Expert

  • [recommended] Streamable-HTTP success path still uses bare print() immediately after the changed block at src/apm_cli/adapters/client/codex.py
    The SSE path was just migrated to _rich_warning, but the success branch directly below it is left with a bare print(). A user installing a streamable-HTTP server sees uncolored, un-symbolled output while a warning fires in yellow with [!]. This breaks the traffic-light contract for the same code path.
    Suggested: Replace print(f"Successfully configured MCP server '{config_key}' for Codex CLI") with _rich_success(...).

  • [nit] symbol="warning" is valid but inconsistent with sibling adapters
    Every other _rich_warning call in vscode.py, copilot.py, and claude.py omits symbol= entirely.
    Suggested: Either adopt symbol="warning" across all _rich_warning call sites or drop it here to match the majority pattern.

DevX UX Expert

  • [recommended] Silent success: no confirmation emitted after streamable-HTTP install at src/apm_cli/adapters/client/codex.py
    After _format_server_config returns remote_config and update_config succeeds, nothing tells the user the server was installed. Running apm install --mcp server --transport http produces no output on the happy path -- indistinguishable from a silent skip.
    Suggested: Emit _rich_success(f"MCP server '{server_name}' installed for Codex CLI (streamable-http).").

  • [recommended] Empty-URL fallback: remotes[0] with no URL silently produces a broken config at src/apm_cli/adapters/client/codex.py
    When every remote lacks a URL, _select_remote_with_url returns None and falls back to remotes[0], writing url='' to Codex TOML. configure_mcp_server returns True but the entry is unusable.
    Suggested: if not (remote.get('url') or '').strip(): raise ValueError(f"MCP server '{server_name}' has no usable URL for streamable-http transport.")

  • [nit] remotes+packages case silently routes to packages-only without acknowledgment
    Suggested: Add _rich_info(f"MCP server '{server_name}' has both remote and package variants; using local package for Codex CLI.").

  • [nit] SSE deprecation warning missing the corrected command
    Suggested: Append Run: apm install --mcp <server> --transport streamable-http to the warning string.

Supply Chain Security Expert

  • [blocking] No URL scheme validation -- registry can inject (redacted) (redacted) or localhost URLs at src/apm_cli/adapters/client/codex.py:235
    The url field is taken directly from the registry response and only stripped before being written to Codex's TOML config. No scheme allow-list, no localhost/loopback block, no HTTPS enforcement. A compromised registry entry can supply (attacker.com/redacted) (MITM), (redacted) or (127.0.0.1/redacted) (SSRF). The attack is persistent -- written to a file Codex reads at runtime. *Suggested:* if not url.startswith('https://'): raise ValueError(f'Remote MCP URL must use HTTPS: {url}')`

  • [recommended] Resolved auth tokens written to disk config without explicit user disclosure at src/apm_cli/adapters/client/codex.py:246-248
    _warn_input_variables only fires for unresolved \$\{input:...} placeholders. Fully-resolved Authorization: Bearer (token) values are written to TOML silently.
    Suggested: Add a check for headers matching Authorization/X-Api-Key and emit an explicit warning naming the config path.

  • [recommended] Empty-string fallback for id silently breaks UUID-based conflict detection at src/apm_cli/adapters/client/codex.py:236
    server_info.get('id', '') falls back to empty string. The conflict detector then matches any other server whose id is also '' -- false-positive conflict blocks.
    Suggested: Skip writing the id key when the value is falsy.

  • [nit] Conflict detector url heuristic could match non-MCP TOML entries at src/apm_cli/core/conflict_detector.py:119

OSS Growth Hacker

  • [recommended] README removes limitation but adds no positive claim about what is now supported at README.md
    Suggested: Add an affirmative line near the Codex install example.

  • [recommended] No CHANGELOG entry for this capability unlock at CHANGELOG.md
    Suggested: "Codex CLI now supports streamable-HTTP remote MCP servers; --transport http no longer skips Codex."

  • [nit] SSE deprecation warning should be mirrored in docs FAQ.

  • [nit] Works-with section could note all clients support both local and hosted MCP transports.

Auth Expert

  • [recommended] No disclosure to user that resolved Authorization headers are persisted in plaintext at src/apm_cli/adapters/client/codex.py
    _warn_input_variables fires only for unresolved placeholders -- silent when the token is fully resolved.

  • [recommended] Static tokens from registry entries are written verbatim with no warning
    _resolve_variable_placeholders passes values through unchanged when they contain no placeholder. A cheap regex check on resolved header values would catch raw tokens (ghp_, github_pat_, etc.).

  • [nit] No GitHub-server detection unlike Cursor adapter
    Cursor injects a live token from GitHubTokenManager and refuses registry-supplied Authorization overrides. Codex has no equivalent.

  • [nit] No credential-leak via logs -- confirmed clean. _log.debug logs only the file path; no resolved token value surfaces in output.

Doc Writer

  • [recommended] install-mcp-servers.md token injection section does not mention Codex adapter at docs/src/content/docs/consumer/install-mcp-servers.md
    The section scopes automatic Authorization: Bearer injection to "Copilot CLI adapter" only. Users installing GitHub MCP against Codex with --transport http have no guidance on whether token injection applies.

  • [recommended] targets-matrix.md Codex section does not list supported MCP transport types at docs/src/content/docs/reference/targets-matrix.md
    With --transport http now working for Codex, the section is materially incomplete.
    Suggested: Add: "MCP transports. stdio and streamable-http (remote). See Install MCP servers for transport selection."

  • [nit] README removes limitation note but adds no positive replacement.

  • [nit] No documentation captures SSE-to-streamable-http migration path.

Test Coverage Expert

  • [recommended] _select_remote_with_url all-empty-URL fallback writes url='' to TOML with no test asserting the outcome at tests/unit/test_mcp_client_factory.py
    When every remote has an empty URL, the fallback path writes url='' to the Codex TOML and returns True. Confirmed missing via grep.
    Proof (missing at unit): tests/unit/test_mcp_client_factory.py::test_configure_mcp_server_all_remotes_have_empty_url -- proves: apm install of a remote-only server with no resolvable URL either fails loudly or writes a non-empty url [devx, secure-by-default]

  • [nit] Unknown transport_type (e.g. "websocket") silently falls through to streamable-HTTP path with no test
    Proof (missing at unit): tests/unit/test_mcp_client_factory.py::test_format_server_config_unknown_transport_treated_as_streamable_http -- proves: unrecognised transport_type produces a known, documented outcome [devx]

This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.

Note

🔒 Integrity filter blocked 2 items

The following items were blocked because they don't meet the GitHub integrity level.

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

Generated by PR Review Panel for issue #1262 · ● 3.3M ·

@github-actions github-actions Bot removed the panel-review Trigger the apm-review-panel gh-aw workflow label May 14, 2026
@danielmeppiel
Copy link
Copy Markdown
Collaborator

Maintainer sweep [2026-05-15]: panel still needs_rework. The single remaining blocker is the non-HTTPS URL write in the Codex Streamable HTTP path -- the supply-chain-security persona flagged this and it must close before merge. @masaishi, your response thread shows engagement; can you confirm whether the latest push enforces HTTPS-only at the URL-validation gate (with a test) so I can re-run the panel? Everything else looks landable.

@masaishi
Copy link
Copy Markdown
Author

@danielmeppiel
Thanks for checking! You're absolutely right — this was still missing. I addressed it in commit 9caa34c by enforcing HTTPS-only validation at the URL validation gate and adding test coverage for the behavior.

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

Labels

status/triaged Initial agentic triage complete; pending maintainer ratification (silence = approval).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Codex CLI skips Streamable HTTP MCP servers; README claims this is unsupported

4 participants