Class: McpProcessor
- Inherits:
-
Object
- Object
- McpProcessor
- Includes:
- RpcErrorHelpers
- Defined in:
- lib/stack-service-base/mcp/mcp_processor.rb
Constant Summary collapse
- PROTOCOL_VERSION =
'2025-06-18'- DEFAULT_SERVER_INFO =
{ name: 'mcp-server', title: 'MCP Server', version: '1.0.0' }.freeze
- ParseError =
Class.new(StandardError) do attr_reader :body, :status def initialize(body:, status:) @body = body @status = status super("MCP parse error") end end
Instance Method Summary collapse
- #error_response(id:, code:, message:) ⇒ Object
- #handle(method:, params:) ⇒ Object
- #handle_notification(method:, params:) ⇒ Object
-
#initialize(registry: nil, server_info: DEFAULT_SERVER_INFO, logger: (LOGGER) ? LOGGER : nil)) ⇒ McpProcessor
constructor
A new instance of McpProcessor.
- #initialize_(_body = nil) ⇒ Object
- #initialize_response ⇒ Object
- #list_tools ⇒ Object
- #notification_response(method:, params:) ⇒ Object
- #root_endpoint ⇒ Object
- #root_response ⇒ Object
- #rpc_endpoint(raw_body) ⇒ Object
- #rpc_response(id:, method:, params:) ⇒ Object
Methods included from RpcErrorHelpers
Constructor Details
#initialize(registry: nil, server_info: DEFAULT_SERVER_INFO, logger: (LOGGER) ? LOGGER : nil)) ⇒ McpProcessor
Returns a new instance of McpProcessor.
37 38 39 40 41 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 37 def initialize(registry: nil, server_info: DEFAULT_SERVER_INFO, logger: (defined?(LOGGER) ? LOGGER : nil)) @registry = registry @server_info = server_info @logger = logger end |
Instance Method Details
#error_response(id:, code:, message:) ⇒ Object
71 72 73 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 71 def error_response(id:, code:, message:) json_rpc_response(id: id) { rpc_error!(code, ) } end |
#handle(method:, params:) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 87 def handle(method:, params:) case method when "tools/list" then list_tools # when "resources/list" then {} # when "prompts/list" then {} when "tools/call" then call_tool(params || {}) when "initialize" then initialize_response when "notifications/initialized" then @logger&.debug(params); {} when "logging/setLevel" then @logger&.debug(params); {} else rpc_error!(-32601, "Unknown method #{method}") end end |
#handle_notification(method:, params:) ⇒ Object
101 102 103 104 105 106 107 108 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 101 def handle_notification(method:, params:) case method when "notifications/initialized", "notifications/cancelled" @logger&.debug("MCP notification accepted: #{method}") else @logger&.debug("MCP notification ignored: #{method}") end end |
#initialize_(_body = nil) ⇒ Object
110 111 112 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 110 def initialize_(_body = nil) initialize_response end |
#initialize_response ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 114 def initialize_response { serverInfo: @server_info, protocolVersion: PROTOCOL_VERSION, capabilities: { logging: {}, prompts: { listChanged: false }, resources: { listChanged: false }, tools: { listChanged: false } } } end |
#list_tools ⇒ Object
63 64 65 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 63 def list_tools { tools: registry.list, nextCursor: 'no-more' } end |
#notification_response(method:, params:) ⇒ Object
79 80 81 82 83 84 85 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 79 def notification_response(method:, params:) handle_notification(method: method, params: params) nil rescue => e @logger&.error("Unhandled MCP notification error: #{e.class}: #{e.}") nil end |
#root_endpoint ⇒ Object
43 44 45 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 43 def root_endpoint root_response end |
#root_response ⇒ Object
67 68 69 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 67 def root_response json_rpc_response(id: nil) { list_tools } end |
#rpc_endpoint(raw_body) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 47 def rpc_endpoint(raw_body) req = JSON.parse(raw_body.to_s) method = req["method"] params = req["params"] if req.key?("id") rpc_response(id: req["id"], method: method, params: params) else notification_response(method: method, params: params) end rescue JSON::ParserError => e @logger&.warn("MCP JSON parse failed: #{e.}") body = error_response(id: nil, code: -32700, message: "Parse error") raise ParseError.new(body: body, status: 400) end |
#rpc_response(id:, method:, params:) ⇒ Object
75 76 77 |
# File 'lib/stack-service-base/mcp/mcp_processor.rb', line 75 def rpc_response(id:, method:, params:) json_rpc_response(id: id) { handle(method: method, params: params) } end |