Class: SmilyCli::Mcp::Client
- Inherits:
-
Object
- Object
- SmilyCli::Mcp::Client
- Defined in:
- lib/smily_cli/mcp/client.rb
Overview
A minimal MCP client for BookingSync's Streamable-HTTP transport.
It speaks JSON-RPC 2.0 over POST <url>: it performs the initialize
handshake (capturing the Mcp-Session-Id and negotiated protocol version),
then issues tools/list / tools/call (or any method) within that session.
Responses are accepted as either application/json or a single SSE
message frame, so it interoperates with both response modes the server
may pick.
The session is established lazily on first use and reused for the life of the client (i.e. for a single CLI invocation).
Constant Summary collapse
- PROTOCOL_VERSION =
"2025-06-18"- SESSION_HEADER =
"Mcp-Session-Id"
Instance Method Summary collapse
-
#call_tool(name, arguments = {}) ⇒ Hash
Call a tool by name.
-
#close ⇒ void
End the session (best-effort; ignores failures).
-
#connect ⇒ Hash
Perform (once) the initialize handshake and return the server's info: { "protocolVersion" =>, "capabilities" =>, "serverInfo" => }.
-
#initialize(token:, url:, verbose: false) ⇒ Client
constructor
A new instance of Client.
-
#list_resources ⇒ Array<Hash>
MCP resource descriptors, if the server exposes any.
-
#list_tools ⇒ Array<Hash>
Tool definitions ({ "name", "description", "inputSchema" }).
Constructor Details
#initialize(token:, url:, verbose: false) ⇒ Client
Returns a new instance of Client.
27 28 29 30 31 32 33 34 35 |
# File 'lib/smily_cli/mcp/client.rb', line 27 def initialize(token:, url:, verbose: false) @token = token @uri = URI(url) @verbose = verbose @id = 0 @session_id = nil @protocol_version = nil @server_info = nil end |
Instance Method Details
#call_tool(name, arguments = {}) ⇒ Hash
Call a tool by name.
67 68 69 70 |
# File 'lib/smily_cli/mcp/client.rb', line 67 def call_tool(name, arguments = {}) connect rpc("tools/call", { "name" => name, "arguments" => arguments }) end |
#close ⇒ void
This method returns an undefined value.
End the session (best-effort; ignores failures).
81 82 83 84 85 86 87 88 89 |
# File 'lib/smily_cli/mcp/client.rb', line 81 def close return unless @session_id http_request(Net::HTTP::Delete.new(@uri)) rescue StandardError nil ensure @session_id = nil end |
#connect ⇒ Hash
Perform (once) the initialize handshake and return the server's info: { "protocolVersion" =>, "capabilities" =>, "serverInfo" => }.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/smily_cli/mcp/client.rb', line 41 def connect return @server_info if @server_info result = rpc("initialize", { "protocolVersion" => PROTOCOL_VERSION, "capabilities" => {}, "clientInfo" => { "name" => "smily-cli", "version" => SmilyCli::VERSION } }, expect_session: true) @protocol_version = result["protocolVersion"] || PROTOCOL_VERSION # Best-effort per MCP spec; the server accepts it as a 202 notification. notify("notifications/initialized") @server_info = result end |
#list_resources ⇒ Array<Hash>
Returns MCP resource descriptors, if the server exposes any.
73 74 75 76 |
# File 'lib/smily_cli/mcp/client.rb', line 73 def list_resources connect collect_paginated("resources/list", "resources") end |
#list_tools ⇒ Array<Hash>
Returns tool definitions ({ "name", "description", "inputSchema" }).
57 58 59 60 |
# File 'lib/smily_cli/mcp/client.rb', line 57 def list_tools connect collect_paginated("tools/list", "tools") end |