Class: LittleGhost::MCP::Client
- Inherits:
-
Object
- Object
- LittleGhost::MCP::Client
- Defined in:
- lib/little_ghost/mcp/client.rb
Overview
Client makes tools from an MCP server available as ordinary LittleGhost tools. Agents can use a remote capability without learning a second tool interface.
transport = LittleGhost::MCP::HTTPTransport.new(url: "https://mcp.example/rpc")
client = LittleGhost::MCP::Client.new(transport:, prefix: "docs")
client.tools.map(&:tool_name) # => ["docs_search", "docs_fetch"]
Tool names are normalized and checked for collisions. Pagination, tool
count, and response sizes are limited; rejected_tools and
definition_filter can enforce an application allowlist.
Server definitions and results remain untrusted input. LittleGhost validates them before creating tools, but applications still decide which servers and capabilities an agent may use.
A client and its transport represent one authenticated server session. Create a separate pair for each principal or trust boundary. Protocol initialization and subsequent requests through one client are serialized; do not share its transport with another client.
Constant Summary collapse
- MAX_TOOL_NAME_LENGTH =
:nodoc:
64- ALIAS_DIGEST_LENGTH =
:nodoc:
12- DEFAULT_MAX_TOOLS =
:nodoc:
1_000- DEFAULT_MAX_PAGES =
:nodoc:
100
Instance Method Summary collapse
-
#call(name, arguments, context: nil) ⇒ Object
Calls an exposed tool and produces text or serialized structured content.
-
#initialize(transport:, name: "mcp", prefix: nil, rejected_tools: [], definition_filter: nil, max_tools: DEFAULT_MAX_TOOLS, max_pages: DEFAULT_MAX_PAGES) ⇒ Client
constructor
Uses a transport that responds to
send. -
#tools(context: nil) ⇒ Object
Negotiates the protocol when needed, then provides Tool instances for the server's current definitions.
Constructor Details
#initialize(transport:, name: "mcp", prefix: nil, rejected_tools: [], definition_filter: nil, max_tools: DEFAULT_MAX_TOOLS, max_pages: DEFAULT_MAX_PAGES) ⇒ Client
Uses a transport that responds to send.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/little_ghost/mcp/client.rb', line 173 def initialize( transport:, name: "mcp", prefix: nil, rejected_tools: [], definition_filter: nil, max_tools: DEFAULT_MAX_TOOLS, max_pages: DEFAULT_MAX_PAGES ) if definition_filter && !definition_filter.respond_to?(:call) raise ArgumentError, "definition_filter must respond to call" end @transport = transport @name = String(name) @prefix = prefix&.to_s @rejected_tools = rejected_tools.map(&:to_s).freeze @definition_filter = definition_filter @max_tools = positive_integer(max_tools, :max_tools) @max_pages = positive_integer(max_pages, :max_pages) @request_id = 0 @mutex = Mutex.new @initialization_mutex = Mutex.new @source_names_mutex = Mutex.new @source_names = {} @initialized = false end |
Instance Method Details
#call(name, arguments, context: nil) ⇒ Object
Calls an exposed tool and produces text or serialized structured content. Server-declared errors raise ToolError.
219 220 221 222 223 224 225 226 |
# File 'lib/little_ghost/mcp/client.rb', line 219 def call(name, arguments, context: nil) source_name = @source_names_mutex.synchronize { @source_names.fetch(name.to_s, name.to_s) } result = request("tools/call", {name: source_name, arguments: arguments}, context:) content = serialize_result(result) raise ToolError, content if result["isError"] content end |
#tools(context: nil) ⇒ Object
Negotiates the protocol when needed, then provides Tool instances for the server's current definitions.
203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/little_ghost/mcp/client.rb', line 203 def tools(context: nil) @initialization_mutex.synchronize do initialize_protocol(context:) unless @initialized end definitions = list_tool_definitions(context:) definitions.filter_map do |definition| source_name = definition_name(definition) next if @rejected_tools.include?(source_name) next if @definition_filter && !@definition_filter.call(definition) build_tool(definition) end end |