| Filename | Latest commit message | Latest commit date |
|---|---|---|
## Motivation and Context The Rack 3 SPEC requires response header names to be lowercase. https://github.com/rack/rack/blob/main/SPEC.rdoc says in its "The Headers" section: > Header keys must not contain uppercase ASCII characters (A-Z). https://github.com/rack/rack/blob/main/SPEC.rdoc#the-headers However, `StreamableHTTPTransport` emitted capitalized names such as `Content-Type` and `Mcp-Session-Id`. Any `Rack::Lint`-wrapped stack, including the default development mode of rackup, rejects every response from the transport with a `LintError` 500. Lowercasing the names restores Rack 3 compliance. HTTP header names are case-insensitive on the wire, so HTTP clients are unaffected; only in-process consumers that read the raw Rack headers hash see the new keys. Lowercase is also the only representation valid across HTTP versions: RFC 9113 makes uppercase field names a protocol error on HTTP/2, so proxies and h2-capable servers already require it. The TypeScript SDK sets `headers['mcp-session-id']` and the Python SDK defines `MCP_SESSION_ID_HEADER = "mcp-session-id"`, so lowercase also matches what the reference SDKs emit; the MCP spec's `Mcp-Session-Id` casing is prose convention, not a wire requirement. Examples and documentation deliberately keep the spec's `Mcp-Session-Id` casing where it does not name a Rack response hash key: curl invocations and `examples/streamable_http_client.rb` set request headers, which the Rack response rule does not govern; the rack-cors `expose:` entry carries a header name as an `Access-Control-Expose-Headers` value, which browsers match case-insensitively; and README/docs prose follows the MCP specification's documentation convention. Only code reading the raw Rack response headers hash, a case-sensitive Hash lookup, had to switch to lowercase keys. AGENTS.md now records the lowercase rule under the code style guidelines, since the MCP spec's `Mcp-Session-Id` prose casing invites reintroducing capitalized names in future transport work. ## How Has This Been Tested? Added a regression test asserting that header names are lowercase in initialize, GET SSE, DELETE, and parse error responses. Existing tests that read the raw headers hash were updated to the new keys. Verified with rake test, rake rubocop, and rake conformance. ## Breaking Changes Code that reads the raw Rack response headers hash returned by `handle_request`, or by middleware around the mounted transport, with exact-case keys such as `"Mcp-Session-Id"` must switch to the lowercase keys. Clients speaking HTTP are unaffected because header names are case-insensitive on the wire. |
||
| .. | ||
| rails | ||
| http_client.rb | ||
| http_server.rb | ||
| README.md | ||
| stdio_client.rb | ||
| stdio_server.rb | ||
| streamable_http_client.rb | ||
| streamable_http_server.rb | ||
MCP Ruby Examples
This directory contains examples of how to use the Model Context Protocol (MCP) Ruby library.
Available Examples
1. stdio Server (stdio_server.rb)
A simple server that communicates over standard input/output. This is useful for desktop applications and command-line tools.
Usage:
$ ruby examples/stdio_server.rb
{"jsonrpc":"2.0","id":0,"method":"tools/list"}
2. stdio Client (stdio_client.rb)
A client that connects to the stdio server using the MCP::Client::Stdio transport.
This demonstrates how to use the SDK's built-in client classes to interact with a server subprocess.
Usage:
$ ruby examples/stdio_client.rb
The client will automatically launch stdio_server.rb as a subprocess and demonstrate:
- Performing the MCP initialization handshake via
client.connect - Listing and calling tools
- Listing prompts
- Listing and reading resources
- Transport cleanup on exit
3. HTTP Server (http_server.rb)
A standalone HTTP server built with Rack that implements the MCP Streamable HTTP transport protocol. This demonstrates how to create a web-based MCP server with session management and Server-Sent Events (SSE) support.
Features:
- HTTP transport with Server-Sent Events (SSE) for streaming
- Session management with unique session IDs
- Example tools, prompts, and resources
- JSON-RPC 2.0 protocol implementation
- Full MCP protocol compliance
Usage:
$ ruby examples/http_server.rb
The server will start on http://localhost:9292 and provide:
- Tools:
example_tool- adds two numbersecho- echoes back messages
- Prompts:
example_prompt- echoes back arguments as a prompt - Resources:
test_resource- returns example content
4. HTTP Client Example (http_client.rb)
A client that demonstrates how to interact with the HTTP server using all MCP protocol methods.
Usage:
-
Start the HTTP server in one terminal:
$ ruby examples/http_server.rb -
Run the client example in another terminal:
$ ruby examples/http_client.rb
The client will demonstrate:
- Session initialization
- Ping requests
- Listing and calling tools
- Listing and getting prompts
- Listing and reading resources
- Session cleanup
5. Streamable HTTP Server (streamable_http_server.rb)
A specialized HTTP server designed to test and demonstrate Server-Sent Events (SSE) functionality in the MCP protocol.
Features:
- Tools specifically designed to trigger SSE notifications
- Real-time progress updates and notifications
- Detailed SSE-specific logging
Available Tools:
notification_tool- Send custom SSE notifications with optional delaysecho- Simple echo tool for basic testing
Usage:
$ ruby examples/streamable_http_server.rb
The server will start on http://localhost:9393 and provide detailed instructions for testing SSE functionality.
6. Streamable HTTP Client (streamable_http_client.rb)
An interactive client that connects to the SSE stream and provides a menu-driven interface for testing SSE functionality.
Features:
- Automatic SSE stream connection
- Interactive menu for triggering various SSE events
- Real-time display of received SSE notifications
- Session management
Usage:
-
Start the SSE test server in one terminal:
$ ruby examples/streamable_http_server.rb -
Run the SSE test client in another terminal:
$ ruby examples/streamable_http_client.rb
The client will:
- Initialize a session automatically
- Connect to the SSE stream
- Provide an interactive menu to trigger notifications
- Display all received SSE events in real-time
7. Rails Server (rails/)
A minimal Rails application that mounts StreamableHTTPTransport in its routes, following the "Rails (mount)" pattern from the top-level README.
It demonstrates class-based tools in app/tools/ and a resource with a read handler.
Usage:
$ cd examples/rails
$ bundle install
$ bundle exec puma --port 9292
The MCP endpoint is available at http://localhost:9292/mcp. See rails/README.md for a full curl-based walkthrough.
Testing with MCP Inspector
MCP Inspector is a browser-based tool for testing and debugging MCP servers.
- Start the server:
$ ruby examples/streamable_http_server.rb
- Start Inspector in another terminal:
$ npx @modelcontextprotocol/inspector
- Open
http://localhost:6274in a browser:
- Set Transport Type to "Streamable HTTP"
- Set URL to
http://localhost:9393 - Disable the Authorization header toggle (the example server does not require authentication)
- Click "Connect"
Once connected, you can list tools, call them, and see SSE notifications in the Inspector UI.
Testing SSE with cURL
You can also test SSE functionality manually using cURL:
- Initialize a session:
SESSION_ID=$(curl -D - -s -o /dev/null http://localhost:9393 \
--json '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl-test","version":"1.0"}}}' | grep -i "Mcp-Session-Id:" | cut -d' ' -f2- | tr -d '\r')
- Connect to SSE stream (in one terminal):
curl -i -N -H "Mcp-Session-Id: $SESSION_ID" http://localhost:9393
- Trigger notifications (in another terminal):
# Send immediate notification
curl -i http://localhost:9393 \
-H "Mcp-Session-Id: $SESSION_ID" \
--json '{"jsonrpc":"2.0","method":"tools/call","id":2,"params":{"name":"notification_tool","arguments":{"message":"Hello from cURL!"}}}'
Streamable HTTP Transport Details
Protocol Flow
The HTTP server implements the MCP Streamable HTTP transport protocol:
-
Initialize Session:
- Client sends POST request with
initializemethod - Server responds with session ID in
Mcp-Session-Idheader
- Client sends POST request with
-
Establish SSE Connection (optional):
- Client sends GET request with
Mcp-Session-Idheader - Server establishes Server-Sent Events stream for notifications
- Client sends GET request with
-
Send Requests:
- Client sends POST requests with JSON-RPC 2.0 format
- Server processes and responds with results
-
Close Session:
- Client sends DELETE request with
Mcp-Session-Idheader
- Client sends DELETE request with
Example cURL Commands
Initialize a session:
curl -i http://localhost:9292 \
--json '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
List tools (using the session ID from initialization):
curl -i http://localhost:9292 \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
--json '{"jsonrpc":"2.0","method":"tools/list","id":2}'
Call a tool:
curl -i http://localhost:9292 \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
--json '{"jsonrpc":"2.0","method":"tools/call","id":3,"params":{"name":"example_tool","arguments":{"a":5,"b":3}}}'