Skip to content

Commit 4f2d056

Browse files
committed
Auto-set server.transport in Transport#initialize
## Motivation and Context Transport subclasses (StreamableHTTPTransport, StdioTransport) already receive the server in their constructor, but users must manually call `server.transport = transport` after creating a transport instance. This is boilerplate that can be eliminated by setting the connection automatically in `Transport#initialize`. ## How Has This Been Tested? All existing tests pass. Redundant `server.transport = transport` lines were removed from tests, examples, README.md, and conformance server. ## Breaking Changes None. Existing code that manually sets `server.transport = transport` continues to work (idempotent assignment).
1 parent 2822e00 commit 4f2d056

12 files changed

+62
-37
lines changed

README.md

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ class McpController < ActionController::API
126126
)
127127
# Since the `MCP-Session-Id` is not shared across requests, `stateless: true` is set.
128128
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server, stateless: true)
129-
server.transport = transport
130129
status, headers, body = transport.handle_request(request)
131130

132131
render(json: body.first, status: status, headers: headers)
@@ -821,7 +820,61 @@ This enables servers to leverage the client's LLM capabilities without needing d
821820
- **Tool Support**: When using tools in sampling requests, clients must declare `sampling.tools` capability
822821
- **Human-in-the-Loop**: Clients can implement user approval before forwarding requests to LLMs
823822

824-
**Using Sampling in Tools:**
823+
**Usage Example (Stdio transport):**
824+
825+
`Server#create_sampling_message` is for single-client transports (e.g., `StdioTransport`).
826+
For multi-client transports (e.g., `StreamableHTTPTransport`), use `server_context.create_sampling_message` inside tools instead,
827+
which routes the request to the correct client session.
828+
829+
```ruby
830+
server = MCP::Server.new(name: "my_server")
831+
transport = MCP::Server::Transports::StdioTransport.new(server)
832+
```
833+
834+
Client must declare sampling capability during initialization.
835+
This happens automatically when the client connects.
836+
837+
```ruby
838+
result = server.create_sampling_message(
839+
messages: [
840+
{ role: "user", content: { type: "text", text: "What is the capital of France?" } }
841+
],
842+
max_tokens: 100,
843+
system_prompt: "You are a helpful assistant.",
844+
temperature: 0.7
845+
)
846+
```
847+
848+
Result contains the LLM response:
849+
850+
```ruby
851+
{
852+
role: "assistant",
853+
content: { type: "text", text: "The capital of France is Paris." },
854+
model: "claude-3-sonnet-20240307",
855+
stopReason: "endTurn"
856+
}
857+
```
858+
859+
**Parameters:**
860+
861+
Required:
862+
863+
- `messages:` (Array) - Array of message objects with `role` and `content`
864+
- `max_tokens:` (Integer) - Maximum tokens in the response
865+
866+
Optional:
867+
868+
- `system_prompt:` (String) - System prompt for the LLM
869+
- `model_preferences:` (Hash) - Model selection preferences (e.g., `{ intelligencePriority: 0.8 }`)
870+
- `include_context:` (String) - Context inclusion: `"none"`, `"thisServer"`, or `"allServers"` (soft-deprecated)
871+
- `temperature:` (Float) - Sampling temperature
872+
- `stop_sequences:` (Array) - Sequences that stop generation
873+
- `metadata:` (Hash) - Additional metadata
874+
- `tools:` (Array) - Tools available to the LLM (requires `sampling.tools` capability)
875+
- `tool_choice:` (Hash) - Tool selection mode (e.g., `{ mode: "auto" }`)
876+
877+
**Using Sampling in Tools (works with both Stdio and HTTP transports):**
825878

826879
Tools that accept a `server_context:` parameter can call `create_sampling_message` on it.
827880
The request is automatically routed to the correct client session.
@@ -1120,7 +1173,6 @@ For more details, see the [MCP Logging specification](https://modelcontextprotoc
11201173
```ruby
11211174
server = MCP::Server.new(name: "my_server")
11221175
transport = MCP::Server::Transports::StdioTransport.new(server)
1123-
server.transport = transport
11241176

11251177
# The client first configures the logging level (on the client side):
11261178
transport.send_request(
@@ -1174,8 +1226,6 @@ server = MCP::Server.new(name: "my_server")
11741226
# Default Streamable HTTP - session oriented
11751227
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
11761228

1177-
server.transport = transport
1178-
11791229
# When tools change, notify clients
11801230
server.define_tool(name: "new_tool") { |**args| { result: "ok" } }
11811231
server.notify_tools_list_changed

conformance/server.rb

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ def initialize(port: DEFAULT_PORT)
394394

395395
def start
396396
server = build_server
397-
transport = build_transport(server)
397+
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
398398
configure_handlers(server)
399399
rack_app = build_rack_app(transport)
400400

@@ -480,12 +480,6 @@ def resource_templates
480480
]
481481
end
482482

483-
def build_transport(server)
484-
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
485-
server.transport = transport
486-
transport
487-
end
488-
489483
def configure_handlers(server)
490484
server.logging_message_notification = MCP::LoggingMessageNotification.new(level: "debug")
491485
server.server_context = server

examples/http_server.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ def template(args, server_context:)
9494

9595
# Create the Streamable HTTP transport
9696
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
97-
server.transport = transport
9897

9998
# Create a logger for MCP-specific logging
10099
mcp_logger = Logger.new($stdout)

examples/streamable_http_server.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ def call(message:, delay: 0)
6363

6464
# Create the Streamable HTTP transport
6565
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
66-
server.transport = transport
6766

6867
# Create a logger for MCP request/response logging
6968
mcp_logger = Logger.new($stdout)

lib/mcp/transport.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class Transport
77
# Initialize the transport with the server instance
88
def initialize(server)
99
@server = server
10+
server.transport = self
1011
end
1112

1213
# Send a response to the client

test/mcp/progress_test.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ def handle_request(request); end
2626
setup do
2727
@server = Server.new(name: "test_server")
2828
@transport = MockTransport.new(@server)
29-
@server.transport = @transport
3029
@session = ServerSession.new(server: @server, transport: @transport)
3130
end
3231

test/mcp/server/transports/stdio_notification_integration_test.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ def closed?
6161
resources: [],
6262
)
6363
@transport = StdioTransport.new(@server)
64-
@server.transport = @transport
6564
end
6665

6766
teardown do

test/mcp/server/transports/streamable_http_notification_integration_test.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ class StreamableHTTPNotificationIntegrationTest < ActiveSupport::TestCase
1515
resources: [],
1616
)
1717
@transport = StreamableHTTPTransport.new(@server)
18-
@server.transport = @transport
1918
end
2019

2120
test "server notification methods send SSE notifications through HTTP transport" do

test/mcp/server/transports/streamable_http_transport_test.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2591,7 +2591,6 @@ def string
25912591
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
25922592
server.logging_message_notification = MCP::LoggingMessageNotification.new(level: "debug")
25932593
transport = StreamableHTTPTransport.new(server)
2594-
server.transport = transport
25952594

25962595
server.define_tool(name: "log_tool") do |server_context:|
25972596
server_context.notify_log_message(data: "secret", level: "info")
@@ -2668,7 +2667,6 @@ def string
26682667
test "session-scoped progress notification is sent only to the originating session" do
26692668
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
26702669
transport = StreamableHTTPTransport.new(server)
2671-
server.transport = transport
26722670

26732671
server.define_tool(name: "progress_tool") do |server_context:|
26742672
server_context.report_progress(50, total: 100, message: "halfway")
@@ -2749,7 +2747,6 @@ def string
27492747
test "each session stores its own client info independently" do
27502748
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
27512749
transport = StreamableHTTPTransport.new(server)
2752-
server.transport = transport
27532750

27542751
# Initialize session 1 with client "alpha".
27552752
init1 = create_rack_request(
@@ -2794,7 +2791,6 @@ def string
27942791
test "each session stores its own logging level independently" do
27952792
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
27962793
transport = StreamableHTTPTransport.new(server)
2797-
server.transport = transport
27982794

27992795
# Initialize two sessions.
28002796
init1 = create_rack_request(

test/mcp/server_notification_test.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ def handle_request(request); end
3636
)
3737

3838
@mock_transport = MockTransport.new(@server)
39-
@server.transport = @mock_transport
4039
end
4140

4241
test "#notify_tools_list_changed sends notification through transport" do
@@ -122,14 +121,13 @@ def handle_request(request); end
122121
end
123122

124123
test "notification methods handle transport errors gracefully" do
125-
# Create a transport that raises errors
126-
error_transport = Class.new(MockTransport) do
124+
# Replace server's transport with one that raises on send_notification.
125+
Class.new(MockTransport) do
127126
def send_notification(method, params = nil)
128127
raise StandardError, "Transport error"
129128
end
130129
end.new(@server)
131130

132-
@server.transport = error_transport
133131
@server.logging_message_notification = MCP::LoggingMessageNotification.new(level: "error")
134132

135133
# Mock the exception reporter

0 commit comments

Comments
 (0)