@@ -65,70 +65,62 @@ 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+
73+ @mcp_logger = Logger . new ( $stdout)
74+ @mcp_logger . formatter = proc { |_severity , _datetime , _progname , msg | "[MCP] #{ msg } \n " }
75+
76+ @sse_logger = Logger . new ( $stdout)
77+ @sse_logger . formatter = proc { |severity , datetime , _progname , msg | "[SSE] #{ severity } #{ datetime . strftime ( "%H:%M:%S.%L" ) } - #{ msg } \n " }
78+ end
7379
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" )
80+ def call ( env )
81+ if env [ "REQUEST_METHOD" ] == "POST"
82+ body = env [ "rack.input" ] . read
83+ env [ "rack.input" ] . rewind
84+
85+ begin
86+ parsed = JSON . parse ( body )
87+
88+ @mcp_logger . info ( "Request: #{ parsed [ "method" ] } (id: #{ parsed [ "id" ] } )" )
89+ @sse_logger . info ( "New client initializing session" ) if parsed [ "method" ] == "initialize"
90+ rescue JSON ::ParserError
91+ @mcp_logger . warn ( "Invalid JSON in request" )
8992 end
90- rescue JSON ::ParserError
91- mcp_logger . warn ( "Invalid JSON in request" )
93+ elsif env [ "REQUEST_METHOD" ] == "GET"
94+ session_id = env [ "HTTP_MCP_SESSION_ID" ] || Rack ::Utils . parse_query ( env [ "QUERY_STRING" ] ) [ "sessionId" ]
95+
96+ @sse_logger . info ( "SSE connection request for session: #{ session_id } " )
9297 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
9898
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" ] } " )
99+ status , headers , response_body = @app . call ( env )
100+
101+ if response_body . is_a? ( Array ) && !response_body . empty? && env [ "REQUEST_METHOD" ] == "POST"
102+ begin
103+ parsed = JSON . parse ( response_body . first )
104+
105+ if parsed [ "error" ]
106+ @mcp_logger . error ( "Response error: #{ parsed [ "error" ] [ "message" ] } " )
107+ else
108+ @mcp_logger . info ( "Response: success (id: #{ parsed [ "id" ] } )" )
109+ @sse_logger . info ( "Session created: #{ headers [ "Mcp-Session-Id" ] } " ) if headers [ "Mcp-Session-Id" ]
119110 end
111+ rescue JSON ::ParserError
112+ @mcp_logger . warn ( "Invalid JSON in response" )
120113 end
121- rescue JSON :: ParserError
122- mcp_logger . warn ( "Invalid JSON in response ")
114+ elsif env [ "REQUEST_METHOD" ] == "GET" && status == 200
115+ @sse_logger . info ( "SSE stream established ")
123116 end
124- elsif request . get? && status == 200
125- sse_logger . info ( "SSE stream established" )
126- end
127117
128- response
118+ [ status , headers , response_body ]
119+ end
129120end
130121
131- # Build the Rack application with middleware
122+ # Build the Rack application with middleware.
123+ # `StreamableHTTPTransport` responds to `call(env)`, so it can be used directly as a Rack app.
132124rack_app = Rack ::Builder . new do
133125 # Enable CORS to allow browser-based MCP clients (e.g., MCP Inspector)
134126 # WARNING: origins("*") allows all origins. Restrict this in production.
@@ -146,7 +138,9 @@ def call(message:, delay: 0)
146138
147139 use ( Rack ::CommonLogger , Logger . new ( $stdout) )
148140 use ( Rack ::ShowExceptions )
149- run ( app )
141+ use ( McpSseLogger )
142+
143+ run ( transport )
150144end
151145
152146# Print usage instructions
0 commit comments