Class: LittleGhost::MCP::Toolset
- Inherits:
-
Object
- Object
- LittleGhost::MCP::Toolset
- Extended by:
- Support::ClassAttributes
- Defined in:
- lib/little_ghost/mcp/toolset.rb
Overview
Loads remote Tool classes through an
application-created official MCP::Client.
The client factory runs during Tool discovery with the current
Tool::Binding. It must return a fresh, unconnected client without starting
remote work. After the factory returns, LittleGhost connects the client,
shares it among the generated Tool instances, and calls close on its
transport, when supported, as the owning run or ToolRegistry closes.
Discovery and Tool calls carry the run's cancellation and deadline into the SDK. The official SDK executes cancellable requests on worker threads. Calls through the official HTTP transport may overlap. When the official stdio transport is supplied directly, calls are serialized and cancelling one invalidates that run's session. Custom or decorated transports own their serialization, cancellation-safe invalidation, and cleanup. SDK handlers may run on worker or listener threads, so application callbacks must support concurrent use and must not depend on the calling fiber's local state. Treat handler requests as untrusted and authorize any local work or data they can reach.
class HelpCenterTools < LittleGhost::MCP::Toolset
client do |_binding|
transport = MCP::Client::HTTP.new(url: "https://mcp.example/rpc")
MCP::Client.new(transport:)
end
end
Defined Under Namespace
Classes: CallbackFailure
Constant Summary collapse
- UNSET =
:nodoc:
Object.new.freeze
Class Method Summary collapse
-
.client(**connect_options, &factory) ⇒ Object
Declares the factory for a fresh, unconnected official MCP::Client.
-
.map_result(&mapping) ⇒ Object
Maps the value produced by LittleGhost's default result conversion.
-
.map_tool(&mapping) ⇒ Object
Maps each generated Tool class before it is bound to the Agent.
-
.on_error(&callback) ⇒ Object
Observes an expected discovery failure caught by optional true.
-
.optional(value = UNSET) ⇒ Object
Makes expected provider and protocol discovery failures produce no tools.
-
.tools(binding) ⇒ Object
Connects the configured client and returns Tool classes for
binding.
Methods included from Support::ClassAttributes
Class Method Details
.client(**connect_options, &factory) ⇒ Object
Declares the factory for a fresh, unconnected official MCP::Client.
The factory receives the current Tool::Binding. LittleGhost forwards
connect_options to MCP::Client#connect, then calls close on the
returned transport when it exposes that method. Calling client
without a block or options returns the inherited factory, if one is
configured.
:call-seq:
client() -> Proc or nil
client(**connect_options) { |binding| ... } -> Proc
62 63 64 65 66 67 68 |
# File 'lib/little_ghost/mcp/toolset.rb', line 62 def client(**, &factory) return client_factory_value if !factory && .empty? raise ArgumentError, "client requires a factory block" unless factory self. = .dup.freeze self.client_factory_value = factory end |
.map_result(&mapping) ⇒ Object
Maps the value produced by LittleGhost's default result conversion.
The block also receives the raw tools/call result: Hash, the
official mcp_tool:, the submitted arguments:, and the current
binding:. Return any Ruby value or Tool::Result. With no block,
returns the inherited mapping, if one is configured.
:call-seq:
map_result() -> Proc or nil
map_result { |value, result:, mcp_tool:, arguments:, binding:| ... } -> Proc
95 96 97 98 99 |
# File 'lib/little_ghost/mcp/toolset.rb', line 95 def map_result(&mapping) return result_mapping_value unless mapping self.result_mapping_value = mapping end |
.map_tool(&mapping) ⇒ Object
Maps each generated Tool class before it is bound to the Agent.
The block receives the generated class, the official
MCP::Client::Tool as mcp_tool:, and the current binding:. Return
the class, a subclass, or nil to omit it. Renaming the class does not
change the operation name sent to the server. With no block, returns
the inherited mapping, if one is configured.
:call-seq:
map_tool() -> Proc or nil
map_tool { |tool_class, mcp_tool:, binding:| ... } -> Proc
80 81 82 83 84 |
# File 'lib/little_ghost/mcp/toolset.rb', line 80 def map_tool(&mapping) return tool_mapping_value unless mapping self.tool_mapping_value = mapping end |
.on_error(&callback) ⇒ Object
Observes an expected discovery failure caught by optional true.
The block receives the translated LittleGhost error and the current
binding:. Exceptions raised by the block propagate. With no block,
returns the inherited callback, if one is configured.
:call-seq:
on_error() -> Proc or nil
on_error { |error, binding:| ... } -> Proc
123 124 125 126 127 |
# File 'lib/little_ghost/mcp/toolset.rb', line 123 def on_error(&callback) return error_callback_value unless callback self.error_callback_value = callback end |
.optional(value = UNSET) ⇒ Object
Makes expected provider and protocol discovery failures produce no tools. Configuration, cancellation, deadline, and callback failures still propagate. With no argument, reports whether discovery is optional.
:call-seq:
optional() -> true or false
optional(value) -> true or false
109 110 111 112 113 |
# File 'lib/little_ghost/mcp/toolset.rb', line 109 def optional(value = UNSET) return optional_value if value.equal?(UNSET) self.optional_value = !!value end |
.tools(binding) ⇒ Object
Connects the configured client and returns Tool classes for binding.
When the binding has a run, the run owns the shared client session.
Otherwise, the ToolRegistry that resolves the returned classes closes
the session through its generated Tool instances. A caller that
bypasses ToolRegistry must instantiate and close a returned class.
Expected discovery failures return an empty Array when
optional true. After the factory returns a client, later
failures call close when its transport exposes that method; failures
then propagate unless they are optional.
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/little_ghost/mcp/toolset.rb', line 139 def tools(binding) context = binding.run&.context context&.check! official_client = build_client(binding) session = Session.new(official_client) connect_client(official_client, context:) binding.run&.register(session) Instrumentation.instrument(:mcp_discovery, toolset: toolset_name) do |telemetry| adapter = Adapter.new( client: official_client, session:, name: toolset_name, tool_mapper: wrapped_tool_mapper, result_mapper: wrapped_result_mapper ) discovered = adapter.tools(context:, binding:) session.close if discovered.empty? && !binding.run telemetry[:outcome] = :success telemetry[:tool_count] = discovered.length discovered end rescue CallbackFailure => error session&.close raise error.original rescue ProviderError, ProtocolError, ToolError => error session&.close raise unless optional_value error_callback_value&.call(error, binding:) [] rescue session&.close raise end |