closeAllConnections() ran before close(), so a connection accepted in
between missed the forced-close pass and close() could wait for its
request timeout. close() now starts first and closeAllConnections()
follows immediately, as Node documents.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Addresses a thirteenth automated review finding: `application/json;q=0`
explicitly refuses JSON, so it no longer counts toward the exact Accept ranges
a session takeover requires.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Addresses the twelfth automated review finding: bodyUsed only means a body
was disturbed, so a route that read one chunk of an upload left the rest
paused on a keep-alive socket. The close decision now follows the incoming
message's end of stream.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Addresses the tenth automated review round: the bridge joins an origin-form
request target onto the listener's origin so a network-path target stays a
path and absolute-form targets are refused; only a lone initialize can replace
an open session; and the shutdown hook records completion only after it
returns, so a hook that threw stays eligible for the next close.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Addresses the ninth automated review round: a method Fetch refuses, such as
TRACE, is answered with 405 instead of escaping the request guard; the
unread-body decision now comes from the incoming message's own body
declaration, so a GET or HEAD carrying a body closes too; and the regression
uses a keep-alive client and checks that the socket actually closes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Addresses the eighth automated review finding: a refused Host or Origin, an
unknown route or the startup 503 answered a POST while its body stayed unread
on the paused bridged stream; such replies now carry Connection: close so an
unread upload cannot keep a socket open.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Addresses the fifth automated review round: the instance's shutdown hook runs
exactly once even when the listener closes without a live session; the
initialize probe no longer awaits cancelling its cloned body, which would wait
for the original request to drain; and the node:http bridge passes repeated
Set-Cookie values through as an array.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Replaces a comma expression left by the previous commit with plain
statements and moves the port release into a small function, so the listener
body stays within the lint limits without changing behaviour.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Addresses the fourth automated review round: a sessionless POST replaces a
session only when its Accept header lists application/json and
text/event-stream as exact media ranges, and a session whose transport
shutdown rejected stays owned so the next close retries it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Addresses the third automated review round: loopback is classified from the
address the listener bound with the configured name added to the Host and
Origin allowlist; scoped IPv6 literals are refused before binding and a URL
that cannot be formed closes the listener; listener errors reach onerror only
after a successful bind; the MCP runtime keeps its factory owner as the single
owner of instance cleanup through `closeInstance: false`.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Addresses the second automated review round: a sessionless POST replaces a
session only when its media type proper is application/json, and the server
instance is created after the listener binds so a bind failure leaves nothing
to clean up and a factory failure releases the listener.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Addresses the automated review findings on the PR: refuse requests once the
session slot is closed and join an arming initialize during shutdown; retry
failed close stages instead of replaying the rejection; classify loopback
binds by address class and add the bind's own hostname to the Host and Origin
allowlist; let only a POST with the streamable headers replace an open
session; announce the bound URL at every log level; route `mcp -h --http` to
the HTTP entry.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Add rea mcp --http [--host] [--port]: the same server rea speaks over stdio,
served over MCP Streamable HTTP on a loopback listener by default, using the
SDK's web-standard transport already in the pinned @modelcontextprotocol/server
behind a small node:http bridge. One client and one session at a time; DELETE
ends the session without running provider teardown, a new client's initialize
replaces a session left open, foreign Host headers are refused on loopback
binds, and shutdown is signals-only. Stdio stays the default and registered
transport; server.json and client registrations are unchanged.
Refs morluto/rea#4933
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>