Repository navigation
fix(transport): make reference WebSocket tests dual-stack - #79
Conversation
Adds a Node http-based Streamable HTTP transport (POST /mcp, GET /health) alongside the existing stdio/tcp/websocket/unix transports, auto-selected when PORT is set or --http is passed. Auth via RPG_MCP_TRANSPORT_TOKEN, same convention as the tcp/websocket transports.
Stateless StreamableHTTPServerTransport throws 'Stateless transport cannot be reused across requests' after the first POST /mcp, since sharing one transport instance across unrelated HTTP requests violates the SDK's stateless-mode contract (server/webStandardStreamableHttp.js guards this explicitly via _hasHandledRequest). Discovered live against the deployed Railway service: the first initialize succeeded, every call after it returned a bare 500. Extract tool registration into buildServer(pubsub, auditLogger) and call it once per request for the HTTP transport (cheap, no I/O), while stdio/tcp/unix/websocket keep a single long-lived instance.
findLatestForParticipant(characterId, worldId?) was called as (worldId, characterId), so the DM-facing 'current' preview always returned scene: null. Both params are string, so TS could not catch it. Agent auto-injection was unaffected — the prompt composer calls listLatestForParticipant with the correct order. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…works Railway's private network is IPv6-only. A server bound to '0.0.0.0' listens on IPv4 only, so it is reachable on its public domain but NOT on <service>.railway.internal -- peer services get a connection failure with no obvious cause. Default the HTTP host to '::', which Node binds dual-stack (IPv6 + IPv4), so both the private hostname and the public domain work. Still overridable via --host for local/dev binding. Found while wiring rpg-mcp-live to this service: the integration had to fall back to the public domain because the private hostname was unreachable.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (12)
📝 WalkthroughWalkthroughThe PR adds character proficiency schemas, management inputs, defaults, database persistence, and migrations. It adds reusable server construction and stateless HTTP MCP transport support with authentication and health checks. It also adds Railway deployment settings and updates runtime defaults. ChangesCharacter proficiency flow
Server transport and deployment
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant HTTPServer
participant McpServer
participant MCPTransport
Client->>HTTPServer: POST /mcp with authorization
HTTPServer->>McpServer: create server for request
HTTPServer->>MCPTransport: create request transport
MCPTransport->>McpServer: handle MCP request
McpServer-->>Client: return MCP response
HTTPServer->>MCPTransport: close transport when connection closes
Possibly related PRs
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
* feat(transport): add HTTP MCP transport for Railway hosting Adds a Node http-based Streamable HTTP transport (POST /mcp, GET /health) alongside the existing stdio/tcp/websocket/unix transports, auto-selected when PORT is set or --http is passed. Auth via RPG_MCP_TRANSPORT_TOKEN, same convention as the tcp/websocket transports. * fix(transport): build a fresh McpServer+transport per HTTP request Stateless StreamableHTTPServerTransport throws 'Stateless transport cannot be reused across requests' after the first POST /mcp, since sharing one transport instance across unrelated HTTP requests violates the SDK's stateless-mode contract (server/webStandardStreamableHttp.js guards this explicitly via _hasHandledRequest). Discovered live against the deployed Railway service: the first initialize succeeded, every call after it returned a bare 500. Extract tool registration into buildServer(pubsub, auditLogger) and call it once per request for the HTTP transport (cheap, no I/O), while stdio/tcp/unix/websocket keep a single long-lived instance. * fix(scene): swap transposed args in scene_manage action:'current' findLatestForParticipant(characterId, worldId?) was called as (worldId, characterId), so the DM-facing 'current' preview always returned scene: null. Both params are string, so TS could not catch it. Agent auto-injection was unaffected — the prompt composer calls listLatestForParticipant with the correct order. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(transport): bind HTTP transport dual-stack so private networking works Railway's private network is IPv6-only. A server bound to '0.0.0.0' listens on IPv4 only, so it is reachable on its public domain but NOT on <service>.railway.internal -- peer services get a connection failure with no obvious cause. Default the HTTP host to '::', which Node binds dual-stack (IPv6 + IPv4), so both the private hostname and the public domain work. Still overridable via --host for local/dev binding. Found while wiring rpg-mcp-live to this service: the integration had to fall back to the public domain because the private hostname was unreachable. * fix(character): persist proficiencies in reference state * fix(railway): expose reference deployment identity and volume path * fix(transport): bind WebSocket dual-stack by default --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Scope
Bind the reference engine WebSocket transport to the dual-stack host by default so Node 18 localhost resolution to ::1 works alongside IPv4.
Verification
This is required for the reference service CI matrix before Railway deployment.
Summary by CodeRabbit