Skip to content

WIP: feat: expose server notifications as an effect-specific stream - #232

Draft
sideeffffect wants to merge 1 commit into
softwaremill:masterfrom
sideeffffect:feat/server-notifications-stream
Draft

WIP: feat: expose server notifications as an effect-specific stream#232
sideeffffect wants to merge 1 commit into
softwaremill:masterfrom
sideeffffect:feat/server-notifications-stream

Conversation

@sideeffffect

Copy link
Copy Markdown

Closes #222.

What

Alongside the existing callback API (onServerNotification), each streaming client module now exposes server-pushed notifications as a stream native to its effect backend, via a serverNotifications extension on BidirectionalMcpClient:

Module Type
chimp-client-ox ox.flow.Flow[ServerNotification]
chimp-client-zio ZStream[Any, Throwable, ServerNotification]
chimp-client-pekko Source[ServerNotification, NotUsed]

Each stream registers a listener when it is run/materialized and removes it when it finishes, so it does not leak listeners for the lifetime of the client.

import chimp.client.transport.zio.*

val notifications: ZStream[Any, Throwable, ServerNotification] = client.serverNotifications

How

  • BidirectionalMcpClient gains removeServerNotification(listener) (listeners compared by reference) so the streams can release their listener on completion. This is the only change to the public core API; the only implementor of the trait is the internal client impl.
  • ox uses an unbounded channel and zio an unbounded queue, so delivery never blocks the transport read loop; pekko uses a BoundedSourceQueue (synchronous, order-preserving FIFO) that drops the newest notification when the buffer is full.

Tests

  • Core: CapabilityHandlerSpec gets a case asserting removeServerNotification stops delivery.
  • One spec per backend ({Ox,Zio,Pekko}ServerNotificationsSpec) driving a shared FakeNotificationClient, asserting the stream emits pushed notifications in order and removes its listener when done.
  • sbt scalafmtCheckAll compile Test/compile compileDocs and the affected unit suites pass locally.

Notes

  • Buffering/overflow semantics differ slightly per backend to fit each concurrency model; documented in the scaladoc and docs/client/capabilities.md.
  • Marked as a draft/WIP.

🤖 Generated with Claude Code

Add a `serverNotifications` extension to each streaming client module that
surfaces server-pushed notifications as a stream native to the effect
backend: an `ox.flow.Flow` for chimp-client-ox, a `ZStream` for
chimp-client-zio, and a Pekko `Source` for chimp-client-pekko. Each stream
registers a listener when it is run and removes it when it finishes.

To support clean removal, `BidirectionalMcpClient` gains a
`removeServerNotification` method (listeners are compared by reference).

Closes softwaremill#222

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sideeffffect sideeffffect changed the title feat: expose server notifications as an effect-specific stream WIP: feat: expose server notifications as an effect-specific stream Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider making client notification a stream

1 participant