Skip to content

Commit baa225f

Browse files
authored
Merge pull request #53 from patvice/2025-06-18-protocol-support
2025-06-18 Protocol Support
2 parents 9ab3307 + a4288e8 commit baa225f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2851
-202
lines changed

.rubocop.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ RSpec/ExampleLength:
6565

6666

6767
RSpec/MultipleExpectations:
68-
Max: 5
68+
Max: 10
6969

7070
RSpec/MultipleMemoizedHelpers:
7171
Max: 15

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This project is a Ruby client for the [Model Context Protocol (MCP)](https://mod
66

77
For a more detailed guide, see the [RubyLLM::MCP docs](https://rubyllm-mcp.com/).
88

9-
Currently full support for MCP protocol version up to `2025-03-26`.
9+
Currently full support for MCP protocol version up to `2025-06-18`.
1010

1111
<div class="badge-container">
1212
<a href="https://badge.fury.io/rb/ruby_llm-mcp"><img src="https://badge.fury.io/rb/ruby_llm-mcp.svg" alt="Gem Version" /></a>
@@ -117,8 +117,11 @@ puts response
117117
You can also execute MCP tools directly:
118118

119119
```ruby
120+
# Tools Execution
121+
tool = client.tool("search_files")
122+
120123
# Execute a specific tool
121-
result = client.execute_tool(
124+
result = tool.execute(
122125
name: "search_files",
123126
parameters: {
124127
query: "*.rb",

docs/client/elicitation.md

Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
---
2+
layout: default
3+
title: Elicitation
4+
parent: Client Interactions
5+
nav_order: 9
6+
description: "MCP elicitation - allow servers to request additional structured information from users"
7+
---
8+
9+
# Elicitation
10+
{: .no_toc }
11+
12+
Elicitation allows MCP servers to request additional structured information from users during interactions. This enables dynamic workflows where servers can ask for clarification, gather additional context, or collect user preferences in real-time.
13+
14+
## Table of contents
15+
{: .no_toc .text-delta }
16+
17+
1. TOC
18+
{:toc}
19+
20+
---
21+
22+
## Overview
23+
24+
When elicitation is enabled, MCP servers can send "elicitation" requests to your client, which will:
25+
26+
1. Present the server's request message to the user
27+
2. Collect structured user input based on a JSON schema
28+
3. Validate the response against the schema
29+
4. Return the structured data back to the server
30+
31+
This is useful for servers that need user input or clarification during complex workflows.
32+
33+
{: .new }
34+
Elicitation is a new feature in MCP Protocol 2025-06-18.
35+
36+
**Note:** Elicitation is only available for clients that support the `2025-06-18` protocol version.
37+
38+
Additional, in this current version the original request still needs to complete in the bounds of the initial request timeout. In some cases (like if you were to get real user input) that may take longer than what a normal request would take. A solution to this will come out in future versions.
39+
40+
## Basic Elicitation Configuration
41+
42+
### Global Configuration
43+
44+
Configure elicitation handling globally for all clients:
45+
46+
```ruby
47+
RubyLLM::MCP.configure do |config|
48+
config.elicitation = lambda do |elicitation|
49+
# Handle elicitation requests from MCP servers
50+
puts "Server requests: #{elicitation.message}"
51+
52+
# Example: Always accept with a default response
53+
elicitation.structured_response = { "status": "accepted" }
54+
true
55+
end
56+
end
57+
```
58+
59+
### Per-Client Configuration
60+
61+
Configure elicitation handling for specific clients:
62+
63+
```ruby
64+
client = RubyLLM::MCP.client(
65+
name: "interactive-server",
66+
transport_type: :streamable,
67+
config: { url: "https://server.com/mcp" }
68+
)
69+
70+
client.on_elicitation do |elicitation|
71+
# Handle server's elicitation request
72+
puts "Server message: #{elicitation.message}"
73+
74+
# The requested schema defines the expected response format
75+
schema = elicitation.requested_schema
76+
77+
# Provide structured response matching the schema
78+
response_data = collect_user_input(schema)
79+
elicitation.structured_response = response_data
80+
81+
# Return true to accept, false to reject
82+
true
83+
end
84+
```
85+
86+
---
87+
88+
## Elicitation Object
89+
90+
The elicitation object provides access to the server's request and allows you to set the response:
91+
92+
### Properties
93+
94+
| Property | Type | Description |
95+
|----------|------|-------------|
96+
| `message` | String | Human-readable message from the server |
97+
| `requested_schema` | Hash | JSON schema defining the expected response format |
98+
| `structured_response` | Hash | Your structured response (set this) |
99+
100+
### Methods
101+
102+
| Method | Returns | Description |
103+
|--------|---------|-------------|
104+
| `validate_response` | Boolean | Validates the structured response against the schema |
105+
106+
### Example Usage
107+
108+
```ruby
109+
client.on_elicitation do |elicitation|
110+
puts "Server says: #{elicitation.message}"
111+
112+
# Examine the requested schema
113+
schema = elicitation.requested_schema
114+
puts "Expected format: #{schema}"
115+
116+
# Create a response that matches the schema
117+
response = {
118+
"user_choice": "option_a",
119+
"confidence": 0.8,
120+
"reasoning": "This option seems most appropriate"
121+
}
122+
123+
# Set the response
124+
elicitation.structured_response = response
125+
126+
# Validation happens automatically, but you can check manually
127+
if elicitation.validate_response
128+
puts "Response is valid"
129+
true # Accept the elicitation
130+
else
131+
puts "Response is invalid"
132+
false # Reject the elicitation
133+
end
134+
end
135+
```
136+
137+
---
138+
139+
## Response Actions
140+
141+
Your elicitation handler should return one of these values to indicate the action:
142+
143+
### Accept (true)
144+
145+
Accept the elicitation and provide the structured response:
146+
147+
```ruby
148+
client.on_elicitation do |elicitation|
149+
elicitation.structured_response = { "decision": "approved" }
150+
true # Accept
151+
end
152+
```
153+
154+
### Reject (false)
155+
156+
Reject the elicitation request:
157+
158+
```ruby
159+
client.on_elicitation do |elicitation|
160+
false # Reject - don't want to provide this information
161+
end
162+
```
163+
164+
### Cancel (validation failure)
165+
166+
If your response doesn't match the schema, the client automatically cancels:
167+
168+
```ruby
169+
client.on_elicitation do |elicitation|
170+
# This will fail validation and trigger a cancel
171+
elicitation.structured_response = { "invalid": "format" }
172+
true # You accept, but validation fails
173+
end
174+
```
175+
176+
---
177+
178+
## Schema Examples
179+
180+
### Simple User Preference
181+
182+
```json
183+
{
184+
"type": "object",
185+
"properties": {
186+
"preference": {
187+
"type": "string",
188+
"enum": ["option_a", "option_b", "option_c"]
189+
},
190+
"confidence": {
191+
"type": "number",
192+
"minimum": 0,
193+
"maximum": 1
194+
}
195+
},
196+
"required": ["preference"]
197+
}
198+
```
199+
200+
Corresponding response:
201+
202+
```ruby
203+
elicitation.structured_response = {
204+
"preference": "option_a",
205+
"confidence": 0.9
206+
}
207+
```
208+
209+
### Complex Configuration
210+
211+
```json
212+
{
213+
"type": "object",
214+
"properties": {
215+
"settings": {
216+
"type": "object",
217+
"properties": {
218+
"theme": {"type": "string"},
219+
"notifications": {"type": "boolean"},
220+
"advanced": {
221+
"type": "array",
222+
"items": {"type": "string"}
223+
}
224+
}
225+
},
226+
"user_info": {
227+
"type": "object",
228+
"properties": {
229+
"name": {"type": "string"},
230+
"department": {"type": "string"}
231+
},
232+
"required": ["name"]
233+
}
234+
},
235+
"required": ["user_info"]
236+
}
237+
```
238+
239+
Corresponding response:
240+
241+
```ruby
242+
elicitation.structured_response = {
243+
"settings": {
244+
"theme": "dark",
245+
"notifications": true,
246+
"advanced": ["experimental_features", "debug_mode"]
247+
},
248+
"user_info": {
249+
"name": "Alice Smith",
250+
"department": "Engineering"
251+
}
252+
}
253+
```
254+
255+
---
256+
257+
## Error Handling
258+
259+
### Schema Validation Errors
260+
261+
```ruby
262+
client.on_elicitation do |elicitation|
263+
begin
264+
response = build_response(elicitation.requested_schema)
265+
elicitation.structured_response = response
266+
267+
unless elicitation.validate_response
268+
puts "Response validation failed"
269+
return false
270+
end
271+
272+
true
273+
rescue StandardError => e
274+
puts "Error processing elicitation: #{e.message}"
275+
false
276+
end
277+
end
278+
```
279+
280+
### Timeout Handling
281+
282+
```ruby
283+
client.on_elicitation do |elicitation|
284+
Timeout.timeout(30) do # 30 second timeout
285+
response = collect_user_input(elicitation.requested_schema)
286+
elicitation.structured_response = response
287+
true
288+
end
289+
rescue Timeout::Error
290+
puts "Elicitation timed out"
291+
false
292+
end
293+
```
294+
295+
---
296+
297+
## Best Practices
298+
299+
### Security Considerations
300+
301+
- **Validate all user input** before setting structured responses
302+
- **Sanitize data** to prevent injection attacks
303+
- **Limit response size** to prevent memory issues
304+
- **Implement timeouts** for user input collection
305+
306+
### User Experience
307+
308+
- **Provide clear prompts** based on the server's message
309+
- **Show schema information** to help users understand what's expected
310+
- **Implement input validation** with helpful error messages
311+
- **Support cancellation** for long-running input collection
312+
313+
### Error Recovery
314+
315+
- **Handle schema validation failures** gracefully
316+
- **Provide fallback responses** for critical workflows
317+
- **Log elicitation requests** for debugging
318+
- **Implement retry logic** for temporary failures
319+
320+
### Performance
321+
322+
- **Cache frequent responses** for common schemas
323+
- **Implement async processing** for complex input collection
324+
- **Set reasonable timeouts** for user interactions
325+
- **Monitor elicitation frequency** to detect issues
326+
327+
## Next Steps
328+
329+
Once you understand client interactions, explore:
330+
331+
- **[Server Interactions]({% link server/index.md %})** - Working with server capabilities
332+
- **[Configuration]({% link configuration.md %})** - Advanced client configuration options
333+
- **[Rails Integration]({% link guides/rails-integration.md %})** - Using MCP with Rails applications

0 commit comments

Comments
 (0)