Class: Prescient::MCP::Rack
- Inherits:
-
Object
- Object
- Prescient::MCP::Rack
- Defined in:
- lib/prescient/mcp/rack.rb
Overview
Optional Rack-compatible MCP HTTP handler with explicit authentication. rubocop:disable Metrics/ClassLength
Constant Summary collapse
- PROTOCOL_VERSION =
MCP protocol version supported by the HTTP transport.
"2025-06-18"- SESSION_HEADER =
Rack environment key containing the MCP session identifier.
"HTTP_MCP_SESSION_ID"- PROTOCOL_HEADER =
Rack environment key containing the MCP protocol version.
"HTTP_MCP_PROTOCOL_VERSION"- ALLOWED_ORIGINS_DEFAULT =
Default policy allowing requests without an Origin header restriction.
[].freeze
Instance Method Summary collapse
-
#call(env) ⇒ Array
Handle one MCP Streamable HTTP request.
-
#initialize(authentication:, server: Server.new, request_context: nil, max_body_bytes: Configuration::DEFAULT_MAX_INPUT_BYTES, allowed_origins: ALLOWED_ORIGINS_DEFAULT, session_ttl: 3600) ⇒ Rack
constructor
A new instance of Rack.
Constructor Details
#initialize(authentication:, server: Server.new, request_context: nil, max_body_bytes: Configuration::DEFAULT_MAX_INPUT_BYTES, allowed_origins: ALLOWED_ORIGINS_DEFAULT, session_ttl: 3600) ⇒ Rack
Returns a new instance of Rack.
26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/prescient/mcp/rack.rb', line 26 def initialize(authentication:, server: Server.new, request_context: nil, max_body_bytes: Configuration::DEFAULT_MAX_INPUT_BYTES, allowed_origins: ALLOWED_ORIGINS_DEFAULT, session_ttl: 3600) @server = server @authentication = authentication @request_context = request_context @max_body_bytes = validate_limit(max_body_bytes) @allowed_origins = Array(allowed_origins).map(&:to_s).freeze @session_ttl = validate_session_ttl(session_ttl) @sessions = {} @sessions_lock = Monitor.new end |
Instance Method Details
#call(env) ⇒ Array
Handle one MCP Streamable HTTP request.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/prescient/mcp/rack.rb', line 42 def call(env) method = env.fetch("REQUEST_METHOD", "GET").upcase unless %w[POST GET DELETE].include?(method) return response( 405, { error: "method_not_allowed" }, { "allow" => "POST, GET, DELETE" } ) end return response(403, { error: "origin_not_allowed" }) unless origin_allowed?(env) authentication = authenticate(env) unless authentication return response(401, { error: "authentication_required" }, { "www-authenticate" => "Bearer" }) end return post(env, authentication) if method == "POST" return get(env, authentication) if method == "GET" delete(env, authentication) rescue JSON::ParserError response(400, { error: "invalid_json" }) rescue SessionNotFoundError response(404, { error: "session_not_found" }) rescue AuthenticationError response(401, { error: "authentication_failed" }) rescue ArgumentError response(400, { error: "invalid_request" }) rescue StandardError response(500, { error: "internal_error" }) end |