Skip to content

Commit a235572

Browse files
committed
Remove Server#create_sampling_message direct call
## Motivation and Context Sampling is a one-to-one request/response interaction between a server and a specific client. `Server#create_sampling_message` does not scope requests to a specific session, which could lead to unintended broadcasts on multi-client transports. `ServerSession#create_sampling_message` should be used instead, as it routes the request to the correct client session. This aligns with the Python SDK, which also exposes sampling only at the session level. ## How Has This Been Tested? Existing tests updated to call `ServerSession#create_sampling_message` instead of `Server#create_sampling_message`. All tests pass (`rake test`), RuboCop is clean, and conformance tests pass. ## Breaking Changes `Server#create_sampling_message` is removed without a deprecation warning. The sampling feature was released recently and the method was not intended to be the primary API for this feature.
1 parent 88248fc commit a235572

3 files changed

Lines changed: 26 additions & 287 deletions

File tree

README.md

Lines changed: 1 addition & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -823,8 +823,7 @@ This enables servers to leverage the client's LLM capabilities without needing d
823823
**Using Sampling in Tools:**
824824

825825
Tools that accept a `server_context:` parameter can call `create_sampling_message` on it.
826-
The request is automatically routed to the correct client session.
827-
Set `server.server_context = server` so that `server_context.create_sampling_message` delegates to the server:
826+
The request is automatically routed to the correct client session:
828827

829828
```ruby
830829
class SummarizeTool < MCP::Tool
@@ -852,7 +851,6 @@ class SummarizeTool < MCP::Tool
852851
end
853852

854853
server = MCP::Server.new(name: "my_server", tools: [SummarizeTool])
855-
server.server_context = server
856854
```
857855

858856
**Parameters:**
@@ -873,86 +871,8 @@ Optional:
873871
- `tools:` (Array) - Tools available to the LLM (requires `sampling.tools` capability)
874872
- `tool_choice:` (Hash) - Tool selection mode (e.g., `{ mode: "auto" }`)
875873

876-
**Direct Usage:**
877-
878-
`Server#create_sampling_message` can also be called directly outside of tools:
879-
880-
```ruby
881-
result = server.create_sampling_message(
882-
messages: [
883-
{ role: "user", content: { type: "text", text: "What is the capital of France?" } }
884-
],
885-
max_tokens: 100,
886-
system_prompt: "You are a helpful assistant.",
887-
temperature: 0.7
888-
)
889-
```
890-
891-
Result contains the LLM response:
892-
893-
```ruby
894-
{
895-
role: "assistant",
896-
content: { type: "text", text: "The capital of France is Paris." },
897-
model: "claude-3-sonnet-20240307",
898-
stopReason: "endTurn"
899-
}
900-
```
901-
902-
For multi-client transports (e.g., `StreamableHTTPTransport`), use `server_context.create_sampling_message` inside tools
903-
to route the request to the correct client session.
904-
905-
**Tool Use in Sampling:**
906-
907-
When tools are provided in a sampling request, the LLM can call them during generation.
908-
The server must handle tool calls and continue the conversation with tool results:
909-
910-
```ruby
911-
result = server.create_sampling_message(
912-
messages: [
913-
{ role: "user", content: { type: "text", text: "What's the weather in Paris?" } }
914-
],
915-
max_tokens: 1000,
916-
tools: [
917-
{
918-
name: "get_weather",
919-
description: "Get weather for a city",
920-
inputSchema: {
921-
type: "object",
922-
properties: { city: { type: "string" } },
923-
required: ["city"]
924-
}
925-
}
926-
],
927-
tool_choice: { mode: "auto" }
928-
)
929-
930-
if result[:stopReason] == "toolUse"
931-
tool_results = result[:content].map do |tool_use|
932-
weather_data = get_weather(tool_use[:input][:city])
933-
934-
{
935-
type: "tool_result",
936-
toolUseId: tool_use[:id],
937-
content: [{ type: "text", text: weather_data.to_json }]
938-
}
939-
end
940-
941-
final_result = server.create_sampling_message(
942-
messages: [
943-
{ role: "user", content: { type: "text", text: "What's the weather in Paris?" } },
944-
{ role: "assistant", content: result[:content] },
945-
{ role: "user", content: tool_results }
946-
],
947-
max_tokens: 1000,
948-
tools: [...]
949-
)
950-
end
951-
```
952-
953874
**Error Handling:**
954875

955-
- Raises `RuntimeError` if transport is not set
956876
- Raises `RuntimeError` if client does not support `sampling` capability
957877
- Raises `RuntimeError` if `tools` are used but client lacks `sampling.tools` capability
958878
- Raises `StandardError` if client returns an error response

lib/mcp/server.rb

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -206,44 +206,6 @@ def notify_log_message(data:, level:, logger: nil)
206206
report_exception(e, { notification: "log_message" })
207207
end
208208

209-
# Sends a `sampling/createMessage` request to the client.
210-
# For single-client transports (e.g., `StdioTransport`). For multi-client transports
211-
# (e.g., `StreamableHTTPTransport`), use `ServerSession#create_sampling_message` instead
212-
# to ensure the request is routed to the correct client.
213-
def create_sampling_message(
214-
messages:,
215-
max_tokens:,
216-
system_prompt: nil,
217-
model_preferences: nil,
218-
include_context: nil,
219-
temperature: nil,
220-
stop_sequences: nil,
221-
metadata: nil,
222-
tools: nil,
223-
tool_choice: nil,
224-
related_request_id: nil
225-
)
226-
unless @transport
227-
raise "Cannot send sampling request without a transport."
228-
end
229-
230-
params = build_sampling_params(
231-
@client_capabilities,
232-
messages: messages,
233-
max_tokens: max_tokens,
234-
system_prompt: system_prompt,
235-
model_preferences: model_preferences,
236-
include_context: include_context,
237-
temperature: temperature,
238-
stop_sequences: stop_sequences,
239-
metadata: metadata,
240-
tools: tools,
241-
tool_choice: tool_choice,
242-
)
243-
244-
@transport.send_request(Methods::SAMPLING_CREATE_MESSAGE, params)
245-
end
246-
247209
# Sets a custom handler for `resources/read` requests.
248210
# The block receives the parsed request params and should return resource
249211
# contents. The return value is set as the `contents` field of the response.

0 commit comments

Comments
 (0)