[PR #5183] [CLOSED] feat(mcp): serve streamable HTTP with drained session handovers #6807

Closed
opened 2026-11-01 21:43:10 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/5183
Author: @gensokyo-dev
Created: 10/19/2026
Status: ❌ Closed

Base: main ← Head: followup/mcp-http-session-drain-20261019


📝 Commits (10+)

  • 46dd8f0 feat(mcp): serve the MCP server over streamable HTTP
  • b0ec63c fix(mcp): harden the streamable HTTP listener's session replacement and shutdown
  • 9ed8f06 fix(mcp): compare the media type proper and bind before creating the server
  • b76f354 fix(mcp): classify loopback from the bound address and keep startup failures out of onerror
  • fb22df3 fix(mcp): match Accept ranges exactly and keep a session whose shutdown failed
  • 54a7475 refactor(mcp): release the listener through one helper
  • 1741882 fix(mcp): fire the shutdown hook once, stop awaiting the probe's tee and keep every Set-Cookie
  • 354b4d8 fix(mcp): latch startup signals so the HTTP entry never ends without cleanup
  • 136d073 fix(mcp): keep a startup signal's exit status through the entry's normal return
  • a23f5f1 fix(mcp): close the connection after a reply sent before the body was read

📊 Changes

35 files changed (+3885 additions, -57 deletions)

View changed files

📝 docs/architecture.mermaid (+3 -3)
📝 docs/cli.md (+26 -0)
📝 docs/mcp-contracts.md (+66 -1)
➕ docs/specs/agent-environments/http-transport/plan.md (+32 -0)
➕ docs/specs/agent-environments/http-transport/spec.md (+79 -0)
➕ docs/specs/agent-environments/http-transport/tasks.md (+11 -0)
➕ docs/specs/agent-environments/http-transport/verification.md (+297 -0)
📝 scripts/rea.mjs (+23 -12)
➕ src/config/mcpHttpEndpoint.ts (+68 -0)
📝 src/main.ts (+117 -3)
➕ src/main/mcpHttpArguments.ts (+104 -0)
📝 src/main/messages.ts (+2 -0)
📝 src/main/processShutdown.ts (+89 -10)
📝 src/main/shutdown.ts (+6 -4)
📝 src/main/transport.ts (+18 -7)
📝 src/main/types.ts (+23 -1)
📝 src/server/EvidenceMcpServer.ts (+2 -2)
➕ src/server/RequestTrackingMcpServer.test.ts (+88 -0)
➕ src/server/RequestTrackingMcpServer.ts (+92 -0)
➕ src/server/http/nodeHttpBridge.test.ts (+283 -0)

...and 15 more files

📄 Description

Closed: this was an unintended replacement PR. All follow-up commits have been pushed directly to the original #4955 author branch at the same validated head dca91463a9. Continue review, CI and merging in #4955. The record below documents validation at closure.

Summary

Continue #4955 on latest main 9aca543: expose the existing MCP catalog through explicit rea mcp --http, and wait for cancelled work before another client or provider teardown can reuse its resources.

Retains @earakely-scale's original transport implementation and fixes. Refs #4933 (item 2); the original PR remains #4955. The requesting human explicitly authorized this scope, initial readiness and merging in the implementation session. Replay serving and bundle export are separate increments.

Behavior and boundaries

  • Stdio remains the default for startup, registrations/setup, doctor and registry metadata. HTTP requires --http, defaults to loopback/ephemeral port, and validates Host/Origin. Invalid HTTP environment settings do not change ordinary stdio startup.
  • HTTP tracks tool callbacks and provider-backed prompt completions through their cleanup. Handover waits up to ten seconds; timeout returns 503 and retains the old owner. Full shutdown waits for completion before provider teardown, including when it joins a timed-out handover. Late validated tool callbacks cannot start after cancellation.
  • HTTP is plain HTTP without TLS/client authentication. Successive clients share the active target; it provides no user isolation. Use a trusted local or isolated environment. Existing target authorities are preserved.

Validation

Executed on dca9146, including latest main 9aca543:

  • Full static CI task gate: 8/8 passed, including typecheck, runtime compilation, lint/module boundaries, formatting, Knip, metadata and duplicate/debt checks. Lint: 0 errors, 1735 repository warnings.
  • 113 tests in 13 files passed across adapters and compiled CLI/MCP/process boundaries. Covers handover/DELETE, callback cleanup, late validation, timeout/shutdown races, prompt completions, signal statuses, default stdio with invalid HTTP settings, and stdio doctor across full/compact/output-schema configurations.
  • Actual installed /usr/bin/gh application (40,149,832 bytes): seven CLI/stdio/HTTP normalized reports matched exactly and agreed with go version -m, artifact size and SHA-256. DELETE/replacement preserved results, the replaced client was refused, and SIGTERM exited 143 with empty stdout and a released listener. Source bytes stayed unchanged.
  • New regressions fail against the prior implementation: a replacement connects before old work finishes, timeout admits a new session, completion cleanup survives premature reconnect/shutdown. They pass after the fixes.

Synthetic handler/provider tests establish lifecycle behavior; real-app validation covers Go artifact analysis. Real Hopper/Ghidra/IDA execution and environment replay/export are not claimed.

Resource measurements

One CPU and one test worker; no concurrent heavy suites or OOM. The final 113-test run took 109.2s wall / 102.1s CPU, with 1464.4 MiB peak descendant RSS.

Equivalent completed real-app workflows, one run per head, including CLI plus stdio/HTTP initialization, tools/list, first/warm calls, reconnection and shutdown:

Head / main base Wall (s) CPU (s) Family RSS (MiB) Stdio first/warm (s) HTTP first/warm (s)
dedc87a / e4c3d7 27.405 26.950 949.6 7.826 / 0.423 7.088 / 0.356
86d908e / e4c3d7 27.732 27.270 994.0 8.298 / 0.350 7.250 / 0.364
dca9146 / 9aca543 31.019 30.476 912.1 8.948 / 0.384 9.358 / 0.395

Fresh processes; OS page caches were not reset. RSS sums descendants every 50ms and can count shared pages twice. The final comparison also includes upstream main changes; these single runs establish no isolated performance effect. Each Evidence envelope was 3536 bytes; agent token usage was not measured, and bytes are not token counts.

Author readiness

Human owner: @gensokyo-dev (acting account for the requesting human; declarations entered at their explicit direction).

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • Scope and authorities are recorded above.
  • Original contributor attribution and Evidence semantics are preserved.
  • Current-head Codex and Greptile reviews completed without new actionable findings; the earlier shutdown finding was fixed and resolved.
  • Required GitHub Actions complete. They remain queued awaiting a runner; local checks do not substitute for protected-branch required statuses.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/5183 **Author:** [@gensokyo-dev](https://github.com/gensokyo-dev) **Created:** 10/19/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `followup/mcp-http-session-drain-20261019` --- ### 📝 Commits (10+) - [`46dd8f0`](https://github.com/morluto/rea/commit/46dd8f0e2b5ff74e09821e09e51bc6fd47f3bc1a) feat(mcp): serve the MCP server over streamable HTTP - [`b0ec63c`](https://github.com/morluto/rea/commit/b0ec63cc0399ad9ca7bd00a65cb1c2d753cfd47b) fix(mcp): harden the streamable HTTP listener's session replacement and shutdown - [`9ed8f06`](https://github.com/morluto/rea/commit/9ed8f06f75ea772dfd81d552142b059852e530c3) fix(mcp): compare the media type proper and bind before creating the server - [`b76f354`](https://github.com/morluto/rea/commit/b76f354d76384abe56b079b0b37e1367d1908efd) fix(mcp): classify loopback from the bound address and keep startup failures out of onerror - [`fb22df3`](https://github.com/morluto/rea/commit/fb22df370b5146b3798b6f83e64317e2785ecfcb) fix(mcp): match Accept ranges exactly and keep a session whose shutdown failed - [`54a7475`](https://github.com/morluto/rea/commit/54a747560207c06196a1ba4eb8b8ca062f15ddc5) refactor(mcp): release the listener through one helper - [`1741882`](https://github.com/morluto/rea/commit/174188279b6ce482354966ed542436514d3d4624) fix(mcp): fire the shutdown hook once, stop awaiting the probe's tee and keep every Set-Cookie - [`354b4d8`](https://github.com/morluto/rea/commit/354b4d8c0867f3d0eadaae2b0dfe42cea810287e) fix(mcp): latch startup signals so the HTTP entry never ends without cleanup - [`136d073`](https://github.com/morluto/rea/commit/136d073fa019fb8a1c5ef95ff70ecaf6d34676c4) fix(mcp): keep a startup signal's exit status through the entry's normal return - [`a23f5f1`](https://github.com/morluto/rea/commit/a23f5f13524b5403794f3599e26f93cc18398820) fix(mcp): close the connection after a reply sent before the body was read ### 📊 Changes **35 files changed** (+3885 additions, -57 deletions) <details> <summary>View changed files</summary> 📝 `docs/architecture.mermaid` (+3 -3) 📝 `docs/cli.md` (+26 -0) 📝 `docs/mcp-contracts.md` (+66 -1) ➕ `docs/specs/agent-environments/http-transport/plan.md` (+32 -0) ➕ `docs/specs/agent-environments/http-transport/spec.md` (+79 -0) ➕ `docs/specs/agent-environments/http-transport/tasks.md` (+11 -0) ➕ `docs/specs/agent-environments/http-transport/verification.md` (+297 -0) 📝 `scripts/rea.mjs` (+23 -12) ➕ `src/config/mcpHttpEndpoint.ts` (+68 -0) 📝 `src/main.ts` (+117 -3) ➕ `src/main/mcpHttpArguments.ts` (+104 -0) 📝 `src/main/messages.ts` (+2 -0) 📝 `src/main/processShutdown.ts` (+89 -10) 📝 `src/main/shutdown.ts` (+6 -4) 📝 `src/main/transport.ts` (+18 -7) 📝 `src/main/types.ts` (+23 -1) 📝 `src/server/EvidenceMcpServer.ts` (+2 -2) ➕ `src/server/RequestTrackingMcpServer.test.ts` (+88 -0) ➕ `src/server/RequestTrackingMcpServer.ts` (+92 -0) ➕ `src/server/http/nodeHttpBridge.test.ts` (+283 -0) _...and 15 more files_ </details> ### 📄 Description **Closed: this was an unintended replacement PR. All follow-up commits have been pushed directly to the original #4955 author branch at the same validated head `dca91463a9`. Continue review, CI and merging in #4955. The record below documents validation at closure.** ## Summary Continue #4955 on latest main 9aca543: expose the existing MCP catalog through explicit `rea mcp --http`, and wait for cancelled work before another client or provider teardown can reuse its resources. Retains @earakely-scale's original transport implementation and fixes. Refs #4933 (item 2); the original PR remains #4955. The requesting human explicitly authorized this scope, initial readiness and merging in the implementation session. Replay serving and bundle export are separate increments. ## Behavior and boundaries - Stdio remains the default for startup, registrations/setup, doctor and registry metadata. HTTP requires `--http`, defaults to loopback/ephemeral port, and validates Host/Origin. Invalid HTTP environment settings do not change ordinary stdio startup. - HTTP tracks tool callbacks and provider-backed prompt completions through their cleanup. Handover waits up to ten seconds; timeout returns 503 and retains the old owner. Full shutdown waits for completion before provider teardown, including when it joins a timed-out handover. Late validated tool callbacks cannot start after cancellation. - HTTP is plain HTTP without TLS/client authentication. Successive clients share the active target; it provides no user isolation. Use a trusted local or isolated environment. Existing target authorities are preserved. ## Validation Executed on dca9146, including latest main 9aca543: - Full static CI task gate: 8/8 passed, including typecheck, runtime compilation, lint/module boundaries, formatting, Knip, metadata and duplicate/debt checks. Lint: 0 errors, 1735 repository warnings. - 113 tests in 13 files passed across adapters and compiled CLI/MCP/process boundaries. Covers handover/DELETE, callback cleanup, late validation, timeout/shutdown races, prompt completions, signal statuses, default stdio with invalid HTTP settings, and stdio doctor across full/compact/output-schema configurations. - Actual installed `/usr/bin/gh` application (40,149,832 bytes): seven CLI/stdio/HTTP normalized reports matched exactly and agreed with `go version -m`, artifact size and SHA-256. DELETE/replacement preserved results, the replaced client was refused, and SIGTERM exited 143 with empty stdout and a released listener. Source bytes stayed unchanged. - New regressions fail against the prior implementation: a replacement connects before old work finishes, timeout admits a new session, completion cleanup survives premature reconnect/shutdown. They pass after the fixes. Synthetic handler/provider tests establish lifecycle behavior; real-app validation covers Go artifact analysis. Real Hopper/Ghidra/IDA execution and environment replay/export are not claimed. ## Resource measurements One CPU and one test worker; no concurrent heavy suites or OOM. The final 113-test run took 109.2s wall / 102.1s CPU, with 1464.4 MiB peak descendant RSS. Equivalent completed real-app workflows, one run per head, including CLI plus stdio/HTTP initialization, tools/list, first/warm calls, reconnection and shutdown: | Head / main base | Wall (s) | CPU (s) | Family RSS (MiB) | Stdio first/warm (s) | HTTP first/warm (s) | | --- | ---: | ---: | ---: | ---: | ---: | | dedc87a / e4c3d7 | 27.405 | 26.950 | 949.6 | 7.826 / 0.423 | 7.088 / 0.356 | | 86d908e / e4c3d7 | 27.732 | 27.270 | 994.0 | 8.298 / 0.350 | 7.250 / 0.364 | | dca9146 / 9aca543 | 31.019 | 30.476 | 912.1 | 8.948 / 0.384 | 9.358 / 0.395 | Fresh processes; OS page caches were not reset. RSS sums descendants every 50ms and can count shared pages twice. The final comparison also includes upstream main changes; these single runs establish no isolated performance effect. Each Evidence envelope was 3536 bytes; agent token usage was not measured, and bytes are not token counts. ## Author readiness Human owner: @gensokyo-dev (acting account for the requesting human; declarations entered at their explicit direction). - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] Scope and authorities are recorded above. - [x] Original contributor attribution and Evidence semantics are preserved. - [x] Current-head Codex and Greptile reviews completed without new actionable findings; the earlier shutdown finding was fixed and resolved. - [ ] Required GitHub Actions complete. They remain queued awaiting a runner; local checks do not substitute for protected-branch required statuses. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-11-01 21:43:10 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#6807
No description provided.