little_ghost 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +33 -5
- data/docs/guides/code_mode.md +2 -2
- data/docs/guides/getting_started.md +26 -1
- data/docs/guides/integrations.md +20 -161
- data/docs/guides/mcp.md +288 -0
- data/docs/guides/models_and_providers.md +21 -54
- data/docs/guides/production.md +14 -5
- data/docs/guides/providers.md +275 -0
- data/docs/guides/sandboxing.md +42 -7
- data/docs/guides/skills.md +1 -3
- data/docs/guides/tools.md +2 -0
- data/exe/little_ghost +12 -0
- data/lib/little_ghost/assembly.rb +11 -3
- data/lib/little_ghost/assembly_builder.rb +2 -2
- data/lib/little_ghost/cli.rb +138 -0
- data/lib/little_ghost/console.rb +17 -0
- data/lib/little_ghost/errors.rb +1 -1
- data/lib/little_ghost/generators/application_generator.rb +179 -0
- data/lib/little_ghost/generators/templates/application/Gemfile.tt +3 -0
- data/lib/little_ghost/generators/templates/application/README.md.tt +29 -0
- data/lib/little_ghost/generators/templates/application/app/agents/application_agent.rb.tt +5 -0
- data/lib/little_ghost/generators/templates/application/app/prompts/application/system.erb.tt +1 -0
- data/lib/little_ghost/generators/templates/application/bin/application.tt +10 -0
- data/lib/little_ghost/generators/templates/application/config/little_ghost.rb.tt +5 -0
- data/lib/little_ghost/generators/templates/application/gitignore.tt +2 -0
- data/lib/little_ghost/generators/templates/application/keep.tt +0 -0
- data/lib/little_ghost/mcp/client.rb +295 -606
- data/lib/little_ghost/mcp/toolset.rb +133 -95
- data/lib/little_ghost/mcp.rb +21 -3
- data/lib/little_ghost/model_resolver.rb +2 -0
- data/lib/little_ghost/models/catalog/models_dev_source.rb +4 -1
- data/lib/little_ghost/provider_registry.rb +1 -0
- data/lib/little_ghost/providers/lm_studio/catalog_source.rb +201 -0
- data/lib/little_ghost/providers/lm_studio.rb +52 -0
- data/lib/little_ghost/providers/openai.rb +3 -75
- data/lib/little_ghost/providers/openai_compatible.rb +78 -1
- data/lib/little_ghost/sandbox/environment_policy.rb +29 -4
- data/lib/little_ghost/sandbox/policy.rb +28 -6
- data/lib/little_ghost/sandboxes/unrestricted.rb +7 -3
- data/lib/little_ghost/skills/catalog.rb +13 -3
- data/lib/little_ghost/tool.rb +6 -1
- data/lib/little_ghost/version.rb +1 -1
- data/lib/little_ghost.rb +1 -0
- metadata +37 -7
- data/lib/little_ghost/mcp/types.rb +0 -216
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d24d2ed91efec3898453d20dfea0902edfca7c207fac0983426153208b308a1e
|
|
4
|
+
data.tar.gz: 74aefcfaf1d9113640f80c6a7c4462c1e4919265705f0eb37c82c9f694eabcae
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: de9e90761042a5cad938664be479e6d35d6b0423b213cde3ac05f0a033c4de7468ef96252073b1405a73510c53b650ea5d7c74be2cae9bd68922494a05cfb406
|
|
7
|
+
data.tar.gz: 96ac0a88302659cad84e80c4491c23ab4bad211b0db8fe9a1bb370dbbcb0a2090d81cc3c922cc62d18ace4804a559efba5bbcb6ee44a6d52cec58ad5f45dfcc0
|
data/README.md
CHANGED
|
@@ -20,7 +20,9 @@ run.response
|
|
|
20
20
|
# One possible response: Hi! How can I help today?
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
That
|
|
23
|
+
That definition is a complete Agent. LittleGhost makes the model call, tracks
|
|
24
|
+
usage, supports streaming, and closes request resources. Add a Tool for
|
|
25
|
+
application capabilities or an Assembly as the work grows.
|
|
24
26
|
|
|
25
27
|
Model requests may send system instructions, caller input, conversation history,
|
|
26
28
|
Tool results, and attachments to the selected provider. Model wording can vary
|
|
@@ -40,9 +42,33 @@ $ bundle install
|
|
|
40
42
|
$ export OPENROUTER_API_KEY="..."
|
|
41
43
|
```
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
The introductory guides use OpenRouter so you can start with one key. Prefer
|
|
46
|
+
another hosted provider or a local Ollama or LM Studio server? See [Provider
|
|
47
|
+
Support](docs/guides/providers.md).
|
|
44
48
|
|
|
45
|
-
LittleGhost runs inside your Ruby process. Use it from a controller, job, CLI,
|
|
49
|
+
LittleGhost runs inside your Ruby process. Use it from a controller, job, CLI,
|
|
50
|
+
or service.
|
|
51
|
+
|
|
52
|
+
## Generate a small application
|
|
53
|
+
|
|
54
|
+
Generate a conventional standalone application:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
$ gem install little_ghost
|
|
58
|
+
$ little_ghost new MyApp
|
|
59
|
+
$ cd my_app
|
|
60
|
+
$ export OPENROUTER_API_KEY="..."
|
|
61
|
+
$ bin/little_ghost console
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The generator installs the bundle. `bin/little_ghost console` runs that
|
|
65
|
+
bundle's LittleGhost version and loads the application before starting IRB.
|
|
66
|
+
|
|
67
|
+
The source checkout also includes a complete
|
|
68
|
+
[single-file Agent](https://github.com/littleghostai/little_ghost/tree/main/examples/basic_agent)
|
|
69
|
+
and
|
|
70
|
+
[coding harness](https://github.com/littleghostai/little_ghost/tree/main/examples/coding_harness),
|
|
71
|
+
both configured for local Ollama.
|
|
46
72
|
|
|
47
73
|
## Give an agent real capabilities
|
|
48
74
|
|
|
@@ -120,15 +146,17 @@ upgrading, because interfaces may change between releases.
|
|
|
120
146
|
|
|
121
147
|
- [Getting Started](docs/guides/getting_started.md) takes you from installation to a tool-backed, streaming agent.
|
|
122
148
|
- [Core Concepts](docs/guides/core_concepts.md) builds the mental model from Agent to Assembly.
|
|
123
|
-
- [Models and Providers](docs/guides/models_and_providers.md)
|
|
149
|
+
- [Models and Providers](docs/guides/models_and_providers.md) explains targets, shared roles, and per-request model selection.
|
|
150
|
+
- [Provider Support](docs/guides/providers.md) has copyable setup for hosted APIs and local model servers.
|
|
124
151
|
- [Prompts as Views](docs/guides/prompt_views.md) gives growing instructions, shared pieces, and application values a natural home.
|
|
125
152
|
- [Tools](docs/guides/tools.md) explains how models call focused Ruby operations.
|
|
153
|
+
- [MCP](docs/guides/mcp.md) connects agents to operations published through the Model Context Protocol.
|
|
126
154
|
- [Structured Results and Content](docs/guides/structured_outputs_and_content.md) covers checked result shapes, images, and documents.
|
|
127
155
|
- [Compose Agents](docs/guides/assemblies.md) walks through workflows, swarms, graphs, nesting, and builders.
|
|
128
156
|
- [Skills](docs/guides/skills.md) organizes reusable instructions and supporting resources.
|
|
129
157
|
- [Workspaces and Sandboxes](docs/guides/sandboxing.md) gives files and child processes a deliberate place to run.
|
|
130
158
|
- [Code Mode](docs/guides/code_mode.md) lets a model compose Tools in sandboxed Ruby or optional JavaScript.
|
|
131
|
-
- [Integrations](docs/guides/integrations.md) connects
|
|
159
|
+
- [Integrations](docs/guides/integrations.md) connects Run streams to AG-UI and OpenTelemetry.
|
|
132
160
|
- [Running in Production](docs/guides/production.md) covers configuration, saved conversations, supervision, and observability.
|
|
133
161
|
- [API reference](rdoc-ref:LittleGhost) provides exact method signatures and ownership rules.
|
|
134
162
|
|
data/docs/guides/code_mode.md
CHANGED
|
@@ -274,5 +274,5 @@ engine, but the generated program then has the same host access as the parent.
|
|
|
274
274
|
|
|
275
275
|
See `LittleGhost::CodeMode::Engine`, `LittleGhost::CodeMode::Session`, and
|
|
276
276
|
`LittleGhost::CodeMode::ProgramResult` for the extension contract. Continue
|
|
277
|
-
with [
|
|
278
|
-
OpenTelemetry.
|
|
277
|
+
with [MCP](mcp.md) to add operations from a remote server, or
|
|
278
|
+
[Integrations](integrations.md) to connect Runs to AG-UI and OpenTelemetry.
|
|
@@ -17,7 +17,8 @@ $ export OPENROUTER_API_KEY="..."
|
|
|
17
17
|
|
|
18
18
|
Use your application's secret manager outside a local shell, and never commit provider credentials.
|
|
19
19
|
|
|
20
|
-
This guide uses OpenRouter
|
|
20
|
+
This guide uses OpenRouter to keep setup to one key. Prefer another hosted
|
|
21
|
+
provider or a local model server? Start with [Provider Support](providers.md).
|
|
21
22
|
|
|
22
23
|
## See your first answer
|
|
23
24
|
|
|
@@ -201,6 +202,30 @@ app/
|
|
|
201
202
|
└── help_center_lookup_tool.rb
|
|
202
203
|
```
|
|
203
204
|
|
|
205
|
+
To generate this layout for a standalone application, install the gem and run
|
|
206
|
+
`little_ghost new`:
|
|
207
|
+
|
|
208
|
+
```sh
|
|
209
|
+
$ gem install little_ghost
|
|
210
|
+
$ little_ghost new MyApp
|
|
211
|
+
$ cd my_app
|
|
212
|
+
$ export OPENROUTER_API_KEY="..."
|
|
213
|
+
$ bin/little_ghost console
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
The generator creates `my_app` with one Agent, a prompt view, configuration,
|
|
217
|
+
the conventional application directories, an installed bundle, and a local
|
|
218
|
+
LittleGhost command. `bin/little_ghost console` uses the generated
|
|
219
|
+
application's bundle, loads its configuration and classes, and then starts
|
|
220
|
+
IRB.
|
|
221
|
+
|
|
222
|
+
The source repository also contains a complete
|
|
223
|
+
[single-file Agent](https://github.com/littleghostai/little_ghost/tree/main/examples/basic_agent)
|
|
224
|
+
and a
|
|
225
|
+
[coding harness](https://github.com/littleghostai/little_ghost/tree/main/examples/coding_harness)
|
|
226
|
+
that demonstrates Agents, prompt views, Tools, a Graph, a Workspace, and a
|
|
227
|
+
native Sandbox.
|
|
228
|
+
|
|
204
229
|
You now have the smallest useful LittleGhost application: one Agent, one Tool, and one familiar Ruby call.
|
|
205
230
|
|
|
206
231
|
When the feature grows, the calling style stays the same. An **assembly** lets one or more agents work as a unit while keeping `.ask` and `.stream_ask`. Read [Core Concepts](core_concepts.md) next and grow this Agent into a larger system.
|
data/docs/guides/integrations.md
CHANGED
|
@@ -1,149 +1,8 @@
|
|
|
1
|
-
# Connect
|
|
1
|
+
# Connect Runs to interfaces and tracing
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Load Tools from an MCP server
|
|
8
|
-
|
|
9
|
-
An MCP Toolset connects to one server and turns its published operations into
|
|
10
|
-
LittleGhost Tool classes. Add the Toolset through the same Agent `tools`
|
|
11
|
-
declaration used for local Tools:
|
|
12
|
-
|
|
13
|
-
```ruby
|
|
14
|
-
require "little_ghost/mcp"
|
|
15
|
-
|
|
16
|
-
class HelpCenterTools < LittleGhost::MCP::Toolset
|
|
17
|
-
connection url: "https://mcp.example/rpc", timeout: 20
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
class CustomerSupportAgent < LittleGhost::Agent
|
|
21
|
-
system_prompt "Use help-center tools for published guidance."
|
|
22
|
-
tools HelpCenterTools
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
run = CustomerSupportAgent.ask("How long do refunds take?")
|
|
26
|
-
run.response
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
`connection` requires `url` and also accepts `headers`, `timeout`, `signer`,
|
|
30
|
-
`allow_insecure_http`, and `max_response_bytes`. Pass a block when credentials
|
|
31
|
-
depend on the current Agent run:
|
|
32
|
-
|
|
33
|
-
```ruby
|
|
34
|
-
connection do |binding|
|
|
35
|
-
token = McpAccessTokens.for_actor(binding.run.invocation.actor_id)
|
|
36
|
-
{
|
|
37
|
-
url: "https://mcp.example/rpc",
|
|
38
|
-
headers: {"Authorization" => "Bearer #{token}"},
|
|
39
|
-
timeout: 20
|
|
40
|
-
}
|
|
41
|
-
end
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
The block's `binding` gives it access to the current Run. LittleGhost evaluates
|
|
45
|
-
the block before opening the MCP session, so each Agent run can use credentials
|
|
46
|
-
for its authenticated caller.
|
|
47
|
-
|
|
48
|
-
By default, the Agent receives every operation published by the server. Their
|
|
49
|
-
normalized server names, such as `search` and `fetch`, become Tool names.
|
|
50
|
-
|
|
51
|
-
Use `map_tool` when the Agent should receive only part of the server catalog or
|
|
52
|
-
when a generated Tool needs a different name or configuration:
|
|
53
|
-
|
|
54
|
-
```ruby
|
|
55
|
-
class CuratedHelpCenterTools < LittleGhost::MCP::Toolset
|
|
56
|
-
connection url: "https://mcp.example/rpc", timeout: 20
|
|
57
|
-
|
|
58
|
-
map_tool do |tool_class, definition:, binding:|
|
|
59
|
-
next unless %w[search fetch].include?(definition.source_name)
|
|
60
|
-
|
|
61
|
-
tool_class.tool_name "help_center_#{definition.source_name}"
|
|
62
|
-
tool_class
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
`definition` describes the operation published by the server, and `binding`
|
|
68
|
-
identifies the current Agent run. Return the class after configuring it, or
|
|
69
|
-
return `nil` to omit the operation. Renaming a generated Tool does not change
|
|
70
|
-
the original `Definition#source_name` sent back to the server.
|
|
71
|
-
|
|
72
|
-
The Agent can call the generated Tools like local Tools. LittleGhost uses one
|
|
73
|
-
local client and transport for the Toolset during the Agent run. The built-in
|
|
74
|
-
HTTP transport does not send an MCP session-termination request. Configure
|
|
75
|
-
server-side expiry, or arrange explicit remote cleanup when the server requires
|
|
76
|
-
it.
|
|
77
|
-
|
|
78
|
-
Most MCP results need no mapping. LittleGhost returns `structuredContent` as a
|
|
79
|
-
Ruby Hash when present, otherwise it returns the server's text. Server images
|
|
80
|
-
become Artifacts.
|
|
81
|
-
|
|
82
|
-
Use `map_result` when one operation needs application-specific conversion. This
|
|
83
|
-
example turns the server's download identifier into a deferred Artifact:
|
|
84
|
-
|
|
85
|
-
```ruby
|
|
86
|
-
map_result do |result, call:, binding:|
|
|
87
|
-
next result unless call.definition.source_name == "export"
|
|
88
|
-
|
|
89
|
-
LittleGhost::Tool::Result.new(
|
|
90
|
-
value: result.structured_content,
|
|
91
|
-
artifacts: [
|
|
92
|
-
LittleGhost::Artifact.deferred(
|
|
93
|
-
reference: result.metadata.fetch("download_id"),
|
|
94
|
-
media_type: "application/octet-stream"
|
|
95
|
-
)
|
|
96
|
-
]
|
|
97
|
-
)
|
|
98
|
-
end
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
`map_result` receives the complete `MCP::Result`, the `MCP::Call` that produced
|
|
102
|
-
it, and the current binding. Return any Ruby value or `Tool::Result`. Returning
|
|
103
|
-
the supplied result unchanged keeps the default conversion described above.
|
|
104
|
-
MCP images and local Tool artifacts use the same storage and presentation
|
|
105
|
-
rules when `Configuration#artifacts` is enabled. Images and documents are sent
|
|
106
|
-
as model content; their stored references are fallback information rather than
|
|
107
|
-
a second representation. LittleGhost also checks results against
|
|
108
|
-
server-advertised JSON Schema Draft 2020-12 output schemas.
|
|
109
|
-
|
|
110
|
-
An optional server can fail discovery without preventing Agent construction:
|
|
111
|
-
|
|
112
|
-
```ruby
|
|
113
|
-
class HelpCenterTools < LittleGhost::MCP::Toolset
|
|
114
|
-
connection { |binding| McpConnections.help_center(binding) }
|
|
115
|
-
optional true
|
|
116
|
-
on_error do |error, binding:|
|
|
117
|
-
McpAvailability.report(error, run_id: binding.run.invocation.run_id)
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
`optional true` converts expected provider and protocol discovery failures
|
|
123
|
-
into an empty Tool set. `on_error` observes only those caught failures.
|
|
124
|
-
Cancellation, deadlines, configuration errors, and application callback
|
|
125
|
-
failures still propagate.
|
|
126
|
-
|
|
127
|
-
LittleGhost limits the number and total size of discovered operations, the
|
|
128
|
-
complexity of their schemas, and the size and number of returned images.
|
|
129
|
-
`HTTPTransport` also limits each HTTP response and requires HTTPS unless local
|
|
130
|
-
HTTP is explicitly enabled.
|
|
131
|
-
|
|
132
|
-
> **Safety note:** An MCP server supplies descriptions and results that the model
|
|
133
|
-
> can see. Structural validation does not make that content trustworthy or
|
|
134
|
-
> authorize an operation it suggests. Expose only the operations the Agent
|
|
135
|
-
> needs, use narrowly scoped credentials, and have the server authorize every
|
|
136
|
-
> sensitive call. If a result becomes a deferred Artifact, its resolver must
|
|
137
|
-
> verify that the referenced file belongs to the authenticated caller, fetch
|
|
138
|
-
> only from an intended service, and limit the response size before returning
|
|
139
|
-
> bytes to LittleGhost.
|
|
140
|
-
|
|
141
|
-
LittleGhost implements its documented client behavior for the [MCP 2025-06-18
|
|
142
|
-
specification](https://modelcontextprotocol.io/specification/2025-06-18).
|
|
143
|
-
|
|
144
|
-
Use `LittleGhost::MCP::HTTPTransport` and `LittleGhost::MCP::Client` directly
|
|
145
|
-
when you need a custom transport. They produce the same generated Tool classes
|
|
146
|
-
and accept the same mapping callbacks as Toolset.
|
|
3
|
+
Use AG-UI to stream Run events to an interactive client. Use OpenTelemetry to
|
|
4
|
+
publish traces to the backend your application already uses. Neither changes
|
|
5
|
+
the Agent that produced the Run.
|
|
147
6
|
|
|
148
7
|
## Send a Run stream through AG-UI
|
|
149
8
|
|
|
@@ -168,13 +27,13 @@ events = LittleGhost::AGUI::Adapter.new.stream(
|
|
|
168
27
|
events.each { |event| websocket.write(JSON.generate(event)) }
|
|
169
28
|
```
|
|
170
29
|
|
|
171
|
-
The adapter translates
|
|
172
|
-
|
|
173
|
-
calls. Your application
|
|
174
|
-
|
|
30
|
+
The adapter translates the full Run, including model output, Tool activity,
|
|
31
|
+
retries, subagent activity, and the final outcome. It does not keep state between
|
|
32
|
+
calls. Your application owns the connection, backpressure, disconnect behavior,
|
|
33
|
+
and any request state its callbacks need.
|
|
175
34
|
|
|
176
|
-
LittleGhost
|
|
177
|
-
|
|
35
|
+
LittleGhost may emit event types beyond the core AG-UI set. Decide whether the
|
|
36
|
+
client preserves or ignores types it does not recognize. See the [AG-UI event
|
|
178
37
|
documentation](https://docs.ag-ui.com/concepts/events) when implementing the
|
|
179
38
|
client.
|
|
180
39
|
|
|
@@ -183,8 +42,8 @@ client.
|
|
|
183
42
|
> see the complete Run, then filter fields before sending or storing events.
|
|
184
43
|
|
|
185
44
|
Calling `each` drives the source stream on the caller's fiber or thread. When a
|
|
186
|
-
client disconnects, stop enumerating and
|
|
187
|
-
|
|
45
|
+
client disconnects, stop enumerating and decide whether the application should
|
|
46
|
+
cancel the Run. Closing the socket cannot undo Tool work that already ran.
|
|
188
47
|
|
|
189
48
|
## Trace Runs with OpenTelemetry
|
|
190
49
|
|
|
@@ -197,9 +56,9 @@ LittleGhost.configure do |config|
|
|
|
197
56
|
end
|
|
198
57
|
```
|
|
199
58
|
|
|
200
|
-
LittleGhost
|
|
201
|
-
|
|
202
|
-
model calls, Tools, assemblies, sessions, usage, and failures
|
|
59
|
+
LittleGhost includes the `opentelemetry-api` integration. Your application
|
|
60
|
+
chooses the SDK, processor, and exporter. The subscriber emits spans and events
|
|
61
|
+
for Runs, model calls, Tools, assemblies, sessions, usage, and failures, and it
|
|
203
62
|
can propagate W3C `traceparent` and `tracestate` fields.
|
|
204
63
|
|
|
205
64
|
Prompts, messages, responses, Tool arguments, and exception content are omitted
|
|
@@ -209,9 +68,9 @@ Avoid putting raw user, order, session, or request IDs in span attributes.
|
|
|
209
68
|
|
|
210
69
|
Attribute names follow the evolving [OpenTelemetry GenAI semantic
|
|
211
70
|
conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/) where they
|
|
212
|
-
apply.
|
|
213
|
-
|
|
71
|
+
apply. If the tracing backend buffers data, flush or shut down
|
|
72
|
+
`LittleGhost::Instrumentation` before the application exits.
|
|
214
73
|
|
|
215
|
-
See [Running in Production](production.md) for startup, shutdown, and
|
|
216
|
-
[
|
|
217
|
-
Sandboxes](sandboxing.md) for child processes and files.
|
|
74
|
+
See [Running in Production](production.md) for startup, shutdown, and
|
|
75
|
+
observability, [MCP](mcp.md) for operations published by remote servers,
|
|
76
|
+
and [Workspaces and Sandboxes](sandboxing.md) for child processes and files.
|
data/docs/guides/mcp.md
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Connect agents to MCP servers
|
|
2
|
+
|
|
3
|
+
Give an Agent access to operations published by a Model Context Protocol (MCP)
|
|
4
|
+
server without changing how your application calls the Agent.
|
|
5
|
+
`LittleGhost::MCP::Toolset` turns operations discovered by the official MCP Ruby
|
|
6
|
+
client into LittleGhost Tool classes, which join the same `tools` declaration as
|
|
7
|
+
local application Tools.
|
|
8
|
+
|
|
9
|
+
MCP support is opt-in. Requiring `little_ghost` alone does not install or load
|
|
10
|
+
the SDK or its transports.
|
|
11
|
+
|
|
12
|
+
## Connect over Streamable HTTP
|
|
13
|
+
|
|
14
|
+
Add the official SDK and its HTTP dependencies to your bundle:
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
gem "mcp", "~> 1.3"
|
|
18
|
+
gem "faraday", "~> 2.0"
|
|
19
|
+
gem "event_stream_parser", "~> 1.0"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Require the integration explicitly, then create a Toolset with a `client`
|
|
23
|
+
block. Return a new official client from the block:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
require "little_ghost/mcp"
|
|
27
|
+
|
|
28
|
+
class HelpCenterTools < LittleGhost::MCP::Toolset
|
|
29
|
+
client do |_binding|
|
|
30
|
+
transport = MCP::Client::HTTP.new(
|
|
31
|
+
url: "https://mcp.example/rpc"
|
|
32
|
+
)
|
|
33
|
+
MCP::Client.new(transport:)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class CustomerSupportAgent < LittleGhost::Agent
|
|
38
|
+
system_prompt "Use help-center tools for published guidance."
|
|
39
|
+
tools HelpCenterTools
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
run = CustomerSupportAgent.ask("How long do refunds take?")
|
|
43
|
+
run.response
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
LittleGhost calls the block once for each Agent run. It connects the client,
|
|
47
|
+
discovers the server's Tools, and closes the transport when the run ends.
|
|
48
|
+
|
|
49
|
+
The `client` block receives the current `Tool::Binding`. Use it to build headers
|
|
50
|
+
or credentials from authenticated application context without storing them on
|
|
51
|
+
the Toolset:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
class AccountTools < LittleGhost::MCP::Toolset
|
|
55
|
+
client do |binding|
|
|
56
|
+
token = McpAccessTokens.for_actor(binding.run.invocation.actor_id)
|
|
57
|
+
transport = MCP::Client::HTTP.new(
|
|
58
|
+
url: "https://mcp.example/rpc",
|
|
59
|
+
headers: {"Authorization" => "Bearer #{token}"}
|
|
60
|
+
)
|
|
61
|
+
MCP::Client.new(transport:)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Connect a local server over standard input and output
|
|
67
|
+
|
|
68
|
+
A standard input and output (stdio) connection needs only the official SDK:
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
gem "mcp", "~> 1.3"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Construct the SDK transport in the same `client` block:
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
class LocalDatabaseTools < LittleGhost::MCP::Toolset
|
|
78
|
+
client do |_binding|
|
|
79
|
+
transport = MCP::Client::Stdio.new(
|
|
80
|
+
command: "bundle",
|
|
81
|
+
args: ["exec", "database-mcp"],
|
|
82
|
+
env: {"APP_ENV" => "production"},
|
|
83
|
+
read_timeout: 30
|
|
84
|
+
)
|
|
85
|
+
MCP::Client.new(transport:)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
A stdio server is a child process with the same operating-system permissions as
|
|
91
|
+
your Ruby process. It is not a sandbox. Use an operating-system sandbox when
|
|
92
|
+
you do not fully trust the executable.
|
|
93
|
+
|
|
94
|
+
The `env` Hash changes only the variables you name. The child inherits every
|
|
95
|
+
other variable from the parent process. Clear sensitive variables explicitly,
|
|
96
|
+
or launch the server through an isolated wrapper when it must not receive
|
|
97
|
+
ambient credentials.
|
|
98
|
+
|
|
99
|
+
## Configure the official client
|
|
100
|
+
|
|
101
|
+
Set timeouts, message limits, OAuth, middleware, and other transport behavior
|
|
102
|
+
through the SDK. Keyword arguments on `client` go directly to
|
|
103
|
+
`MCP::Client#connect`; use them for an explicit protocol mode, version, or client
|
|
104
|
+
capability.
|
|
105
|
+
|
|
106
|
+
### Respond to server requests
|
|
107
|
+
|
|
108
|
+
A server may need more information while handling a Tool call. MCP calls this
|
|
109
|
+
elicitation. Advertise the capability when connecting, then register a handler
|
|
110
|
+
on the client:
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
class InteractiveTools < LittleGhost::MCP::Toolset
|
|
114
|
+
client(capabilities: {elicitation: {}}) do |binding|
|
|
115
|
+
transport = MCP::Client::HTTP.new(url: "https://mcp.example/rpc")
|
|
116
|
+
MCP::Client.new(transport:).tap do |official_client|
|
|
117
|
+
official_client.on_elicitation do |request|
|
|
118
|
+
Elicitations.answer(request, run: binding.run)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The handler can answer from the current Run or pass the request to an application
|
|
126
|
+
interface. Sampling similarly lets a server request a model call, while roots
|
|
127
|
+
tell a server which directories the application makes available. Configure
|
|
128
|
+
these features on the official client.
|
|
129
|
+
|
|
130
|
+
Treat every server-initiated handler request as untrusted. Authorize it against
|
|
131
|
+
the current run, restrict roots to intended paths, constrain model sampling and
|
|
132
|
+
its cost, and return only the application data that server is allowed to receive.
|
|
133
|
+
|
|
134
|
+
Return a new, unconnected client for every run. Building it should not start
|
|
135
|
+
remote work. LittleGhost closes transports that provide `close`, including when
|
|
136
|
+
connection or discovery fails. If a custom transport owns other resources, it
|
|
137
|
+
must release them itself.
|
|
138
|
+
|
|
139
|
+
Set transport timeouts to match the application's deadline. LittleGhost passes
|
|
140
|
+
Run cancellation and deadlines to Tool discovery and calls, but connection has
|
|
141
|
+
its own timeout behavior.
|
|
142
|
+
|
|
143
|
+
## Plan concurrency and cancellation
|
|
144
|
+
|
|
145
|
+
Most applications only need transport timeouts. The details below matter when
|
|
146
|
+
the application uses a Fiber scheduler or runs independent Tools concurrently.
|
|
147
|
+
|
|
148
|
+
### Connection
|
|
149
|
+
|
|
150
|
+
LittleGhost connects while it discovers the Agent's Tools. Run cancellation
|
|
151
|
+
does not interrupt connection, so the transport's connection and read timeouts
|
|
152
|
+
control how long it can wait. Choose a scheduler-compatible transport adapter
|
|
153
|
+
when other fibers must continue during that time.
|
|
154
|
+
|
|
155
|
+
### Tool discovery and calls
|
|
156
|
+
|
|
157
|
+
Tool discovery and calls honor Run cancellation and deadlines. Cancelling an
|
|
158
|
+
HTTP call returns control to the Run, but the underlying request may continue
|
|
159
|
+
waiting until the server responds or the transport closes.
|
|
160
|
+
|
|
161
|
+
All Tools for one run share the same client. HTTP calls may overlap when
|
|
162
|
+
LittleGhost runs independent Tools concurrently, so choose a Faraday adapter
|
|
163
|
+
that supports overlapping calls. If the server or transport requires one call
|
|
164
|
+
at a time, mark the generated Tools exclusive:
|
|
165
|
+
|
|
166
|
+
```ruby
|
|
167
|
+
map_tool do |tool_class, mcp_tool:, binding:|
|
|
168
|
+
tool_class.exclusive true
|
|
169
|
+
tool_class
|
|
170
|
+
end
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
LittleGhost serializes calls through the official stdio transport. If one of
|
|
174
|
+
those calls is cancelled, it closes that run's session rather than risk reading
|
|
175
|
+
a late response as the answer to a later call. A custom or decorated stdio
|
|
176
|
+
transport must provide its own serialization, cancellation behavior, and
|
|
177
|
+
cleanup.
|
|
178
|
+
|
|
179
|
+
### Server handlers
|
|
180
|
+
|
|
181
|
+
The server may invoke a handler while other work is active. Write handlers for
|
|
182
|
+
concurrent use and capture the application values they need when building the
|
|
183
|
+
client. Do not rely on fiber-local state inside a handler.
|
|
184
|
+
|
|
185
|
+
## Select and map Tools
|
|
186
|
+
|
|
187
|
+
By default, the Agent receives every Tool published by the server. LittleGhost
|
|
188
|
+
normalizes each name for the model and keeps the server's original name for
|
|
189
|
+
calls. Discovery stops after 1,000 Tools or 100 pages, which bounds the work an
|
|
190
|
+
untrusted catalog can create in one run.
|
|
191
|
+
|
|
192
|
+
Use `map_tool` to omit operations or configure their generated classes:
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
class CuratedHelpCenterTools < HelpCenterTools
|
|
196
|
+
map_tool do |tool_class, mcp_tool:, binding:|
|
|
197
|
+
next unless %w[search fetch].include?(mcp_tool.name)
|
|
198
|
+
|
|
199
|
+
tool_class.tool_name "help_center_#{mcp_tool.name}"
|
|
200
|
+
tool_class
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`mcp_tool` is the Tool published by the official client. Return the generated
|
|
206
|
+
class, a subclass, or `nil` to omit it. Renaming the generated Tool changes the
|
|
207
|
+
name shown to the model, not the name sent back to the server.
|
|
208
|
+
|
|
209
|
+
LittleGhost sends the server's input schema to the model unchanged. It does not
|
|
210
|
+
validate arguments against that schema; the server must validate them before
|
|
211
|
+
performing an operation. LittleGhost limits schema depth and node count during
|
|
212
|
+
discovery. Configure the transport's message-size limit to bound the bytes
|
|
213
|
+
accepted from a server.
|
|
214
|
+
|
|
215
|
+
> **Safety note:** Server descriptions and results become visible to the model.
|
|
216
|
+
> Treat them as untrusted content. Expose only the operations the Agent needs,
|
|
217
|
+
> use narrowly scoped credentials, and have the server authorize every sensitive
|
|
218
|
+
> call.
|
|
219
|
+
|
|
220
|
+
## Convert results
|
|
221
|
+
|
|
222
|
+
Without a mapping, LittleGhost returns `structuredContent` when the server sends
|
|
223
|
+
it. Otherwise, it returns the text or remaining visible content blocks. MCP
|
|
224
|
+
image blocks become Artifacts.
|
|
225
|
+
|
|
226
|
+
Suppose the help-center server returns `structuredContent` with an `articles`
|
|
227
|
+
array. Use `map_result` to present each article as a short line:
|
|
228
|
+
|
|
229
|
+
```ruby
|
|
230
|
+
map_result do |value, mcp_tool:, **|
|
|
231
|
+
next value unless mcp_tool.name == "search"
|
|
232
|
+
|
|
233
|
+
value.fetch("articles").map do |article|
|
|
234
|
+
"#{article.fetch("title")}: #{article.fetch("url")}"
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`value` is LittleGhost's default conversion, and `mcp_tool` identifies the
|
|
240
|
+
server operation. Return `value` unchanged or replace it with any Ruby value or
|
|
241
|
+
`Tool::Result`. The block can also receive the raw result, sent arguments, and
|
|
242
|
+
current binding; see the [`MCP::Toolset`
|
|
243
|
+
API](rdoc-ref:LittleGhost::MCP::Toolset) for their exact shapes.
|
|
244
|
+
|
|
245
|
+
Image Artifacts remain attached to the mapped result. A server result marked
|
|
246
|
+
`isError` remains a model-visible Tool error.
|
|
247
|
+
|
|
248
|
+
For custom images, files, or deferred Artifacts, continue with [Structured
|
|
249
|
+
Results and Content](structured_outputs_and_content.md). A deferred resolver
|
|
250
|
+
must verify ownership, fetch only from the intended service, and limit response
|
|
251
|
+
size.
|
|
252
|
+
|
|
253
|
+
## Keep an optional server from blocking a run
|
|
254
|
+
|
|
255
|
+
An optional server can fail discovery without preventing Agent construction:
|
|
256
|
+
|
|
257
|
+
```ruby
|
|
258
|
+
class OptionalHelpCenterTools < HelpCenterTools
|
|
259
|
+
optional true
|
|
260
|
+
on_error do |error, binding:|
|
|
261
|
+
McpAvailability.report(error, run_id: binding.run.invocation.run_id)
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
`optional true` turns an expected connection or protocol error during discovery
|
|
267
|
+
into an empty Tool set. Configuration errors, cancellation, deadlines, and
|
|
268
|
+
failures in application callbacks still stop the run.
|
|
269
|
+
|
|
270
|
+
## Let the SDK negotiate the protocol version
|
|
271
|
+
|
|
272
|
+
The [official MCP Ruby SDK](https://github.com/modelcontextprotocol/ruby-sdk)
|
|
273
|
+
handles protocol negotiation and transport behavior. Without explicit connect
|
|
274
|
+
options, it negotiates with the server using a protocol version the installed
|
|
275
|
+
SDK supports. Pin `protocol_version` or `mode` only when interoperability
|
|
276
|
+
requires it.
|
|
277
|
+
|
|
278
|
+
Need sampling, roots, elicitation, or another client capability? Configure it
|
|
279
|
+
on the client you build above. The installed SDK and negotiated protocol version
|
|
280
|
+
determine what is available. Check the [Ruby SDK client
|
|
281
|
+
documentation](https://ruby.sdk.modelcontextprotocol.io/client/) and the
|
|
282
|
+
[versioned MCP specification](https://modelcontextprotocol.io/specification/)
|
|
283
|
+
for the capability you need.
|
|
284
|
+
|
|
285
|
+
Continue with [Tools](tools.md) for the local Tool boundary,
|
|
286
|
+
[Integrations](integrations.md) to send Runs through AG-UI or OpenTelemetry, or
|
|
287
|
+
the [`MCP::Toolset` API](rdoc-ref:LittleGhost::MCP::Toolset) for exact mapping
|
|
288
|
+
and ownership contracts.
|