Support ping client API per MCP specification
## Motivation and Context The MCP specification defines the `ping` utility for verifying that the peer of a connection is still responsive. The Ruby SDK server side already replies to incoming `ping` requests with an empty result, but `MCP::Client` had no public API to send a `ping` request. Users had to build the JSON-RPC payload themselves and call the transport directly. This adds a client-side counterpart to the existing server handler and aligns the Ruby SDK in spirit with the Python and TypeScript SDKs, which expose `ClientSession.send_ping` and `Client.ping` respectively. Those SDKs validate the response envelope via type schemas (`EmptyResult` / `EmptyResultSchema`) and raise their validation library's generic exception (Pydantic's `ValidationError` / Zod's `ZodError`). The Ruby client applies a Hash type check on `result` (matching Python's behavior of requiring a dict while allowing arbitrary contents) and raises a new `MCP::Client::ValidationError` for malformed responses, keeping `MCP::Client::ServerError` reserved for JSON-RPC error responses. ## How Has This Been Tested? Client tests cover: - request structure (method is `ping`, no `params`) - empty result on success - `ServerError` on JSON-RPC error response - `ValidationError` on a response missing `result` - `ValidationError` on a `result` of the wrong type (e.g., String) - propagation of transport-level errors raised by `transport.send_request` The existing server-side `ping` handler tests continue to pass unchanged. ## Breaking Changes None. `MCP::Client#ping` and `MCP::Client::ValidationError` are purely additive. The server-side `ping` handler behavior is unchanged.
This commit is contained in:
parent
2edba778f0
commit
493321ca46
1 changed files with 112 additions and 0 deletions
|
|
@ -28,6 +28,11 @@ module MCP
|
|||
end
|
||||
end
|
||||
|
||||
# Raised when a server response fails client-side validation, e.g., a success response
|
||||
# whose `result` field is missing or has the wrong type. This is distinct from a
|
||||
# server-returned JSON-RPC error, which is raised as `ServerError`.
|
||||
class ValidationError < StandardError; end
|
||||
|
||||
# Initializes a new MCP::Client instance.
|
||||
#
|
||||
# @param transport [Object] The transport object to use for communication with the server.
|
||||
|
|
@ -303,6 +308,24 @@ module MCP
|
|||
response.dig("result", "completion") || { "values" => [], "hasMore" => false }
|
||||
end
|
||||
|
||||
# Sends a `ping` request to the server to verify the connection is alive.
|
||||
# Per the MCP spec, the server responds with an empty result.
|
||||
#
|
||||
# @return [Hash] An empty hash on success.
|
||||
# @raise [ServerError] If the server returns a JSON-RPC error.
|
||||
# @raise [ValidationError] If the response `result` is missing or not a Hash.
|
||||
#
|
||||
# @example
|
||||
# client.ping # => {}
|
||||
#
|
||||
# @see https://modelcontextprotocol.io/specification/latest/basic/utilities/ping
|
||||
def ping
|
||||
result = request(method: Methods::PING)["result"]
|
||||
raise ValidationError, "Response validation failed: missing or invalid `result`" unless result.is_a?(Hash)
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def request(method:, params: nil)
|
||||
|
|
|
|||
Loading…
Reference in a new issue