Skip to content

feat(server): add onSessionClose hook to ClientConnection#737

Open
jskjw157 wants to merge 1 commit into
modelcontextprotocol:mainfrom
jskjw157:feature/issue-553-session-cleanup
Open

feat(server): add onSessionClose hook to ClientConnection#737
jskjw157 wants to merge 1 commit into
modelcontextprotocol:mainfrom
jskjw157:feature/issue-553-session-cleanup

Conversation

@jskjw157
Copy link
Copy Markdown
Contributor

@jskjw157 jskjw157 commented Apr 30, 2026

Adds an onSessionClose(block: () -> Unit) hook on ClientConnection, delegating to the existing callback chain on ServerSession.onClose.

closes #553

Motivation and Context

Tool, prompt, and resource handlers often acquire session-scoped resources — DB connections, temporary files, background coroutines — that need to be released when the session terminates. Today there's no first-class way for a handler to register that cleanup: the only workaround is to fish the ServerSession out of the Server via sessionId and call its internal onClose, which is awkward and easy to get wrong.

This mirrors the access pattern from #552 (#733): expose what ServerSession already does through the public ClientConnection surface so handlers can reach it directly.

How Has This Been Tested?

Two integration tests in ClientConnectionTest:

  • onSessionClose callback runs when the session closes — register from a tool handler, close the client, assert the callback fires.
  • multiple onSessionClose callbacks run in registration order — verifies the documented ordering guarantee inherited from ServerSession.onClose.

Only the tool-handler case is exercised because onSessionClose is session-scoped — the registration site (tool vs. prompt vs. resource) doesn't change behavior, and adding three near-identical tests would just be noise.

./gradlew :integration-test:jvmTest --tests "*ClientConnectionTest"
./gradlew :kotlin-sdk-server:apiCheck
./gradlew :kotlin-sdk-server:detekt
./gradlew ktlintCheck

Breaking Changes

None for consumers. Adds one abstract method to ClientConnection, which would require any external implementer to recompile — but ClientConnectionImpl is the only implementation and is internal.

Types of changes

  • 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

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

@jskjw157
Copy link
Copy Markdown
Contributor Author

jskjw157 commented Apr 30, 2026

@devcrocod follow-up to #733 — same access pattern, just delegating to the existing ServerSession.onClose chain. Happy to adjust the API shape (e.g. naming, returning a deregistration handle) if you'd prefer something different.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new public cleanup hook to the server-side handler surface by exposing ServerSession.onClose via ClientConnection.onSessionClose, enabling tools/prompts/resources to register session-scoped resource cleanup directly.

Changes:

  • Add ClientConnection.onSessionClose(block: () -> Unit) and delegate to ServerSession.onClose.
  • Update public API dump to include the new method.
  • Add integration tests asserting callback execution on close and registration-order invocation.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ClientConnection.kt Adds the onSessionClose API and delegates to ServerSession close callback chain.
kotlin-sdk-server/api/kotlin-sdk-server.api Updates API surface to include onSessionClose.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ClientConnectionTest.kt Adds integration tests for onSessionClose execution and ordering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +315 to +317
override fun onSessionClose(block: () -> Unit) {
session.onClose(block)
}
}

override fun onSessionClose(block: () -> Unit) {
session.onClose(block)
Copy link
Copy Markdown
Contributor

@devcrocod devcrocod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some doubts
On the one hand, this is a useful method. On the other hand, it significantly blurs the responsibility of ClientConnection, since it adds lifecycle management to it

notification(notification)
}

override fun onSessionClose(block: () -> Unit) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a callback is registered after the session has already been closed, it will never be invoked

notification(notification)
}

override fun onSessionClose(block: () -> Unit) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this could potentially cause a leak. Would it make sense to use DisposableHandle?

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.

Add a way to register session cleanup actions from server handlers

3 participants