[Doc] Update Rails controller example in README.md

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 https://github.com/modelcontextprotocol/ruby-sdk/pull/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.
This commit is contained in:
Koichi ITO 2026-04-05 19:03:43 +09:00
commit 17604beff9

View file

@ -113,7 +113,7 @@ You can use `StreamableHTTPTransport#handle_request` to handle requests with pro
status codes (e.g., 202 Accepted for notifications).
```ruby
class McpController < ActionController::Base
class McpController < ActionController::API
def create
server = MCP::Server.new(
name: "my_server",
@ -124,7 +124,8 @@ class McpController < ActionController::Base
prompts: [MyPrompt],
server_context: { user_id: current_user.id },
)
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
# Since the `MCP-Session-Id` is not shared across requests, `stateless: true` is set.
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server, stateless: true)
server.transport = transport
status, headers, body = transport.handle_request(request)