Make StreamableHTTPTransport a Rack application#263
Conversation
06f5b81 to
361288f
Compare
StreamableHTTPTransport a standard Rack applicationStreamableHTTPTransport a Rack application
0912d7d to
f4961a8
Compare
880daa9 to
40767ff
Compare
40767ff to
11f3534
Compare
The following two points have been updated: ## 1. Use ActionController::API in README controller example `ActionController::Base` includes CSRF protection which rejects POST requests without an authenticity token. MCP clients do not send CSRF tokens, so the controller example should inherit from `ActionController::API` instead. ## 2. Use `stateless: true` for `StreamableHTTPTransport.new` The controller creates a new transport per request, so the session stored on the previous transport is lost. Without `stateless: true`, the second request with `Mcp-Session-Id` returns 404 because the new transport has an empty session map. To share sessions via `Mcp-Session-Id` across requests, there are two approaches. One is persisting the transport in a class variable. The other is mounting the transport as a Rack app via #263. Both approaches maintain sessions, so features that depend on `server_context` within the SDK (Progress, Sampling) work correctly. However, per-request user-specific context such as `server_context: { user_id: current_user.id }` cannot be passed since the server is shared across all requests.
## Motivation and Context Add `call(env)` to `StreamableHTTPTransport`, making it a Rack application that works with `mount`, `run`, and Rack middleware. Refactor examples to use Rack middleware classes for MCP logging instead of proc wrappers, demonstrating idiomatic Rack composition with the new `run(transport)` pattern. Update README.md with mount and controller integration patterns. Closes modelcontextprotocol#59, modelcontextprotocol#60 ## How Has This Been Tested? Added tests for `call(env)` as a Rack app. All tests pass. ## Breaking Change No breaking changes. All existing APIs are preserved: - `StreamableHTTPTransport.new(server)` continues to work as before. - `handle_request(request)` is unchanged. The new `call(env)` is a purely additive public method.
11f3534 to
af99a30
Compare
|
@modelcontextprotocol/ruby-sdk In practice, when using stateful Streamable HTTP with It would be possible to provide a separate Rack app API that wraps If this can be merged, it should lower the barrier to implementing servers with the MCP Ruby SDK. A review would be appreciated when convenient. |
jonathanhefner
left a comment
There was a problem hiding this comment.
Vibe-reviewed. Claude says: "This is a well-scoped, well-tested PR. The core change is a 3-line method that follows a standard Ruby pattern (Rack app interface). The frozen-headers fix addresses a real bug. The example refactoring to proper middleware classes is more idiomatic. The README additions clearly explain both integration patterns."
Motivation and Context
Add
call(env)toStreamableHTTPTransport, making it a Rack application that works withmount,run, and Rack middleware.Refactor examples to use Rack middleware classes for MCP logging instead of proc wrappers, demonstrating idiomatic Rack composition with the new
run(transport)pattern.Update README.md with mount and controller integration patterns.
Closes #59, #60
How Has This Been Tested?
Added tests for
call(env)as a Rack app. All tests pass.Breaking Change
No breaking changes. All existing APIs are preserved:
StreamableHTTPTransport.new(server)continues to work as before.handle_request(request)is unchanged. The newcall(env)is a purely additive public method.Types of changes
Checklist