Merge pull request #305 from koic/auto_set_server_transport
Auto-set `server.transport` in `Transport#initialize`
This commit is contained in:
commit
89281cac57
12 changed files with 10 additions and 36 deletions
|
|
@ -126,7 +126,6 @@ class McpController < ActionController::API
|
||||||
)
|
)
|
||||||
# Since the `MCP-Session-Id` is not shared across requests, `stateless: true` is set.
|
# Since the `MCP-Session-Id` is not shared across requests, `stateless: true` is set.
|
||||||
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server, stateless: true)
|
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server, stateless: true)
|
||||||
server.transport = transport
|
|
||||||
status, headers, body = transport.handle_request(request)
|
status, headers, body = transport.handle_request(request)
|
||||||
|
|
||||||
render(json: body.first, status: status, headers: headers)
|
render(json: body.first, status: status, headers: headers)
|
||||||
|
|
@ -1120,7 +1119,6 @@ For more details, see the [MCP Logging specification](https://modelcontextprotoc
|
||||||
```ruby
|
```ruby
|
||||||
server = MCP::Server.new(name: "my_server")
|
server = MCP::Server.new(name: "my_server")
|
||||||
transport = MCP::Server::Transports::StdioTransport.new(server)
|
transport = MCP::Server::Transports::StdioTransport.new(server)
|
||||||
server.transport = transport
|
|
||||||
|
|
||||||
# The client first configures the logging level (on the client side):
|
# The client first configures the logging level (on the client side):
|
||||||
transport.send_request(
|
transport.send_request(
|
||||||
|
|
@ -1174,8 +1172,6 @@ server = MCP::Server.new(name: "my_server")
|
||||||
# Default Streamable HTTP - session oriented
|
# Default Streamable HTTP - session oriented
|
||||||
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
||||||
|
|
||||||
server.transport = transport
|
|
||||||
|
|
||||||
# When tools change, notify clients
|
# When tools change, notify clients
|
||||||
server.define_tool(name: "new_tool") { |**args| { result: "ok" } }
|
server.define_tool(name: "new_tool") { |**args| { result: "ok" } }
|
||||||
server.notify_tools_list_changed
|
server.notify_tools_list_changed
|
||||||
|
|
|
||||||
|
|
@ -394,7 +394,7 @@ module Conformance
|
||||||
|
|
||||||
def start
|
def start
|
||||||
server = build_server
|
server = build_server
|
||||||
transport = build_transport(server)
|
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
||||||
configure_handlers(server)
|
configure_handlers(server)
|
||||||
rack_app = build_rack_app(transport)
|
rack_app = build_rack_app(transport)
|
||||||
|
|
||||||
|
|
@ -480,12 +480,6 @@ module Conformance
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_transport(server)
|
|
||||||
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
|
||||||
server.transport = transport
|
|
||||||
transport
|
|
||||||
end
|
|
||||||
|
|
||||||
def configure_handlers(server)
|
def configure_handlers(server)
|
||||||
server.logging_message_notification = MCP::LoggingMessageNotification.new(level: "debug")
|
server.logging_message_notification = MCP::LoggingMessageNotification.new(level: "debug")
|
||||||
server.server_context = server
|
server.server_context = server
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,6 @@ end
|
||||||
|
|
||||||
# Create the Streamable HTTP transport
|
# Create the Streamable HTTP transport
|
||||||
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
||||||
server.transport = transport
|
|
||||||
|
|
||||||
# Create a logger for MCP-specific logging
|
# Create a logger for MCP-specific logging
|
||||||
mcp_logger = Logger.new($stdout)
|
mcp_logger = Logger.new($stdout)
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ end
|
||||||
|
|
||||||
# Create the Streamable HTTP transport
|
# Create the Streamable HTTP transport
|
||||||
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
||||||
server.transport = transport
|
|
||||||
|
|
||||||
# Create a logger for MCP request/response logging
|
# Create a logger for MCP request/response logging
|
||||||
mcp_logger = Logger.new($stdout)
|
mcp_logger = Logger.new($stdout)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ module MCP
|
||||||
# Initialize the transport with the server instance
|
# Initialize the transport with the server instance
|
||||||
def initialize(server)
|
def initialize(server)
|
||||||
@server = server
|
@server = server
|
||||||
|
server.transport = self
|
||||||
end
|
end
|
||||||
|
|
||||||
# Send a response to the client
|
# Send a response to the client
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ module MCP
|
||||||
setup do
|
setup do
|
||||||
@server = Server.new(name: "test_server")
|
@server = Server.new(name: "test_server")
|
||||||
@transport = MockTransport.new(@server)
|
@transport = MockTransport.new(@server)
|
||||||
@server.transport = @transport
|
|
||||||
@session = ServerSession.new(server: @server, transport: @transport)
|
@session = ServerSession.new(server: @server, transport: @transport)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ module MCP
|
||||||
resources: [],
|
resources: [],
|
||||||
)
|
)
|
||||||
@transport = StdioTransport.new(@server)
|
@transport = StdioTransport.new(@server)
|
||||||
@server.transport = @transport
|
|
||||||
end
|
end
|
||||||
|
|
||||||
teardown do
|
teardown do
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ module MCP
|
||||||
resources: [],
|
resources: [],
|
||||||
)
|
)
|
||||||
@transport = StreamableHTTPTransport.new(@server)
|
@transport = StreamableHTTPTransport.new(@server)
|
||||||
@server.transport = @transport
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "server notification methods send SSE notifications through HTTP transport" do
|
test "server notification methods send SSE notifications through HTTP transport" do
|
||||||
|
|
|
||||||
|
|
@ -2591,7 +2591,6 @@ module MCP
|
||||||
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
|
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
|
||||||
server.logging_message_notification = MCP::LoggingMessageNotification.new(level: "debug")
|
server.logging_message_notification = MCP::LoggingMessageNotification.new(level: "debug")
|
||||||
transport = StreamableHTTPTransport.new(server)
|
transport = StreamableHTTPTransport.new(server)
|
||||||
server.transport = transport
|
|
||||||
|
|
||||||
server.define_tool(name: "log_tool") do |server_context:|
|
server.define_tool(name: "log_tool") do |server_context:|
|
||||||
server_context.notify_log_message(data: "secret", level: "info")
|
server_context.notify_log_message(data: "secret", level: "info")
|
||||||
|
|
@ -2668,7 +2667,6 @@ module MCP
|
||||||
test "session-scoped progress notification is sent only to the originating session" do
|
test "session-scoped progress notification is sent only to the originating session" do
|
||||||
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
|
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
|
||||||
transport = StreamableHTTPTransport.new(server)
|
transport = StreamableHTTPTransport.new(server)
|
||||||
server.transport = transport
|
|
||||||
|
|
||||||
server.define_tool(name: "progress_tool") do |server_context:|
|
server.define_tool(name: "progress_tool") do |server_context:|
|
||||||
server_context.report_progress(50, total: 100, message: "halfway")
|
server_context.report_progress(50, total: 100, message: "halfway")
|
||||||
|
|
@ -2749,7 +2747,6 @@ module MCP
|
||||||
test "each session stores its own client info independently" do
|
test "each session stores its own client info independently" do
|
||||||
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
|
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
|
||||||
transport = StreamableHTTPTransport.new(server)
|
transport = StreamableHTTPTransport.new(server)
|
||||||
server.transport = transport
|
|
||||||
|
|
||||||
# Initialize session 1 with client "alpha".
|
# Initialize session 1 with client "alpha".
|
||||||
init1 = create_rack_request(
|
init1 = create_rack_request(
|
||||||
|
|
@ -2794,7 +2791,6 @@ module MCP
|
||||||
test "each session stores its own logging level independently" do
|
test "each session stores its own logging level independently" do
|
||||||
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
|
server = Server.new(name: "test", tools: [], prompts: [], resources: [])
|
||||||
transport = StreamableHTTPTransport.new(server)
|
transport = StreamableHTTPTransport.new(server)
|
||||||
server.transport = transport
|
|
||||||
|
|
||||||
# Initialize two sessions.
|
# Initialize two sessions.
|
||||||
init1 = create_rack_request(
|
init1 = create_rack_request(
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ module MCP
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock_transport = MockTransport.new(@server)
|
@mock_transport = MockTransport.new(@server)
|
||||||
@server.transport = @mock_transport
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "#notify_tools_list_changed sends notification through transport" do
|
test "#notify_tools_list_changed sends notification through transport" do
|
||||||
|
|
@ -122,14 +121,13 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
test "notification methods handle transport errors gracefully" do
|
test "notification methods handle transport errors gracefully" do
|
||||||
# Create a transport that raises errors
|
# Replace server's transport with one that raises on send_notification.
|
||||||
error_transport = Class.new(MockTransport) do
|
Class.new(MockTransport) do
|
||||||
def send_notification(method, params = nil)
|
def send_notification(method, params = nil)
|
||||||
raise StandardError, "Transport error"
|
raise StandardError, "Transport error"
|
||||||
end
|
end
|
||||||
end.new(@server)
|
end.new(@server)
|
||||||
|
|
||||||
@server.transport = error_transport
|
|
||||||
@server.logging_message_notification = MCP::LoggingMessageNotification.new(level: "error")
|
@server.logging_message_notification = MCP::LoggingMessageNotification.new(level: "error")
|
||||||
|
|
||||||
# Mock the exception reporter
|
# Mock the exception reporter
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,6 @@ module MCP
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock_transport = MockTransport.new(@server)
|
@mock_transport = MockTransport.new(@server)
|
||||||
@server.transport = @mock_transport
|
|
||||||
@session = ServerSession.new(server: @server, transport: @mock_transport)
|
@session = ServerSession.new(server: @server, transport: @mock_transport)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ module MCP
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock_transport = MockTransport.new(@server)
|
@mock_transport = MockTransport.new(@server)
|
||||||
@server.transport = @mock_transport
|
|
||||||
|
|
||||||
# Simulate client initialization with sampling capability.
|
# Simulate client initialization with sampling capability.
|
||||||
@server.handle({
|
@server.handle({
|
||||||
|
|
@ -197,8 +196,8 @@ module MCP
|
||||||
|
|
||||||
test "init with sampling capability allows create_sampling_message" do
|
test "init with sampling capability allows create_sampling_message" do
|
||||||
server = Server.new(name: "test", version: "1.0")
|
server = Server.new(name: "test", version: "1.0")
|
||||||
mock_transport = MockTransport.new(server)
|
# Assigns server.transport via Transport#initialize, which create_sampling_message requires.
|
||||||
server.transport = mock_transport
|
MockTransport.new(server)
|
||||||
|
|
||||||
server.handle({
|
server.handle({
|
||||||
jsonrpc: "2.0",
|
jsonrpc: "2.0",
|
||||||
|
|
@ -222,8 +221,8 @@ module MCP
|
||||||
|
|
||||||
test "init without capabilities rejects create_sampling_message" do
|
test "init without capabilities rejects create_sampling_message" do
|
||||||
server = Server.new(name: "test", version: "1.0")
|
server = Server.new(name: "test", version: "1.0")
|
||||||
mock_transport = MockTransport.new(server)
|
# Assigns server.transport via Transport#initialize, which create_sampling_message requires.
|
||||||
server.transport = mock_transport
|
MockTransport.new(server)
|
||||||
|
|
||||||
server.handle({
|
server.handle({
|
||||||
jsonrpc: "2.0",
|
jsonrpc: "2.0",
|
||||||
|
|
@ -247,7 +246,6 @@ module MCP
|
||||||
|
|
||||||
test "create_sampling_message uses per-session capabilities via ServerSession" do
|
test "create_sampling_message uses per-session capabilities via ServerSession" do
|
||||||
transport = MCP::Server::Transports::StreamableHTTPTransport.new(@server)
|
transport = MCP::Server::Transports::StreamableHTTPTransport.new(@server)
|
||||||
@server.transport = transport
|
|
||||||
|
|
||||||
# Session with sampling capability passes validation (fails at send_request due to no stream).
|
# Session with sampling capability passes validation (fails at send_request due to no stream).
|
||||||
session_with_sampling = ServerSession.new(server: @server, transport: transport, session_id: "s1")
|
session_with_sampling = ServerSession.new(server: @server, transport: transport, session_id: "s1")
|
||||||
|
|
@ -277,7 +275,6 @@ module MCP
|
||||||
|
|
||||||
test "ServerSession#client_capabilities falls back to server global capabilities" do
|
test "ServerSession#client_capabilities falls back to server global capabilities" do
|
||||||
transport = MCP::Server::Transports::StreamableHTTPTransport.new(@server)
|
transport = MCP::Server::Transports::StreamableHTTPTransport.new(@server)
|
||||||
@server.transport = transport
|
|
||||||
|
|
||||||
# Session without capabilities stored falls back to @server.client_capabilities.
|
# Session without capabilities stored falls back to @server.client_capabilities.
|
||||||
session = ServerSession.new(server: @server, transport: transport, session_id: "s3")
|
session = ServerSession.new(server: @server, transport: transport, session_id: "s3")
|
||||||
|
|
@ -295,8 +292,8 @@ module MCP
|
||||||
|
|
||||||
test "session init does not overwrite server global client_capabilities" do
|
test "session init does not overwrite server global client_capabilities" do
|
||||||
server = Server.new(name: "test", version: "1.0")
|
server = Server.new(name: "test", version: "1.0")
|
||||||
mock_transport = MockTransport.new(server)
|
# Assigns server.transport via Transport#initialize, which create_sampling_message requires.
|
||||||
server.transport = mock_transport
|
MockTransport.new(server)
|
||||||
|
|
||||||
# Non-session init sets global capabilities.
|
# Non-session init sets global capabilities.
|
||||||
server.handle({
|
server.handle({
|
||||||
|
|
@ -314,7 +311,6 @@ module MCP
|
||||||
|
|
||||||
# Session-scoped init must NOT overwrite global capabilities.
|
# Session-scoped init must NOT overwrite global capabilities.
|
||||||
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
||||||
server.transport = transport
|
|
||||||
session = ServerSession.new(server: server, transport: transport, session_id: "s1")
|
session = ServerSession.new(server: server, transport: transport, session_id: "s1")
|
||||||
|
|
||||||
server.handle(
|
server.handle(
|
||||||
|
|
@ -340,7 +336,6 @@ module MCP
|
||||||
test "Server#create_sampling_message does not see session-scoped capabilities from HTTP init" do
|
test "Server#create_sampling_message does not see session-scoped capabilities from HTTP init" do
|
||||||
server = Server.new(name: "test", version: "1.0")
|
server = Server.new(name: "test", version: "1.0")
|
||||||
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
||||||
server.transport = transport
|
|
||||||
|
|
||||||
# HTTP init stores capabilities on the session, not on the server.
|
# HTTP init stores capabilities on the session, not on the server.
|
||||||
session = ServerSession.new(server: server, transport: transport, session_id: "s1")
|
session = ServerSession.new(server: server, transport: transport, session_id: "s1")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue