@@ -65,70 +65,57 @@ def call(message:, delay: 0)
6565transport = MCP ::Server ::Transports ::StreamableHTTPTransport . new ( server )
6666server . transport = transport
6767
68- # Create a logger for MCP request/response logging
69- mcp_logger = Logger . new ( $stdout)
70- mcp_logger . formatter = proc do |_severity , _datetime , _progname , msg |
71- "[MCP] #{ msg } \n "
72- end
68+ # Rack middleware for MCP request/response and SSE logging
69+ class McpSseLogger
70+ def initialize ( app )
71+ @app = app
72+ @mcp_logger = Logger . new ( $stdout)
73+ @mcp_logger . formatter = proc { |_sev , _dt , _prog , msg | "[MCP] #{ msg } \n " }
74+ @sse_logger = Logger . new ( $stdout)
75+ @sse_logger . formatter = proc { |sev , dt , _prog , msg | "[SSE] #{ sev } #{ dt . strftime ( "%H:%M:%S.%L" ) } - #{ msg } \n " }
76+ end
7377
74- # Create the Rack application
75- app = proc do |env |
76- request = Rack ::Request . new ( env )
77-
78- # Log request details
79- if request . post?
80- body = request . body . read
81- request . body . rewind
82- begin
83- parsed_body = JSON . parse ( body )
84- mcp_logger . info ( "Request: #{ parsed_body [ "method" ] } (id: #{ parsed_body [ "id" ] } )" )
85-
86- # Log SSE-specific setup
87- if parsed_body [ "method" ] == "initialize"
88- sse_logger . info ( "New client initializing session" )
78+ def call ( env )
79+ if env [ "REQUEST_METHOD" ] == "POST"
80+ body = env [ "rack.input" ] . read
81+ env [ "rack.input" ] . rewind
82+ begin
83+ parsed = JSON . parse ( body )
84+ @mcp_logger . info ( "Request: #{ parsed [ "method" ] } (id: #{ parsed [ "id" ] } )" )
85+ @sse_logger . info ( "New client initializing session" ) if parsed [ "method" ] == "initialize"
86+ rescue JSON ::ParserError
87+ @mcp_logger . warn ( "Invalid JSON in request" )
8988 end
90- rescue JSON ::ParserError
91- mcp_logger . warn ( "Invalid JSON in request" )
89+ elsif env [ "REQUEST_METHOD" ] == "GET"
90+ session_id = env [ "HTTP_MCP_SESSION_ID" ] ||
91+ Rack ::Utils . parse_query ( env [ "QUERY_STRING" ] ) [ "sessionId" ]
92+ @sse_logger . info ( "SSE connection request for session: #{ session_id } " )
9293 end
93- elsif request . get?
94- session_id = request . env [ "HTTP_MCP_SESSION_ID" ] ||
95- Rack ::Utils . parse_query ( request . env [ "QUERY_STRING" ] ) [ "sessionId" ]
96- sse_logger . info ( "SSE connection request for session: #{ session_id } " )
97- end
9894
99- # Handle the request
100- response = transport . handle_request ( request )
101-
102- # Log response details
103- status , headers , body = response
104- if body . is_a? ( Array ) && !body . empty? && request . post?
105- begin
106- parsed_response = JSON . parse ( body . first )
107- if parsed_response [ "error" ]
108- mcp_logger . error ( "Response error: #{ parsed_response [ "error" ] [ "message" ] } " )
109- elsif parsed_response [ "accepted" ]
110- # Response was sent via SSE
111- server . notify_log_message ( data : { details : "Response accepted and sent via SSE" } , level : "info" )
112- sse_logger . info ( "Response sent via SSE stream" )
113- else
114- mcp_logger . info ( "Response: success (id: #{ parsed_response [ "id" ] } )" )
115-
116- # Log session ID for initialization
117- if headers [ "Mcp-Session-Id" ]
118- sse_logger . info ( "Session created: #{ headers [ "Mcp-Session-Id" ] } " )
95+ status , headers , response_body = @app . call ( env )
96+
97+ if response_body . is_a? ( Array ) && !response_body . empty? && env [ "REQUEST_METHOD" ] == "POST"
98+ begin
99+ parsed = JSON . parse ( response_body . first )
100+ if parsed [ "error" ]
101+ @mcp_logger . error ( "Response error: #{ parsed [ "error" ] [ "message" ] } " )
102+ else
103+ @mcp_logger . info ( "Response: success (id: #{ parsed [ "id" ] } )" )
104+ @sse_logger . info ( "Session created: #{ headers [ "Mcp-Session-Id" ] } " ) if headers [ "Mcp-Session-Id" ]
119105 end
106+ rescue JSON ::ParserError
107+ @mcp_logger . warn ( "Invalid JSON in response" )
120108 end
121- rescue JSON :: ParserError
122- mcp_logger . warn ( "Invalid JSON in response ")
109+ elsif env [ "REQUEST_METHOD" ] == "GET" && status == 200
110+ @sse_logger . info ( "SSE stream established ")
123111 end
124- elsif request . get? && status == 200
125- sse_logger . info ( "SSE stream established" )
126- end
127112
128- response
113+ [ status , headers , response_body ]
114+ end
129115end
130116
131117# Build the Rack application with middleware
118+ # StreamableHTTPTransport responds to `call(env)`, so it can be used directly as a Rack app
132119rack_app = Rack ::Builder . new do
133120 # Enable CORS to allow browser-based MCP clients (e.g., MCP Inspector)
134121 # WARNING: origins("*") allows all origins. Restrict this in production.
@@ -146,7 +133,8 @@ def call(message:, delay: 0)
146133
147134 use ( Rack ::CommonLogger , Logger . new ( $stdout) )
148135 use ( Rack ::ShowExceptions )
149- run ( app )
136+ use ( McpSseLogger )
137+ run ( transport )
150138end
151139
152140# Print usage instructions
0 commit comments