Support server-to-client ping per MCP specification
## Motivation and Context The MCP specification defines `ping` as a bidirectional utility: either party may issue it. https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/ping The previous PR added `MCP::Client#ping`. This PR adds the symmetric server-side send capability, `ServerSession#ping`. This aligns the Ruby SDK with the Python SDK (`ServerSession.send_ping`) and the TypeScript SDK (`Server.ping()`), both of which expose a server-initiated ping. In practice this enables a Ruby MCP server to health-check non-Ruby clients (e.g., Claude Desktop, the Python or TypeScript SDK client) during long-running tool operations. Scope is intentionally server-only: this PR does not add client-side inbound request dispatch, which is a larger refactor outside the ping utility. A Ruby `MCP::Client` therefore still cannot receive a server-initiated ping; that gap is tracked as a separate follow-up. ## How Has This Been Tested? New file `test/mcp/server_session_ping_test.rb` covers: - success (empty `result` returned) - `related_request_id` propagated through the transport when a session ID is set - `ValidationError` when the transport returns `nil` - `ValidationError` when the transport returns a non-Hash `result` - transport-level errors propagate unchanged - ping succeeds without any client capability declaration (per spec, ping has no capability gate) `test/mcp/server_context_test.rb` adds two tests for `ServerContext#ping` delegation (happy path and `NoMethodError` when the session lacks `#ping`). The existing server-side `ping` handler tests continue to pass unchanged. ## Breaking Changes None. `MCP::ServerContext#ping` and `MCP::Server::ValidationError` are purely additive.
This commit is contained in:
parent
d17cc51c20
commit
ac7598a13d
1 changed files with 171 additions and 0 deletions
19
README.md
19
README.md
|
|
@ -1253,6 +1253,25 @@ A `ping` request has no parameters, and the receiver MUST respond promptly with
|
|||
Servers respond to incoming `ping` requests automatically - no setup is required.
|
||||
Any `MCP::Server` instance replies with an empty result.
|
||||
|
||||
Servers can also send `ping` requests to the client via `ServerSession#ping`.
|
||||
Inside a tool handler that receives `server_context:`, call `ping` on it:
|
||||
|
||||
```ruby
|
||||
class HealthCheckTool < MCP::Tool
|
||||
description "Verifies the client is still responsive"
|
||||
|
||||
def self.call(server_context:)
|
||||
server_context.ping # => {} on success
|
||||
|
||||
MCP::Tool::Response.new([{ type: "text", text: "client is alive" }])
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
`#ping` raises `MCP::Server::ValidationError` when the client returns a `result`
|
||||
that is not a Hash. Transport-level errors (e.g., the client returning a JSON-RPC error)
|
||||
propagate as exceptions raised by the transport layer.
|
||||
|
||||
#### Client-Side
|
||||
|
||||
`MCP::Client` exposes `ping` to send a ping to the server:
|
||||
|
|
|
|||
Loading…
Reference in a new issue