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.
149 150 151 152 153 154 155 156 157 |
# File 'lib/tina4/mcp.rb', line 149 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.
146 147 148 |
# File 'lib/tina4/mcp.rb', line 146 def instances @instances end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
141 142 143 |
# File 'lib/tina4/mcp.rb', line 141 def name @name end |
#path ⇒ Object (readonly)
Returns the value of attribute path.
141 142 143 |
# File 'lib/tina4/mcp.rb', line 141 def path @path end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
141 142 143 |
# File 'lib/tina4/mcp.rb', line 141 def version @version end |
Instance Method Details
#handle_message(raw_data) ⇒ Object
Process an incoming JSON-RPC message and return the response string.
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/tina4/mcp.rb', line 187 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.
176 177 178 179 180 181 182 183 184 |
# File 'lib/tina4/mcp.rb', line 176 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.
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 218 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.
165 166 167 168 169 170 171 172 173 |
# File 'lib/tina4/mcp.rb', line 165 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)
271 272 273 |
# File 'lib/tina4/mcp.rb', line 271 def resources @resources end |
#tools ⇒ Object
Access registered tools (for testing)
266 267 268 |
# File 'lib/tina4/mcp.rb', line 266 def tools @tools end |
#write_claude_config(port = 7145) ⇒ Object
Write/update .claude/settings.json with this MCP server config.
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 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 |