Class: Tina4::McpServer
- Inherits:
-
Object
- Object
- Tina4::McpServer
- Defined in:
- lib/tina4/mcp.rb
Overview
── McpServer ─────────────────────────────────────────────────────
Class Attribute Summary collapse
-
.instances ⇒ Object
readonly
Returns the value of attribute instances.
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#path ⇒ Object
readonly
Returns the value of attribute path.
-
#version ⇒ Object
readonly
Returns the value of attribute version.
Instance Method Summary collapse
-
#handle_message(raw_data) ⇒ Object
Process an incoming JSON-RPC message and return the response string.
-
#initialize(path, name: "Tina4 MCP", version: "1.0.0") ⇒ McpServer
constructor
A new instance of McpServer.
-
#register_resource(uri, handler, description = "", mime_type = "application/json") ⇒ Object
Register a resource URI.
-
#register_routes(router = nil) ⇒ Object
Register HTTP routes for this MCP server on the Tina4 router.
-
#register_tool(name, handler, description = "", schema = nil) ⇒ Object
Register a tool callable.
-
#resources ⇒ Object
Access registered resources (for testing).
-
#tools ⇒ Object
Access registered tools (for testing).
-
#write_claude_config(port = 7145) ⇒ Object
Write/update .claude/settings.json with this MCP server config.
Constructor Details
#initialize(path, name: "Tina4 MCP", version: "1.0.0") ⇒ McpServer
Returns a new instance of McpServer.
227 228 229 230 231 232 233 234 235 |
# File 'lib/tina4/mcp.rb', line 227 def initialize(path, name: "Tina4 MCP", version: "1.0.0") @path = path.chomp("/") @name = name @version = version @tools = {} @resources = {} @initialized = false self.class.instances << self end |
Class Attribute Details
.instances ⇒ Object (readonly)
Returns the value of attribute instances.
224 225 226 |
# File 'lib/tina4/mcp.rb', line 224 def instances @instances end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
219 220 221 |
# File 'lib/tina4/mcp.rb', line 219 def name @name end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
219 220 221 |
# File 'lib/tina4/mcp.rb', line 219 def path @path end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
219 220 221 |
# File 'lib/tina4/mcp.rb', line 219 def version @version end |
Instance Method Details
#handle_message(raw_data) ⇒ Object
Process an incoming JSON-RPC message and return the response string.
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/tina4/mcp.rb', line 265 def (raw_data) begin method, params, request_id = McpProtocol.decode_request(raw_data) rescue ArgumentError => e return McpProtocol.encode_error(nil, McpProtocol::PARSE_ERROR, e.) end handler_method = { "initialize" => :_handle_initialize, "notifications/initialized" => :_handle_initialized, "tools/list" => :_handle_tools_list, "tools/call" => :_handle_tools_call, "resources/list" => :_handle_resources_list, "resources/read" => :_handle_resources_read, "ping" => :_handle_ping }[method] if handler_method.nil? return McpProtocol.encode_error(request_id, McpProtocol::METHOD_NOT_FOUND, "Method not found: #{method}") end begin result = send(handler_method, params) return "" if request_id.nil? # Notification -- no response McpProtocol.encode_response(request_id, result) rescue => e McpProtocol.encode_error(request_id, McpProtocol::INTERNAL_ERROR, e.) end end |
#register_resource(uri, handler, description = "", mime_type = "application/json") ⇒ Object
Register a resource URI.
254 255 256 257 258 259 260 261 262 |
# File 'lib/tina4/mcp.rb', line 254 def register_resource(uri, handler, description = "", mime_type = "application/json") @resources[uri] = { "uri" => uri, "name" => description.empty? ? uri : description, "description" => description.empty? ? uri : description, "mimeType" => mime_type, "handler" => handler } end |
#register_routes(router = nil) ⇒ Object
Register HTTP routes for this MCP server on the Tina4 router.
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/tina4/mcp.rb', line 296 def register_routes(router = nil) server = self msg_path = "#{@path}/message" sse_path = "#{@path}/sse" Tina4::Router.post(msg_path) do |request, response| body = request.body raw = body.is_a?(Hash) ? body : (body.is_a?(String) ? body : body.to_s) result = server.(raw) if result.nil? || result.empty? response.call("", 204) else response.call(JSON.parse(result)) end end Tina4::Router.get(sse_path) do |request, response| endpoint_url = "#{request.url.sub(%r{/sse\z}, "")}/message" sse_data = "event: endpoint\ndata: #{endpoint_url}\n\n" response.call(sse_data, 200, "text/event-stream") end end |
#register_tool(name, handler, description = "", schema = nil) ⇒ Object
Register a tool callable.
243 244 245 246 247 248 249 250 251 |
# File 'lib/tina4/mcp.rb', line 243 def register_tool(name, handler, description = "", schema = nil) schema ||= Tina4.schema_from_method(handler) @tools[name] = { "name" => name, "description" => description.empty? ? name : description, "inputSchema" => schema, "handler" => handler } end |
#resources ⇒ Object
Access registered resources (for testing)
349 350 351 |
# File 'lib/tina4/mcp.rb', line 349 def resources @resources end |
#tools ⇒ Object
Access registered tools (for testing)
344 345 346 |
# File 'lib/tina4/mcp.rb', line 344 def tools @tools end |
#write_claude_config(port = 7145) ⇒ Object
Write/update .claude/settings.json with this MCP server config.
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/tina4/mcp.rb', line 320 def write_claude_config(port = 7145) config_dir = File.join(Dir.pwd, ".claude") FileUtils.mkdir_p(config_dir) config_file = File.join(config_dir, "settings.json") config = {} if File.exist?(config_file) begin config = JSON.parse(File.read(config_file)) rescue JSON::ParserError, IOError # ignore corrupt file end end config["mcpServers"] ||= {} server_key = @name.downcase.gsub(" ", "-") config["mcpServers"][server_key] = { "url" => "http://localhost:#{port}#{@path}/sse" } File.write(config_file, JSON.pretty_generate(config) + "\n") end |