-
Notifications
You must be signed in to change notification settings - Fork 80
[Server] Add Bidirectional Client Communication Support #109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Server] Add Bidirectional Client Communication Support #109
Conversation
| $meta = $data['params']['_meta']; | ||
| if ($meta instanceof \stdClass) { | ||
| $meta = (array) $meta; | ||
| } | ||
| if (\is_array($meta)) { | ||
| $request->meta = $meta; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if that's something we should be able to control instead of having it ambigous?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm 🤔. What do you mean by control in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is it an array or an object? isn't that something we can handle more strict?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the spec, there’s no strict structure defined for request metadata. The progress token is the only documented key so far, but servers and clients are allowed to attach arbitrary metadata to their requests.
69000ec to
5db83d4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could pull out some changes here into separate PRs to get the diff smaller, or debate on the size of the TransportInterface - but that's also fine as a follow up to get this in and get going with the next features on top of it.
Thanks for tackling that mind-twisting exercise @CodeWithKyrian!
This PR introduces full bidirectional communication between MCP servers and clients, letting tools surface outbound requests, logging, and progress updates while awaiting client responses (for server requests).
Motivation and Context
What’s Changed
Protocolwith callbacks so transports can track pending requests, resume suspended handlers (immediate for notifications and with client responses for pending requests), and flush queued messages for a session.ClientGatewaywith a straightforward API to send server-initiated requests and notifications. with helpers for logging, progress and sampling.ReferenceHandlerauto-injects it whileSchemaGeneratorhides it from generated tool schemas so type-hinted parameters stay internal.BaseTransportandManagesTransportCallbacks, reducing boilerplate for message/session/fiber wiring in Transports.StdioTransportto poll input without blocking usingstream_set_blocking($stdin, false), enabling it to process suspended fibers, flush queued messages, and then return to polling input without stalling.StreamableHttpTransportwith SSE support via a newCallbackStream, allowing suspended handlers to stream notifications and await client responses over the same request.RequestHandlerInterface, genericResponse) and augmentedRequestwith meta/id accessors and setters so server-originated requests can be cloned safely.Additional Notes
ClientGatewayis adapted from [Server] Introduce ClientAwareInterface and Trait #101 so I could actually test the bidirectional flow; its interface and injection strategy is not set in stone, and can still evolve there if this is merged. This patch just wires it in viaReferenceHandlerpurely to validate the transport/protocol changes.StreamableHttpTransport. This functionality depends on the GET streaming endpoint which isn't implemented yet.Breaking Changes
None. Existing transports and handlers continue to work; new behavior is opt-in through the injected gateway.