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.
194 195 196 197 198 199 200 201 202 |
# File 'lib/tina4/mcp.rb', line 194 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.
191 192 193 |
# File 'lib/tina4/mcp.rb', line 191 def instances @instances end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
186 187 188 |
# File 'lib/tina4/mcp.rb', line 186 def name @name end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
186 187 188 |
# File 'lib/tina4/mcp.rb', line 186 def path @path end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
186 187 188 |
# File 'lib/tina4/mcp.rb', line 186 def version @version end |
Instance Method Details
#handle_message(raw_data) ⇒ Object
Process an incoming JSON-RPC message and return the response string.
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/tina4/mcp.rb', line 232 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.
221 222 223 224 225 226 227 228 229 |
# File 'lib/tina4/mcp.rb', line 221 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.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
# File 'lib/tina4/mcp.rb', line 263 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.
210 211 212 213 214 215 216 217 218 |
# File 'lib/tina4/mcp.rb', line 210 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)
316 317 318 |
# File 'lib/tina4/mcp.rb', line 316 def resources @resources end |
#tools ⇒ Object
Access registered tools (for testing)
311 312 313 |
# File 'lib/tina4/mcp.rb', line 311 def tools @tools end |
#write_claude_config(port = 7145) ⇒ Object
Write/update .claude/settings.json with this MCP server config.
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/tina4/mcp.rb', line 287 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 |