Skip to content

fix(gateway): support Streamable HTTP MCP transport on loopback server#89851

Merged
shakkernerd merged 9 commits into
openclaw:mainfrom
anagnorisis2peripeteia:fix/mcp-streamable-http
Jun 9, 2026
Merged

fix(gateway): support Streamable HTTP MCP transport on loopback server#89851
shakkernerd merged 9 commits into
openclaw:mainfrom
anagnorisis2peripeteia:fix/mcp-streamable-http

Conversation

@anagnorisis2peripeteia

@anagnorisis2peripeteia anagnorisis2peripeteia commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

The MCP loopback HTTP server generates a config with "type": "http" (Streamable HTTP transport), but only handled POST — a GET to /mcp returned 405. Claude Code's Streamable HTTP client opens an SSE notification channel by sending GET /mcp during initialization; the 405 left it hanging at "still connecting" indefinitely, so the agent got no OpenClaw MCP tools for the whole session.

This adds the missing transport surface, kept stateless (the loopback server owns no session lifecycle):

  • GET /mcp → 200 text/event-stream — an auth-gated, browser-origin-rejected idle SSE notification channel (the actual fix for the hang). Closes cleanly when the client disconnects.
  • DELETE /mcp → 200 — auth-gated no-op acknowledgement of Streamable HTTP session teardown, so clients that send DELETE on close get a clean 200 rather than 405.
  • Stateless POST — POST responses advertise no Mcp-Session-Id. The server processes each request independently; advertising a session id it never validates, expires, or owns would be misleading and push clients to echo a session the server ignores. (Per the spec, a stateless server simply omits the session id.)
  • Allow now advertises GET, POST, DELETE; other methods still 405.

Session semantics

Resolved the stateless-vs-sessionful question in favor of stateless: a single-purpose local loopback tool endpoint has no session state to manage, so it stays stateless rather than taking on a session lifecycle. (Maintainer can revisit if sessionful semantics are ever wanted.)

Tests

src/gateway/mcp-http.test.ts — added focused gateway transport tests, all passing:

  • GET valid bearer → 200 + text/event-stream
  • GET no auth → 401; GET browser Origin → 403
  • DELETE valid bearer → 200; DELETE no auth → 401
  • unsupported method → 405 with Allow: GET, POST, DELETE
  • POST stays stateless → no Mcp-Session-Id header

Real behavior proof

  • Behavior addressed: Streamable HTTP MCP clients now get the loopback notification channel they open during initialization. Before this patch, GET /mcp returned 405 even though OpenClaw generated an HTTP MCP server config, leaving clients stuck connecting without OpenClaw MCP tools.
  • Real environment tested: Blacksmith Testbox through Crabbox, provider blacksmith-testbox, id tbx_01ktn2f64amve324y4w7fqn87c, GitHub Actions run 27179521692, Ubuntu runner with Node 24. The compiled smoke ran from the built OpenClaw dist output. The contributor also provided curl output from a built and running loopback MCP server.
  • Exact steps or command run after this patch: Built the repo, started the compiled MCP loopback server from dist, hit the real HTTP endpoint with fetch/curl-equivalent requests for GET, DELETE, and unsupported methods, connected the official @modelcontextprotocol/sdk StreamableHTTPClientTransport client, called tools/list, opened an authenticated GET SSE stream, and closed the server while the SSE stream was active.
  • Evidence after fix: Terminal output from the remote Testbox proof:
compiled MCP loopback smoke passed {"port":38599,"sdkTools":28}
blacksmith run summary sync=delegated command=10m36.118s total=10m45.557s exit=0
{"provider":"blacksmith-testbox","leaseId":"tbx_01ktn2f64amve324y4w7fqn87c","slug":"brisk-krill","commandPhases":[{"name":"format","ms":584},{"name":"lint-core","ms":384218},{"name":"tsgo-core","ms":9933},{"name":"tsgo-core-test","ms":47245},{"name":"focused-vitest","ms":35406},{"name":"build","ms":111519},{"name":"compiled-e2e","ms":13749}],"exitCode":0}

Contributor curl proof from a built and running loopback MCP server also showed GET with a valid bearer returning 200 and Content-Type: text/event-stream, GET without auth returning 401, browser-Origin GET returning 403, authenticated DELETE returning 200, unauthenticated DELETE returning 401, and PUT returning 405 with Allow: GET, POST, DELETE.

  • Observed result after fix: The compiled loopback server accepted authenticated GET /mcp as a live SSE channel, rejected missing/wrong bearer tokens, rejected browser Origin requests before auth, acknowledged authenticated DELETE without creating session state, kept POST stateless with no Mcp-Session-Id, returned 405 with the updated Allow header for unsupported methods, allowed the MCP SDK client to list 28 tools, and closed an active SSE stream cleanly during server shutdown.
  • What was not tested: A live Claude Code interactive session with real user credentials was not run in this proof. The transport contract, compiled OpenClaw loopback runtime, official MCP SDK client path, auth/origin edges, shutdown behavior, focused gateway/agent tests, type checks, lint, and build were tested remotely.

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 3, 2026
@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 7, 2026, 5:07 AM ET / 09:07 UTC.

Summary
The PR adds GET /mcp SSE handling, DELETE /mcp teardown acknowledgement, stateless POST behavior, and focused gateway tests for the MCP loopback HTTP server.

PR surface: Source +57, Tests +87. Total +144 across 2 files.

Reproducibility: yes. Current main can be reproduced from source by starting the loopback MCP server and sending GET /mcp, which reaches the non-POST 405 path despite the generated type: "http" Streamable HTTP config.

Review metrics: 2 noteworthy metrics.

  • MCP loopback HTTP methods: 2 added, 1 Allow header changed. GET and DELETE alter the protocol surface and security/session contract beyond ordinary test coverage.
  • Session-id behavior: 0 session IDs advertised, 1 DELETE no-op added. The stateless choice is central to whether this is the right long-term loopback MCP contract.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Have a gateway/MCP owner explicitly accept the stateless no-session and DELETE no-op contract.
  • Run or rely on final-head src/gateway/mcp-http.test.ts or CI after rebasing onto current main.

Risk before merge

  • [P1] The PR expands the bearer-authenticated loopback MCP surface from POST-only to a long-lived GET SSE stream; the code rejects browser Origin before bearer auth, but the security-boundary expansion still needs owner acceptance.
  • [P1] The PR chooses stateless semantics: POST advertises no Mcp-Session-Id and DELETE is an auth-gated no-op, so maintainers should explicitly accept that loopback contract instead of expecting session lifecycle management.
  • [P2] Current main moved under the same MCP loopback files after the PR branch; final merge-head CI or a rebase should prove the GET/DELETE additions compose with current body-timeout and cache behavior.

Maintainer options:

  1. Accept the stateless loopback contract (recommended)
    A gateway/MCP owner can merge after confirming no session lifecycle is intended and the auth-gated DELETE no-op is the desired compatibility behavior.
  2. Make the bridge sessionful before merge
    If maintainers want Mcp-Session-Id semantics, replace the no-session path with real session issuance, validation, expiry, and teardown tests before landing.
  3. Pause the branch if the surface is too broad
    If owners do not want a long-lived SSE endpoint on the loopback server yet, keep the POST-only bridge and close or redesign this PR around a smaller approved contract.

Next step before merge

  • [P2] The open PR should stay in human maintainer review because the remaining blocker is owner acceptance of protocol/session/security semantics, not a narrow automated repair.

Security
Cleared: No concrete security defect was found in the diff; GET and DELETE are bearer-gated and reject browser Origin before auth, while the broader loopback SSE surface remains a maintainer merge-risk decision.

Review details

Best possible solution:

Land the narrow GET SSE and stateless DELETE behavior only after a gateway/MCP owner accepts the stateless/security contract and final-head gateway tests or CI confirm it composes with current main.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main can be reproduced from source by starting the loopback MCP server and sending GET /mcp, which reaches the non-POST 405 path despite the generated type: "http" Streamable HTTP config.

Is this the best way to solve the issue?

Yes for the missing GET SSE behavior; it is the narrowest fix for the reported hang. The stateless no-session and DELETE no-op parts are acceptable only if a gateway/MCP owner explicitly accepts that as the loopback contract.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against e06f6ffc3e87.

Label changes

Label justifications:

  • P1: The PR targets a broken agent/tool workflow where Streamable HTTP clients can hang without receiving OpenClaw MCP tools.
  • merge-risk: 🚨 session-state: The diff intentionally chooses no Mcp-Session-Id lifecycle while accepting DELETE as a no-op, which defines session behavior for the loopback bridge.
  • merge-risk: 🚨 security-boundary: The diff adds a long-lived bearer-authenticated SSE response on the local loopback server, expanding the HTTP boundary even though Origin checks remain in place.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body and follow-up comment include after-fix curl output from a built, running loopback MCP server showing GET 200 text/event-stream, auth/Origin failures, DELETE 200, and updated 405 Allow behavior.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body and follow-up comment include after-fix curl output from a built, running loopback MCP server showing GET 200 text/event-stream, auth/Origin failures, DELETE 200, and updated 405 Allow behavior.
Evidence reviewed

PR surface:

Source +57, Tests +87. Total +144 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 58 1 +57
Tests 1 87 0 +87
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 145 1 +144

What I checked:

  • Current main behavior: Current main emits a loopback MCP config with type: "http" and /mcp, while validateMcpLoopbackRequest rejects every non-POST /mcp request with 405 and Allow: POST; this supports the reported Streamable HTTP GET gap. (src/gateway/mcp-http.loopback-runtime.ts:36, e06f6ffc3e87)
  • PR implementation: The proposed head adds auth- and Origin-gated GET handling that returns text/event-stream, auth- and Origin-gated DELETE handling that returns 200, and updates the unsupported-method Allow header to GET, POST, DELETE. (src/gateway/mcp-http.request.ts:96, a4e3cedad5a1)
  • Regression coverage: The PR adds focused loopback tests for GET SSE success, GET/DELETE auth and Origin rejection, DELETE 200, unsupported-method Allow, and no Mcp-Session-Id on POST. (src/gateway/mcp-http.test.ts:658, a4e3cedad5a1)
  • Codex Streamable HTTP contract checked: Codex's Streamable HTTP adapter sends POST with optional Mcp-Session-Id, treats response Mcp-Session-Id as optional, tolerates DELETE 405 as unsupported, and has a GET SSE path requiring text/event-stream or JSON-compatible content type. (../codex/codex-rs/rmcp-client/src/http_client_adapter.rs:84, b89ce9a2bced)
  • MCP transport spec checked: The 2025-06-18 MCP transport spec says clients may issue GET to open an SSE stream; the server must return text/event-stream or 405, session IDs are optional, and DELETE is the session-termination path when a session is in use.
  • History and ownership: Gateway MCP loopback work is concentrated in prior commits restoring/splitting the bridge and recent current-main cleanup around request timeout/cache behavior. (src/gateway/mcp-http.ts:138, 6bfd47af38a4)

Likely related people:

  • steipete: History shows Peter Steinberger restored the Claude CLI loopback MCP bridge and later split the MCP loopback transport helpers, which are the owner boundary this PR changes. (role: feature introducer and adjacent owner; confidence: high; commits: 3de09fbe74, 25b069a6f3, 19d8069aea; files: src/gateway/mcp-http.ts, src/gateway/mcp-http.request.ts, src/gateway/mcp-http.runtime.ts)
  • vincentkoc: Current-main blame for the central MCP loopback files points to Vincent Koc's recent cleanup, including request timeout, runtime config, and test coverage now adjacent to this PR. (role: recent area contributor; confidence: high; commits: 6bfd47af38a4, 2e08f0f4221f, 84bcae95a0b7; files: src/gateway/mcp-http.ts, src/gateway/mcp-http.request.ts, src/gateway/mcp-http.test.ts)
  • eleqtrizit: Agustin Rivera has recent history hardening MCP loopback request validation and related non-owner gateway behavior, which is relevant to the Origin/bearer boundary here. (role: adjacent security-boundary contributor; confidence: medium; commits: 62430d9f3a, fe0f686c92; files: src/gateway/mcp-http.request.ts, src/gateway/mcp-http.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels Jun 3, 2026
@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. and removed merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels Jun 3, 2026
@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. label Jun 3, 2026
@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

Addressed the review:

  • Session semantics → stateless ([P1] "keep stateless or validate"): dropped the advertised Mcp-Session-Id. A single-purpose local loopback tool endpoint owns no session lifecycle, so advertising a session id clients would echo back (and the server would ignore) was misleading. POST responses are now stateless; per the spec a stateless server simply omits the session id.
  • DELETE → 200 no-op (auth-gated): the body claimed DELETE teardown but the code returned 405; added a real auth-gated 200 acknowledgement so clients that DELETE on close get a clean 200. Allow now advertises GET, POST, DELETE.
  • Focused gateway tests ([P1]): GET 200+text/event-stream, GET 401 (no auth), GET 403 (browser Origin), DELETE 200, DELETE 401, unsupported 405 with the correct Allow, and POST stays stateless (no Mcp-Session-Id) — all driving the real loopback HTTP server via fetch.

On the [P1] real-behavior proof: the transport (GET notification channel returning 200+SSE instead of the 405 that caused the hang) is exercised over real HTTP in the tests above. The full live Claude Code "MCP tools connect" run is contributor-setup proof — the agent runtime's private deps resolve only in the build environment, so it can't be produced from a plain source checkout — and will be attached from a patched OpenClaw + Claude Code session.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

Added real-behavior proof: built and started the patched loopback MCP server and hit it with curl — GET (valid bearer) returns 200 + text/event-stream (the SSE notification channel; curl then blocks on the open stream, not the old 405 that hung "still connecting"); GET no-auth → 401; GET browser-origin → 403; DELETE → 200; DELETE no-auth → 401; PUT → 405 with Allow: GET, POST, DELETE. Full curl transcript in the PR body, mirrored by the gateway tests. @clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 6, 2026
@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

Addressed both code findings:

  • Origin-before-auth ([P1]): reordered the new GET and DELETE branches so rejectsBrowserLoopbackRequest() runs before bearer auth, matching the POST path — a browser-Origin loopback request is now rejected (403) before auth, so the loopback Origin boundary holds for unauthenticated browser requests too. Added tests: browser-Origin GET and DELETE with no bearer → 403 (before auth).
  • Test import ([P1]): the new transport tests now read the owner token from getActiveMcpLoopbackRuntime().ownerToken rather than resolveMcpLoopbackBearerToken, so they don't depend on that helper's import (current main's test file no longer carries it) — the added tests compile against current main.

84 gateway tests pass. The stateless no-Mcp-Session-Id choice + DELETE no-op remain as the maintainer-acceptance item. @clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

@openclaw-barnacle openclaw-barnacle Bot added triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 6, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 6, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label Jun 6, 2026
@anagnorisis2peripeteia anagnorisis2peripeteia marked this pull request as ready for review June 7, 2026 08:58
anagnorisis2peripeteia added a commit to anagnorisis2peripeteia/openclaw that referenced this pull request Jun 7, 2026
…rt) onto combined branch

The agent's MCP loopback client opens a GET/SSE notification channel; without
openclaw#89851's GET/SSE handling the loopback server 405s it and the agent turn hangs
after tool-policy, before the model call. Porting openclaw#89851 (GET/SSE + DELETE no-op
+ origin-before-auth, stateless) so the loopback completes and a live agent turn
can actually stream — needed for the streaming echo capture. 3-way applied clean.
anagnorisis2peripeteia and others added 9 commits June 9, 2026 15:50
The MCP loopback server generates config with `"type": "http"` for
Claude Code, but only handled POST requests. Claude Code's Streamable
HTTP client sends GET to open an SSE notification channel before
completing initialization. The 405 rejection on GET caused Claude Code
to hang at "still connecting" indefinitely.

- Accept GET /mcp with bearer auth, return text/event-stream (idle SSE)
- Accept DELETE /mcp for session termination (spec compliance)
- Add Mcp-Session-Id header to POST responses (spec requirement)
- Update 405 Allow header to reflect supported methods
…check

- flushHeaders() + initial SSE comment so clients don't hang
- DELETE requires bearer auth (matching GET/POST gates)
- DELETE checks browser-origin rejection (matching POST gate)
…o terminate

The DELETE path acknowledged Mcp-Session-Id without validating,
terminating, or expiring anything. Since the loopback server is
stateless (session ID is cosmetic for spec compliance), return 405
instead of pretending to support session teardown.
…rt tests

Addresses review feedback on the Streamable HTTP transport:

- Keep the loopback server stateless: drop the advertised Mcp-Session-Id header
  (the server owns no session lifecycle, so advertising a session id clients
  would echo back was misleading). Resolves the stateless-vs-sessionful concern.
- Add DELETE /mcp as an auth-gated 200 no-op (Streamable HTTP teardown), so
  clients that send DELETE on close get a clean 200 instead of 405; Allow now
  advertises GET, POST, DELETE.
- Keep the GET/SSE notification channel (the actual fix for the 'still
  connecting' hang) auth-gated and browser-origin-rejected.
- Add focused gateway tests: GET 200 + text/event-stream, GET 401 (no auth),
  GET 403 (browser origin), DELETE 200, DELETE 401, unsupported 405 with the
  correct Allow, and POST stays stateless (no Mcp-Session-Id).
…est token

Addresses review:
- Reorder the new GET and DELETE branches so rejectsBrowserLoopbackRequest()
  runs BEFORE bearer auth, matching the POST path — a browser-Origin loopback
  request is now rejected (403) before auth, preserving the loopback Origin
  boundary even for unauthenticated browser requests. Added focused tests:
  browser-Origin GET and DELETE with no bearer return 403 (before auth).
- The new transport tests now read the loopback owner token from
  getActiveMcpLoopbackRuntime().ownerToken instead of resolveMcpLoopbackBearerToken,
  so they don't depend on that helper's import (which current main's test file
  no longer carries).
@shakkernerd shakkernerd force-pushed the fix/mcp-streamable-http branch from a4e3ced to a016383 Compare June 9, 2026 14:50
@openclaw-barnacle openclaw-barnacle Bot added size: M proof: supplied External PR includes structured after-fix real behavior proof. and removed size: S proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 9, 2026
@shakkernerd shakkernerd merged commit d2a6529 into openclaw:main Jun 9, 2026
183 of 188 checks passed
@shakkernerd

Copy link
Copy Markdown
Member

Merged using rebase.

What landed:

  • Streamable HTTP MCP loopback support for GET SSE and stateless DELETE.
  • Browser Origin rejection before bearer auth on GET/DELETE.
  • Active SSE response cleanup during gateway shutdown so long-lived streams do not hang shutdown.
  • Focused gateway coverage for auth, origin, stateless POST/DELETE behavior, unsupported methods, SDK transport interop, and shutdown.

Verification:

  • Auto-review reran clean with no accepted/actionable findings.
  • Crabbox/Testbox proof passed on blacksmith-testbox (tbx_01ktn2f64amve324y4w7fqn87c, run 27179521692): lint, type checks, focused gateway/agent tests, build, and compiled MCP loopback smoke.
  • PR CI and Real behavior proof passed before merge.

Thanks @anagnorisis2peripeteia.

eleboucher pushed a commit to eleboucher/homelab that referenced this pull request Jun 12, 2026
…26.6.6) (#1040)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/openclaw/openclaw](https://openclaw.ai) ([source](https://github.com/openclaw/openclaw)) | patch | `2026.6.5` → `2026.6.6` |

---

### Release Notes

<details>
<summary>openclaw/openclaw (ghcr.io/openclaw/openclaw)</summary>

### [`v2026.6.6`](https://github.com/openclaw/openclaw/blob/HEAD/CHANGELOG.md#202666)

[Compare Source](openclaw/openclaw@v2026.6.5...v2026.6.6)

##### Highlights

- Security boundaries are substantially tighter across transcripts, sandbox binds, host environment inheritance, MCP stdio, Codex HTTP access, native search policy, elevated sender checks, deleted-agent ACP bypasses, loopback tools, Discord moderation, and Teams group actions; exec approvals now fail closed on timeout. ([#&#8203;91529](openclaw/openclaw#91529), [#&#8203;91618](openclaw/openclaw#91618), [#&#8203;91615](openclaw/openclaw#91615), [#&#8203;91619](openclaw/openclaw#91619), [#&#8203;91741](openclaw/openclaw#91741), [#&#8203;91745](openclaw/openclaw#91745), [#&#8203;91746](openclaw/openclaw#91746), [#&#8203;91748](openclaw/openclaw#91748), [#&#8203;91749](openclaw/openclaw#91749), [#&#8203;91750](openclaw/openclaw#91750), [#&#8203;91751](openclaw/openclaw#91751), [#&#8203;91752](openclaw/openclaw#91752), [#&#8203;91763](openclaw/openclaw#91763), [#&#8203;89938](openclaw/openclaw#89938)) Thanks [@&#8203;joshavant](https://github.com/joshavant), [@&#8203;pgondhi987](https://github.com/pgondhi987), [@&#8203;mmaps](https://github.com/mmaps), [@&#8203;eleqtrizit](https://github.com/eleqtrizit), [@&#8203;shakkernerd](https://github.com/shakkernerd), and [@&#8203;drobison00](https://github.com/drobison00).
- Telegram delivery is safer and more coherent: account-scoped topics route to the right agent, streamed text survives tool calls, `/compact` works on generic ingress, callback handling uses concrete APIs, draft chunking is shared, durable dispatch dedupe moved into the SDK, and unauthorized DM text stays out of cache and prompt context. ([#&#8203;91189](openclaw/openclaw#91189), [#&#8203;88682](openclaw/openclaw#88682), [#&#8203;89588](openclaw/openclaw#89588), [#&#8203;90212](openclaw/openclaw#90212), [#&#8203;91876](openclaw/openclaw#91876), [#&#8203;91874](openclaw/openclaw#91874), [#&#8203;91904](openclaw/openclaw#91904), [#&#8203;91478](openclaw/openclaw#91478), [#&#8203;91915](openclaw/openclaw#91915)) Thanks [@&#8203;codysai001](https://github.com/codysai001), [@&#8203;alexzhu0](https://github.com/alexzhu0), [@&#8203;joelnishanth](https://github.com/joelnishanth), [@&#8203;snowzlm](https://github.com/snowzlm), [@&#8203;obviyus](https://github.com/obviyus), and [@&#8203;sallyom](https://github.com/sallyom).
- iMessage recovery and delivery now cover always-on inbound restart, durable echo markers, block streaming, idle approval discovery, hardened outbound transport, and actionable inbound startup diagnostics. ([#&#8203;91335](openclaw/openclaw#91335), [#&#8203;91449](openclaw/openclaw#91449), [#&#8203;88969](openclaw/openclaw#88969), [#&#8203;88530](openclaw/openclaw#88530), [#&#8203;91783](openclaw/openclaw#91783), [#&#8203;91785](openclaw/openclaw#91785)) Thanks [@&#8203;omarshahine](https://github.com/omarshahine), [@&#8203;jmissig](https://github.com/jmissig), and [@&#8203;colmbrogan](https://github.com/colmbrogan).
- Browser and MCP connectivity gained existing-session CDP support, discovered WebSocket validation, default-profile `cdpUrl` handling, safer browser-output boundaries, Streamable HTTP loopback transport, corrected OAuth/SSE authorization handling, and broader schema compatibility. ([#&#8203;91422](openclaw/openclaw#91422), [#&#8203;89851](openclaw/openclaw#89851), [#&#8203;91736](openclaw/openclaw#91736), [#&#8203;91747](openclaw/openclaw#91747), [#&#8203;91451](openclaw/openclaw#91451), [#&#8203;80143](openclaw/openclaw#80143)) Thanks [@&#8203;pgondhi987](https://github.com/pgondhi987), [@&#8203;anagnorisis2peripeteia](https://github.com/anagnorisis2peripeteia), [@&#8203;lifuyue](https://github.com/lifuyue), [@&#8203;eleqtrizit](https://github.com/eleqtrizit), [@&#8203;LiuwqGit](https://github.com/LiuwqGit), and [@&#8203;HemantSudarshan](https://github.com/HemantSudarshan).
- Control UI startup and first-reply latency are lower through cached model metadata, removal of the startup catalog wait, lazy slash-command loading, and first-event tracing with slow-reply diagnostics. ([#&#8203;91531](openclaw/openclaw#91531), [#&#8203;91538](openclaw/openclaw#91538), [#&#8203;91568](openclaw/openclaw#91568), [#&#8203;91583](openclaw/openclaw#91583), [#&#8203;91598](openclaw/openclaw#91598))
- Provider support expands with OpenRouter OAuth onboarding and Claude Fable 5 adaptive thinking, while Codex sessions keep correct compaction ownership, local models skip guardian review, dynamic tool progress normalizes cleanly, and Gemma 4 reasoning replay is preserved. ([#&#8203;91830](openclaw/openclaw#91830), [#&#8203;91882](openclaw/openclaw#91882), [#&#8203;91590](openclaw/openclaw#91590), [#&#8203;88630](openclaw/openclaw#88630), [#&#8203;88768](openclaw/openclaw#88768), [#&#8203;91696](openclaw/openclaw#91696)) Thanks [@&#8203;Patrick-Erichsen](https://github.com/Patrick-Erichsen), [@&#8203;joshavant](https://github.com/joshavant), [@&#8203;bdjben](https://github.com/bdjben), and [@&#8203;Coder-Wangyankun](https://github.com/Coder-Wangyankun).

##### Changes

- CLI progress: emit Claude CLI commentary progress events and bridge inter-tool commentary into channel progress without exposing internal protocol scaffolding. ([#&#8203;89834](openclaw/openclaw#89834), [#&#8203;90883](openclaw/openclaw#90883)) Thanks [@&#8203;anagnorisis2peripeteia](https://github.com/anagnorisis2peripeteia).
- Observability: allow trusted diagnostics channels to capture tool input/output content, add first-assistant-event traces, and warn on slow initial replies. ([#&#8203;91256](openclaw/openclaw#91256), [#&#8203;91568](openclaw/openclaw#91568), [#&#8203;91583](openclaw/openclaw#91583)) Thanks [@&#8203;amknight](https://github.com/amknight).
- Plugins/ClawHub: dogfood reusable package publishing, let dry runs skip publish approval, allow declared installed trusted hooks, report managed plugin version drift, and warn instead of failing on retired Skill Workshop configuration. ([#&#8203;91574](openclaw/openclaw#91574), [#&#8203;91591](openclaw/openclaw#91591), [#&#8203;90004](openclaw/openclaw#90004), [#&#8203;90927](openclaw/openclaw#90927), [#&#8203;90838](openclaw/openclaw#90838)) Thanks [@&#8203;Patrick-Erichsen](https://github.com/Patrick-Erichsen), [@&#8203;brokemac79](https://github.com/brokemac79), and [@&#8203;lonexreb](https://github.com/lonexreb).
- Memory/providers: move the local llama.cpp runtime into its provider plugin, batch embeddings across files, persist the agent model catalog cache, and keep QMD JSON search one-shot while filtering stale REM recall previews. ([#&#8203;91324](openclaw/openclaw#91324), [#&#8203;89138](openclaw/openclaw#89138), [#&#8203;90457](openclaw/openclaw#90457), [#&#8203;91837](openclaw/openclaw#91837), [#&#8203;91851](openclaw/openclaw#91851)) Thanks [@&#8203;osolmaz](https://github.com/osolmaz), [@&#8203;mushuiyu886](https://github.com/mushuiyu886), [@&#8203;ai-hpc](https://github.com/ai-hpc), and [@&#8203;TurboTheTurtle](https://github.com/TurboTheTurtle).
- Channels/mobile: add the QQBot group mention toggle, improve iPad and iPhone control surfaces, and expose the active connection host in the TUI footer. ([#&#8203;91423](openclaw/openclaw#91423), [#&#8203;91557](openclaw/openclaw#91557), [#&#8203;89909](openclaw/openclaw#89909)) Thanks [@&#8203;cxyhhhhh](https://github.com/cxyhhhhh), [@&#8203;Solvely-Colin](https://github.com/Solvely-Colin), and [@&#8203;baskduf](https://github.com/baskduf).
- Performance: prewarm TUI runtime plugins, deduplicate plugin auto-enable fanout, trim dense text-delta snapshots, and reuse prepared startup model metadata. ([#&#8203;90782](openclaw/openclaw#90782), [#&#8203;89978](openclaw/openclaw#89978), [#&#8203;91580](openclaw/openclaw#91580), [#&#8203;91531](openclaw/openclaw#91531)) Thanks [@&#8203;RomneyDa](https://github.com/RomneyDa) and [@&#8203;ai-hpc](https://github.com/ai-hpc).

##### Fixes

- Agent/session recovery: drop stale approval follow-ups after session rebind, remove drained reply-queue items by identity, recover stale main and visible replies, preserve Codex context-engine compaction ownership, lower the default compaction timeout to 180 seconds while respecting explicit configuration, and keep provider-failure terminal lifecycle state correct. ([#&#8203;85679](openclaw/openclaw#85679), [#&#8203;91450](openclaw/openclaw#91450), [#&#8203;91566](openclaw/openclaw#91566), [#&#8203;91840](openclaw/openclaw#91840), [#&#8203;91590](openclaw/openclaw#91590), [#&#8203;91361](openclaw/openclaw#91361), [#&#8203;91895](openclaw/openclaw#91895)) Thanks [@&#8203;openperf](https://github.com/openperf), [@&#8203;yetval](https://github.com/yetval), [@&#8203;joshavant](https://github.com/joshavant), [@&#8203;wangmiao0668000666](https://github.com/wangmiao0668000666), and [@&#8203;TurboTheTurtle](https://github.com/TurboTheTurtle).
- User-visible content boundaries: suppress Codex/Harmony protocol artifacts, neutralize browser and LanceDB memory media directives, redact transcript images, and preserve native `/compact` replies through source suppression. ([#&#8203;89151](openclaw/openclaw#89151), [#&#8203;91422](openclaw/openclaw#91422), [#&#8203;91425](openclaw/openclaw#91425), [#&#8203;91529](openclaw/openclaw#91529), [#&#8203;90212](openclaw/openclaw#90212)) Thanks [@&#8203;joelnishanth](https://github.com/joelnishanth), [@&#8203;pgondhi987](https://github.com/pgondhi987), [@&#8203;joshavant](https://github.com/joshavant), and [@&#8203;snowzlm](https://github.com/snowzlm).
- Channel delivery: keep WhatsApp captured replies attached to the successor controller after restart, retry Feishu rate limits, preserve Mattermost thread replies, canonicalize LINE webhook paths, restore Discord reply hydration and runtime timeout exports, and show OpenAI Realtime WebRTC assistant transcripts. ([#&#8203;85823](openclaw/openclaw#85823), [#&#8203;89659](openclaw/openclaw#89659), [#&#8203;91684](openclaw/openclaw#91684), [#&#8203;91649](openclaw/openclaw#91649), [#&#8203;90263](openclaw/openclaw#90263), [#&#8203;91686](openclaw/openclaw#91686), [#&#8203;90426](openclaw/openclaw#90426)) Thanks [@&#8203;itsuzef](https://github.com/itsuzef), [@&#8203;ladygege](https://github.com/ladygege), [@&#8203;jacobtomlinson](https://github.com/jacobtomlinson), [@&#8203;fuller-stack-dev](https://github.com/fuller-stack-dev), and [@&#8203;shushushv](https://github.com/shushushv).
- Cron: cancel active task runs cleanly, preserve terminal timeout/cancel state, and recover no-deliver tool warnings instead of silently losing the outcome. ([#&#8203;90666](openclaw/openclaw#90666), [#&#8203;90678](openclaw/openclaw#90678)) Thanks [@&#8203;ai-hpc](https://github.com/ai-hpc).
- Gateway/config/auth: share the approval runtime socket token, replace arrays explicitly in `config.patch`, skip the deleted-agent guard only for valid ACP harness sessions, surface headless LaunchAgent state, verify SQLite auth migration before cleanup, and arm QMD startup maintenance. ([#&#8203;87105](openclaw/openclaw#87105), [#&#8203;91551](openclaw/openclaw#91551), [#&#8203;91219](openclaw/openclaw#91219), [#&#8203;91614](openclaw/openclaw#91614), [#&#8203;91740](openclaw/openclaw#91740), [#&#8203;91978](openclaw/openclaw#91978)) Thanks [@&#8203;fuller-stack-dev](https://github.com/fuller-stack-dev) and [@&#8203;scotthuang](https://github.com/scotthuang).
- Providers/Codex: clarify quota errors, restore the Codex synthetic usage line, canonicalize Codex protocol assets, require API-key auth for realtime voice, normalize ACP model refs, preserve Gemma 4 `reasoning_content`, and avoid guardian review for local models. ([#&#8203;91390](openclaw/openclaw#91390), [#&#8203;91709](openclaw/openclaw#91709), [#&#8203;91507](openclaw/openclaw#91507), [#&#8203;91567](openclaw/openclaw#91567), [#&#8203;88630](openclaw/openclaw#88630), [#&#8203;91696](openclaw/openclaw#91696)) Thanks [@&#8203;hxy91819](https://github.com/hxy91819), [@&#8203;brokemac79](https://github.com/brokemac79), [@&#8203;RomneyDa](https://github.com/RomneyDa), [@&#8203;joshavant](https://github.com/joshavant), and [@&#8203;Coder-Wangyankun](https://github.com/Coder-Wangyankun).
- Updates/builds: recover package Gateway restarts after refresh failure, expose plugin convergence repair, fall back to Corepack in PATH-less pnpm environments, seed the correct Docker store packages, and keep ClawHub dry-run and publish paths reusable. ([#&#8203;91581](openclaw/openclaw#91581), [#&#8203;91599](openclaw/openclaw#91599), [#&#8203;91547](openclaw/openclaw#91547), [#&#8203;91591](openclaw/openclaw#91591)) Thanks [@&#8203;fuller-stack-dev](https://github.com/fuller-stack-dev), [@&#8203;sallyom](https://github.com/sallyom), and [@&#8203;Patrick-Erichsen](https://github.com/Patrick-Erichsen).
- UI: require explicit user intent before opening chat sessions and drain restored chat queues after session switches. ([#&#8203;91480](openclaw/openclaw#91480)) Thanks [@&#8203;TurboTheTurtle](https://github.com/TurboTheTurtle).
- Android: avoid the `dataSync` foreground-service type for persistent nodes. ([#&#8203;80082](openclaw/openclaw#80082)) Thanks [@&#8203;davelutztx](https://github.com/davelutztx).
- Native hooks: bound relay lifetimes so abandoned native hook connections cannot linger indefinitely. ([#&#8203;91550](openclaw/openclaw#91550)) Thanks [@&#8203;joshavant](https://github.com/joshavant).

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19-->

Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/1040
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P1 High-priority user-facing bug, regression, or broken workflow. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: M status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants