Class: Encom::Server
- Inherits:
-
Object
- Object
- Encom::Server
- Defined in:
- lib/encom/server.rb,
lib/encom/server/tool.rb
Defined Under Namespace
Classes: Tool
Constant Summary collapse
- LATEST_PROTOCOL_VERSION =
'2024-11-05'- SUPPORTED_PROTOCOL_VERSIONS =
[ LATEST_PROTOCOL_VERSION # Add more supported versions as they're developed ].freeze
Class Attribute Summary collapse
-
.tools ⇒ Object
readonly
Returns the value of attribute tools.
Instance Attribute Summary collapse
-
#capabilities ⇒ Object
readonly
Returns the value of attribute capabilities.
-
#transport ⇒ Object
readonly
Returns the value of attribute transport.
Class Method Summary collapse
- .name(server_name = nil) ⇒ Object
- .tool(tool_name, description, schema, proc) ⇒ Object
- .version(version = nil) ⇒ Object
Instance Method Summary collapse
- #call_tool(name, arguments) ⇒ Object
-
#handle_initialize(message) ⇒ Object
Handle initialize request.
-
#handle_initialized(message) ⇒ Object
Handle initialized notification.
-
#handle_resources_list(message) ⇒ Object
Handle resources/list request.
-
#handle_roots_list(message) ⇒ Object
Handle roots/list request.
-
#handle_sampling_prepare(message) ⇒ Object
Handle sampling/prepare request.
-
#handle_sampling_sample(message) ⇒ Object
Handle sampling/sample request.
-
#handle_shutdown(message) ⇒ Object
Handle JSON-RPC shutdown request.
-
#handle_tools_call(message) ⇒ Object
Handle tools/call request.
-
#handle_tools_list(message) ⇒ Object
Handle tools/list request.
-
#initialize(options = {}) ⇒ Server
constructor
A new instance of Server.
- #name ⇒ Object
-
#process_message(message) ⇒ Object
Process incoming JSON-RPC message.
-
#respond(id, result) ⇒ Object
Generate and send a JSON-RPC response.
-
#respond_error(id, code, message, data = nil) ⇒ Object
Generate and send a JSON-RPC error response.
-
#run(transport_class, transport_options = {}) ⇒ Object
Run the server with the specified transport.
-
#shutdown ⇒ Object
Shutdown the server and clean up.
- #tools ⇒ Object
- #version ⇒ Object
Constructor Details
#initialize(options = {}) ⇒ Server
Returns a new instance of Server.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/encom/server.rb', line 31 def initialize( = {}) = 0 @capabilities = [:capabilities] || { roots: { listChanged: true }, sampling: {}, tools: {} } # Validate protocol version immediately protocol_version = [:protocol_version] || LATEST_PROTOCOL_VERSION unless SUPPORTED_PROTOCOL_VERSIONS.include?(protocol_version) raise ArgumentError, "Unsupported protocol version: #{protocol_version}. Supported versions: #{SUPPORTED_PROTOCOL_VERSIONS.join(', ')}" end @protocol_version = protocol_version @transport = nil end |
Class Attribute Details
.tools ⇒ Object (readonly)
Returns the value of attribute tools.
26 27 28 |
# File 'lib/encom/server.rb', line 26 def tools @tools end |
Instance Attribute Details
#capabilities ⇒ Object (readonly)
Returns the value of attribute capabilities.
29 30 31 |
# File 'lib/encom/server.rb', line 29 def capabilities @capabilities end |
#transport ⇒ Object (readonly)
Returns the value of attribute transport.
29 30 31 |
# File 'lib/encom/server.rb', line 29 def transport @transport end |
Class Method Details
.name(server_name = nil) ⇒ Object
13 14 15 |
# File 'lib/encom/server.rb', line 13 def name(server_name = nil) @server_name ||= server_name end |
.tool(tool_name, description, schema, proc) ⇒ Object
21 22 23 24 |
# File 'lib/encom/server.rb', line 21 def tool(tool_name, description, schema, proc) @tools ||= [] @tools << Tool.new(name: tool_name, description:, schema:, proc:) end |
.version(version = nil) ⇒ Object
17 18 19 |
# File 'lib/encom/server.rb', line 17 def version(version = nil) @version ||= version end |
Instance Method Details
#call_tool(name, arguments) ⇒ Object
63 64 65 66 67 |
# File 'lib/encom/server.rb', line 63 def call_tool(name, arguments) tool = tools.find { |t| t.name.to_s == name.to_s || t.name == name.to_sym } raise "Unknown tool: #{name}" unless tool tool.call(arguments) end |
#handle_initialize(message) ⇒ Object
Handle initialize request
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/encom/server.rb', line 164 def handle_initialize() client_protocol_version = [:params][:protocolVersion] client_capabilities = [:params][:capabilities] client_info = [:params][:clientInfo] server_info = { name: name, version: version } # Debug log the received protocol version if @transport && @transport.respond_to?(:debug) @transport.debug "Received initialize request with protocol version: #{client_protocol_version}" @transport.debug "Supported protocol versions: #{SUPPORTED_PROTOCOL_VERSIONS.inspect}" end # Check if the requested protocol version is supported if SUPPORTED_PROTOCOL_VERSIONS.include?(client_protocol_version) # Use the requested version if supported protocol_version = client_protocol_version if @transport && @transport.respond_to?(:debug) @transport.debug "Protocol version #{protocol_version} is supported, sending success response" end # Send initialize response respond([:id], { protocolVersion: protocol_version, capabilities: @capabilities, serverInfo: server_info }) else # Return an error for unsupported protocol versions if @transport && @transport.respond_to?(:debug) @transport.debug "Protocol version error: Client requested unsupported version #{client_protocol_version}" end respond_error( [:id], Encom::ErrorCodes::PROTOCOL_ERROR, "Unsupported protocol version: #{client_protocol_version}", { supportedVersions: SUPPORTED_PROTOCOL_VERSIONS } ) end end |
#handle_initialized(message) ⇒ Object
Handle initialized notification
211 212 213 |
# File 'lib/encom/server.rb', line 211 def handle_initialized() # No response needed for notifications end |
#handle_resources_list(message) ⇒ Object
Handle resources/list request
216 217 218 219 220 221 |
# File 'lib/encom/server.rb', line 216 def handle_resources_list() # Default implementation returns an empty list respond([:id], { resources: [] }) end |
#handle_roots_list(message) ⇒ Object
Handle roots/list request
224 225 226 227 228 229 |
# File 'lib/encom/server.rb', line 224 def handle_roots_list() # Default implementation returns an empty list respond([:id], { roots: [] }) end |
#handle_sampling_prepare(message) ⇒ Object
Handle sampling/prepare request
232 233 234 235 236 237 238 |
# File 'lib/encom/server.rb', line 232 def handle_sampling_prepare() # Default implementation returns a simple response respond([:id], { prepared: false, samplingId: nil }) end |
#handle_sampling_sample(message) ⇒ Object
Handle sampling/sample request
241 242 243 244 245 246 247 |
# File 'lib/encom/server.rb', line 241 def handle_sampling_sample() # Default implementation returns a simple response respond([:id], { completion: "Sampling not implemented", completionId: nil }) end |
#handle_shutdown(message) ⇒ Object
Handle JSON-RPC shutdown request
272 273 274 275 276 277 278 279 280 281 |
# File 'lib/encom/server.rb', line 272 def handle_shutdown() if [:id] # If it's a request with ID, respond with a success result respond([:id], { shutdown: true }) end # Initiate clean shutdown shutdown end |
#handle_tools_call(message) ⇒ Object
Handle tools/call request
259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/encom/server.rb', line 259 def handle_tools_call() tool_name = [:params][:name] arguments = [:params][:arguments] || {} begin result = call_tool(tool_name, arguments) respond([:id], result) rescue StandardError => e respond_error([:id], Encom::ErrorCodes::TOOL_EXECUTION_ERROR, "Tool execution error: #{e.message}") end end |
#handle_tools_list(message) ⇒ Object
Handle tools/list request
250 251 252 253 254 255 256 |
# File 'lib/encom/server.rb', line 250 def handle_tools_list() tool_definitions = tools ? tools.map(&:definition) : [] respond([:id], { tools: tool_definitions }) end |
#name ⇒ Object
51 52 53 |
# File 'lib/encom/server.rb', line 51 def name self.class.name end |
#process_message(message) ⇒ Object
Process incoming JSON-RPC message
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/encom/server.rb', line 80 def () return unless .is_a?(Hash) if @transport && @transport.respond_to?(:debug) @transport.debug "Processing message: #{message.inspect}" end # Check for jsonrpc version unless [:jsonrpc] == '2.0' if [:id] respond_error([:id], Encom::ErrorCodes::INVALID_REQUEST, 'Invalid JSON-RPC request') end return end # Process request by method case [:method] when 'initialize' handle_initialize() when 'initialized' handle_initialized() when 'resources/list' handle_resources_list() when 'roots/list' handle_roots_list() when 'sampling/prepare' handle_sampling_prepare() when 'sampling/sample' handle_sampling_sample() when 'tools/list' handle_tools_list() when 'tools/call' handle_tools_call() when 'shutdown' handle_shutdown() else if [:id] if @transport && @transport.respond_to?(:debug) @transport.debug "Unknown method: #{message[:method]}" end respond_error([:id], Encom::ErrorCodes::METHOD_NOT_FOUND, "Method not found: #{message[:method]}") end end rescue StandardError => e if @transport && @transport.respond_to?(:debug) @transport.debug "Error processing message: #{e.message}\n#{e.backtrace.join("\n")}" end if && [:id] respond_error([:id], Encom::ErrorCodes::INTERNAL_ERROR, "Internal error: #{e.message}") end end |
#respond(id, result) ⇒ Object
Generate and send a JSON-RPC response
134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/encom/server.rb', line 134 def respond(id, result) return unless @transport response = { jsonrpc: "2.0", id: id, result: result } @transport.(response) end |
#respond_error(id, code, message, data = nil) ⇒ Object
Generate and send a JSON-RPC error response
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/encom/server.rb', line 147 def respond_error(id, code, , data = nil) return unless @transport response = { jsonrpc: "2.0", id: id, error: { code: code, message: } } response[:error][:data] = data if data @transport.(response) end |
#run(transport_class, transport_options = {}) ⇒ Object
Run the server with the specified transport
70 71 72 73 74 75 76 77 |
# File 'lib/encom/server.rb', line 70 def run(transport_class, = {}) @transport = transport_class.new(self, ) @transport.start rescue StandardError => e $stderr.puts "Error running server: #{e.message}" $stderr.puts e.backtrace.join("\n") if [:debug] raise end |
#shutdown ⇒ Object
Shutdown the server and clean up
284 285 286 287 288 289 290 291 292 |
# File 'lib/encom/server.rb', line 284 def shutdown return if @shutting_down @shutting_down = true if @transport @transport.stop @transport = nil end end |
#tools ⇒ Object
59 60 61 |
# File 'lib/encom/server.rb', line 59 def tools self.class.tools end |
#version ⇒ Object
55 56 57 |
# File 'lib/encom/server.rb', line 55 def version self.class.version end |