@@ -64,70 +64,62 @@ def call(message:, delay: 0)
6464# Create the Streamable HTTP transport
6565transport = MCP ::Server ::Transports ::StreamableHTTPTransport . new ( server )
6666
67- # Create a logger for MCP request/response logging
68- mcp_logger = Logger . new ( $stdout)
69- mcp_logger . formatter = proc do |_severity , _datetime , _progname , msg |
70- "[MCP] #{ msg } \n "
71- end
67+ # Rack middleware for MCP request/response and SSE logging.
68+ class McpSseLogger
69+ def initialize ( app )
70+ @app = app
71+
72+ @mcp_logger = Logger . new ( $stdout)
73+ @mcp_logger . formatter = proc { |_severity , _datetime , _progname , msg | "[MCP] #{ msg } \n " }
74+
75+ @sse_logger = Logger . new ( $stdout)
76+ @sse_logger . formatter = proc { |severity , datetime , _progname , msg | "[SSE] #{ severity } #{ datetime . strftime ( "%H:%M:%S.%L" ) } - #{ msg } \n " }
77+ end
7278
73- # Create the Rack application
74- app = proc do |env |
75- request = Rack ::Request . new ( env )
76-
77- # Log request details
78- if request . post?
79- body = request . body . read
80- request . body . rewind
81- begin
82- parsed_body = JSON . parse ( body )
83- mcp_logger . info ( "Request: #{ parsed_body [ "method" ] } (id: #{ parsed_body [ "id" ] } )" )
84-
85- # Log SSE-specific setup
86- if parsed_body [ "method" ] == "initialize"
87- sse_logger . info ( "New client initializing session" )
79+ def call ( env )
80+ if env [ "REQUEST_METHOD" ] == "POST"
81+ body = env [ "rack.input" ] . read
82+ env [ "rack.input" ] . rewind
83+
84+ begin
85+ parsed = JSON . parse ( body )
86+
87+ @mcp_logger . info ( "Request: #{ parsed [ "method" ] } (id: #{ parsed [ "id" ] } )" )
88+ @sse_logger . info ( "New client initializing session" ) if parsed [ "method" ] == "initialize"
89+ rescue JSON ::ParserError
90+ @mcp_logger . warn ( "Invalid JSON in request" )
8891 end
89- rescue JSON ::ParserError
90- mcp_logger . warn ( "Invalid JSON in request" )
92+ elsif env [ "REQUEST_METHOD" ] == "GET"
93+ session_id = env [ "HTTP_MCP_SESSION_ID" ] || Rack ::Utils . parse_query ( env [ "QUERY_STRING" ] ) [ "sessionId" ]
94+
95+ @sse_logger . info ( "SSE connection request for session: #{ session_id } " )
9196 end
92- elsif request . get?
93- session_id = request . env [ "HTTP_MCP_SESSION_ID" ] ||
94- Rack ::Utils . parse_query ( request . env [ "QUERY_STRING" ] ) [ "sessionId" ]
95- sse_logger . info ( "SSE connection request for session: #{ session_id } " )
96- end
9797
98- # Handle the request
99- response = transport . handle_request ( request )
100-
101- # Log response details
102- status , headers , body = response
103- if body . is_a? ( Array ) && !body . empty? && request . post?
104- begin
105- parsed_response = JSON . parse ( body . first )
106- if parsed_response [ "error" ]
107- mcp_logger . error ( "Response error: #{ parsed_response [ "error" ] [ "message" ] } " )
108- elsif parsed_response [ "accepted" ]
109- # Response was sent via SSE
110- server . notify_log_message ( data : { details : "Response accepted and sent via SSE" } , level : "info" )
111- sse_logger . info ( "Response sent via SSE stream" )
112- else
113- mcp_logger . info ( "Response: success (id: #{ parsed_response [ "id" ] } )" )
114-
115- # Log session ID for initialization
116- if headers [ "Mcp-Session-Id" ]
117- sse_logger . info ( "Session created: #{ headers [ "Mcp-Session-Id" ] } " )
98+ status , headers , response_body = @app . call ( env )
99+
100+ if response_body . is_a? ( Array ) && !response_body . empty? && env [ "REQUEST_METHOD" ] == "POST"
101+ begin
102+ parsed = JSON . parse ( response_body . first )
103+
104+ if parsed [ "error" ]
105+ @mcp_logger . error ( "Response error: #{ parsed [ "error" ] [ "message" ] } " )
106+ else
107+ @mcp_logger . info ( "Response: success (id: #{ parsed [ "id" ] } )" )
108+ @sse_logger . info ( "Session created: #{ headers [ "Mcp-Session-Id" ] } " ) if headers [ "Mcp-Session-Id" ]
118109 end
110+ rescue JSON ::ParserError
111+ @mcp_logger . warn ( "Invalid JSON in response" )
119112 end
120- rescue JSON :: ParserError
121- mcp_logger . warn ( "Invalid JSON in response ")
113+ elsif env [ "REQUEST_METHOD" ] == "GET" && status == 200
114+ @sse_logger . info ( "SSE stream established ")
122115 end
123- elsif request . get? && status == 200
124- sse_logger . info ( "SSE stream established" )
125- end
126116
127- response
117+ [ status , headers , response_body ]
118+ end
128119end
129120
130- # Build the Rack application with middleware
121+ # Build the Rack application with middleware.
122+ # `StreamableHTTPTransport` responds to `call(env)`, so it can be used directly as a Rack app.
131123rack_app = Rack ::Builder . new do
132124 # Enable CORS to allow browser-based MCP clients (e.g., MCP Inspector)
133125 # WARNING: origins("*") allows all origins. Restrict this in production.
@@ -145,7 +137,9 @@ def call(message:, delay: 0)
145137
146138 use ( Rack ::CommonLogger , Logger . new ( $stdout) )
147139 use ( Rack ::ShowExceptions )
148- run ( app )
140+ use ( McpSseLogger )
141+
142+ run ( transport )
149143end
150144
151145# Print usage instructions
0 commit comments