Class: RailsAiContext::McpController
- Inherits:
-
ActionController::API
- Object
- ActionController::API
- RailsAiContext::McpController
- Includes:
- ActionController::Live
- Defined in:
- app/controllers/rails_ai_context/mcp_controller.rb
Overview
Rails controller for serving MCP over Streamable HTTP. Alternative to the Rack middleware - integrates with Rails routing, authentication, and middleware stack.
Mount in routes: mount RailsAiContext::Engine, at: "/mcp"
Class Method Summary collapse
-
.mcp_transport ⇒ Object
Class-level memoization - transport persists across requests.
- .reset_transport! ⇒ Object
Instance Method Summary collapse
Class Method Details
.mcp_transport ⇒ Object
Class-level memoization - transport persists across requests. Thread-safe: MCP::Server and transport are stateless for reads.
49 50 51 52 53 54 55 56 |
# File 'app/controllers/rails_ai_context/mcp_controller.rb', line 49 def mcp_transport @transport_mutex.synchronize do @mcp_transport ||= begin server = RailsAiContext::Server.new(Rails.application, transport: :http).build MCP::Server::Transports::StreamableHTTPTransport.new(server) end end end |
.reset_transport! ⇒ Object
58 59 60 |
# File 'app/controllers/rails_ai_context/mcp_controller.rb', line 58 def reset_transport! @transport_mutex.synchronize { @mcp_transport = nil } end |
Instance Method Details
#handle ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'app/controllers/rails_ai_context/mcp_controller.rb', line 19 def handle status_code, rack_headers, body = self.class.mcp_transport.handle_request(request) self.status = status_code rack_headers.each { |k, v| response.headers[k] = v } if body.respond_to?(:each) # Plain enumerable body (initialize, errors, JSON mode): join to a # string so Content-Length/ETag semantics stay conventional. chunks = [] body.each { |chunk| chunks << chunk } body.close if body.respond_to?(:close) self.response_body = chunks.join elsif body.respond_to?(:call) begin body.call(response.stream) ensure begin response.stream.close rescue StandardError nil end end else self.response_body = body end end |