kotlin-sdk/kotlin-sdk-client
Repository files (latest commit first)
Filename Latest commit message Latest commit date
johny 44e012e4ee
fix(client): invoke onClose when SSE session disconnects (#437) (#738)
Fixes the SSE client transport so that registered `onClose` callbacks
fire when the underlying SSE session ends — whether the server closes
the stream gracefully or an error event terminates it.

closes #437

## Motivation and Context
`SseClientTransport.collectMessages` already runs `closeResources()` in
its `finally` block when `session.incoming` completes, but it never
invoked the `onClose` callback chain. As a result, the MCP `Client` (and
any user code calling `transport.onClose { ... }`) had no way to detect
that the server-side SSE connection had dropped.

The other client transports already do this correctly:
- `StdioClientTransport` calls `invokeOnCloseCallback()` from its
read-loop `finally`
(kotlin-sdk-client/src/.../StdioClientTransport.kt:224).
- The protected `AbstractTransport.invokeOnCloseCallback()` helper
guards against duplicate firing with an `AtomicBoolean`, so it is safe
to call from both the read-loop `finally` and the user-initiated
`close()` path.

The fix mirrors that established pattern in one line.

## How Has This Been Tested?
Added `onClose callback fires when the SSE stream is disconnected by the
server` to `SseClientTransportTest`. The test:

1. Starts the transport against a mock SSE engine.
2. Closes the SSE byte channel server-side via a new
`MockSseClientEngine.disconnectSseStream()` helper.
3. Asserts the registered `onClose` callback fires (using Kotest
`eventually`, since the close propagates on a real-time dispatcher).

I also verified the test fails before the fix and passes after.

```
./gradlew :kotlin-sdk-client:jvmTest
./gradlew apiCheck ktlintCheck detekt
```

## Breaking Changes
None. `invokeOnCloseCallback()` is `protected` on `AbstractTransport`;
this PR only adds a call site inside `SseClientTransport`. No public API
surface changes.

## Types of changes
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed
2026-05-15 18:44:16 +02:00
..
api feat!: SEP-1577 sampling with tools (#718) 2026-04-28 17:51:48 +02:00
src fix(client): invoke onClose when SSE session disconnects (#437) (#738) 2026-05-15 18:44:16 +02:00
build.gradle.kts refactor: explicit locked detekt config (#729) 2026-04-29 12:31:49 +02:00
detekt-baseline-main.xml refactor: explicit locked detekt config (#729) 2026-04-29 12:31:49 +02:00
Module.md docs: Update readme, enable Knit (#162) (#510) 2026-02-06 18:40:31 +02:00