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.
173 174 175 176 177 178 179 180 181 |
# File 'lib/tina4/mcp.rb', line 173 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.
170 171 172 |
# File 'lib/tina4/mcp.rb', line 170 def instances @instances end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
165 166 167 |
# File 'lib/tina4/mcp.rb', line 165 def name @name end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
165 166 167 |
# File 'lib/tina4/mcp.rb', line 165 def path @path end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
165 166 167 |
# File 'lib/tina4/mcp.rb', line 165 def version @version end |
Instance Method Details
#handle_message(raw_data) ⇒ Object
Process an incoming JSON-RPC message and return the response string.
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/tina4/mcp.rb', line 211 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.
200 201 202 203 204 205 206 207 208 |
# File 'lib/tina4/mcp.rb', line 200 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.
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/tina4/mcp.rb', line 242 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.
189 190 191 192 193 194 195 196 197 |
# File 'lib/tina4/mcp.rb', line 189 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)
295 296 297 |
# File 'lib/tina4/mcp.rb', line 295 def resources @resources end |
#tools ⇒ Object
Access registered tools (for testing)
290 291 292 |
# File 'lib/tina4/mcp.rb', line 290 def tools @tools end |
#write_claude_config(port = 7145) ⇒ Object
Write/update .claude/settings.json with this MCP server config.
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/tina4/mcp.rb', line 266 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 |