Support sampling/createMessage per MCP specification#282
Open
koic wants to merge 1 commit intomodelcontextprotocol:mainfrom
Open
Support sampling/createMessage per MCP specification#282koic wants to merge 1 commit intomodelcontextprotocol:mainfrom
sampling/createMessage per MCP specification#282koic wants to merge 1 commit intomodelcontextprotocol:mainfrom
Conversation
## Motivation and Context The MCP specification defines `sampling/createMessage` to request LLM completions from the client. The Ruby SDK did not yet support server-to-client requests, so the server had no way to ask the client to sample an LLM. This caused the `tools-call-sampling` conformance test to fail. This adds `Server#create_sampling_message` to send a `sampling/createMessage` request to the client via the transport layer. The method validates that the client declared the `sampling` capability during initialization, and optionally checks the `sampling.tools` capability when tools or tool_choice parameters are provided. On the transport side, `Transport#send_request` is introduced as an abstract method, with implementations in both `StdioTransport` and `StreamableHTTPTransport`. Each transport assigns a unique request ID, sends the JSON-RPC request to the client, and blocks until the client responds. Client capabilities are stored per session via `ServerSession`, so validation is scoped to the originating client. `ServerSession#create_sampling_message` uses `build_sampling_params` for capability validation and sends the request directly through the transport with the session ID, following the same pattern as `notify_progress`. `Server#create_sampling_message` is the public API for single-client transports (e.g., StdioTransport). For multi-client transports (e.g., StreamableHTTPTransport), `ServerSession#create_sampling_message` must be used to route requests to the correct client. Tools using `server_context.create_sampling_message` automatically route to the correct session regardless of transport. `StreamableHTTPTransport#send_request` requires `session_id` to prevent broadcasting sampling requests to all connected clients. Missing or invalid session IDs raise explicit errors instead of silently failing. The `include_context` parameter is soft-deprecated in the MCP specification but is included for compatibility with existing clients that declare the `sampling.context` capability. Python and TypeScript SDKs also retain this parameter. Ref: https://modelcontextprotocol.io/specification/latest/server/utilities/sampling ## How Has This Been Tested? Added comprehensive tests in `test/mcp/server_sampling_test.rb` covering required and optional parameters, capability validation, error handling, nil-param omission, per-session capability isolation, and HTTP init capability scoping. Added transport tests in `test/mcp/server/transports/stdio_transport_test.rb` and `test/mcp/server/transports/streamable_http_transport_test.rb` for `send_request` round-trip behavior, error responses, stateless mode rejection, missing session_id, invalid session_id, and no-active-stream error. Conformance: `tools-call-sampling` is removed from expected failures. The conformance server's `TestSampling` tool now calls `server_context.create_sampling_message` instead of returning a stub error. This aligns the Ruby SDK with the MCP specification and other SDK implementations. ## Breaking Change None for end users. `Transport#send_request` is a new abstract method. `ServerSession#create_sampling_message` is a new method.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation and Context
The MCP specification defines
sampling/createMessageto request LLM completions from the client. The Ruby SDK did not yet support server-to-client requests, so the server had no way to ask the client to sample an LLM. This caused thetools-call-samplingconformance test to fail.This adds
Server#create_sampling_messageto send asampling/createMessagerequest to the client via the transport layer. The method validates that the client declared thesamplingcapability during initialization, and optionally checks thesampling.toolscapability when tools or tool_choice parameters are provided.On the transport side,
Transport#send_requestis introduced as an abstract method, with implementations in bothStdioTransportandStreamableHTTPTransport. Each transport assigns a unique request ID, sends the JSON-RPC request to the client, and blocks until the client responds.Client capabilities are stored per session via
ServerSession, so validation is scoped to the originating client.ServerSession#create_sampling_messageusesbuild_sampling_paramsfor capability validation and sends the request directly through the transport with the session ID, following the same pattern asnotify_progress.Server#create_sampling_messageis the public API for single-client transports (e.g., StdioTransport).For multi-client transports (e.g., StreamableHTTPTransport),
ServerSession#create_sampling_messagemust be used to route requests to the correct client. Tools usingserver_context.create_sampling_messageautomatically route to the correct session regardless of transport.StreamableHTTPTransport#send_requestrequiressession_idto prevent broadcasting sampling requests to all connected clients. Missing or invalid session IDs raise explicit errors instead of silently failing.The
include_contextparameter is soft-deprecated in the MCP specification but is included for compatibility with existing clients that declare thesampling.contextcapability. Python and TypeScript SDKs also retain this parameter.Ref: https://modelcontextprotocol.io/specification/latest/server/utilities/sampling
How Has This Been Tested?
Added comprehensive tests in
test/mcp/server_sampling_test.rbcovering required and optional parameters, capability validation, error handling, nil-param omission, per-session capability isolation, and HTTP init capability scoping.Added transport tests in
test/mcp/server/transports/stdio_transport_test.rbandtest/mcp/server/transports/streamable_http_transport_test.rbforsend_requestround-trip behavior, error responses, stateless mode rejection, missing session_id, invalid session_id, and no-active-stream error.Conformance:
tools-call-samplingis removed from expected failures. The conformance server'sTestSamplingtool now callsserver_context.create_sampling_messageinstead of returning a stub error.This aligns the Ruby SDK with the MCP specification and other SDK implementations.
Breaking Change
None for end users.
Transport#send_requestis a new abstract method.ServerSession#create_sampling_messageis a new method.Types of changes
Checklist