Skip to content

fix(server): notifications not delivered over Streamable HTTP (#587)#599

Merged
kpavlov merged 35 commits intomainfrom
kpavlov/fix-sse-notifications
Mar 12, 2026
Merged

fix(server): notifications not delivered over Streamable HTTP (#587)#599
kpavlov merged 35 commits intomainfrom
kpavlov/fix-sse-notifications

Conversation

@kpavlov
Copy link
Contributor

@kpavlov kpavlov commented Mar 12, 2026

Changes

  • fix(server): keep SSE connection open until explicitly cancelled
  • conformance: add logging to test_tool_with_logging and update troubleshooting documentation
  • chore(conformance): remove 5 passing server tests from conformance baselines:
    • tools-call-with-logging
    • tools-call-with-progress
    • tools-call-sampling
    • tools-call-elicitation
    • elicitation-sep1034-defaults

Motivation and Context

Two bugs in StreamableHttpServerTransport caused server-to-client notifications (e.g. notifications/message during tool calls) to be silently dropped.

Bug 1 — GET SSE stream closed immediately

handleGetRequest rejected GET requests with 405 when enableJsonResponse = true (which mcpStreamableHttp always sets). Since the Ktor sse {} handler commits response headers before the body runs, the reject failed silently and the function returned, causing Ktor to close the SSE stream. There was also no awaitCancellation() to keep the connection alive.

Bug 2 — Notifications discarded in JSON mode

In send(), notifications with a relatedRequestId entered the POST-stream path but hit if (!isTerminated) return without being forwarded anywhere.

Fix

  • Remove the enableJsonResponse guard from handleGetRequest. The GET SSE stream is an always-required notification channel, orthogonal to how POST responses are delivered.
  • Add awaitCancellation() to keep the GET SSE connection open until the client disconnects or the transport closes.
    • In send(), route notifications with a relatedRequestId to the standalone GET SSE stream when enableJsonResponse = true.

How Has This Been Tested?

Verified against the MCP conformance test suite — the ToolsCallWithLogging scenario now passes. ngrep confirms the GET /mcp stream stays open and notifications/message events arrive before the tools/call response.

Breaking Changes

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

Additional context

Fixes #587
Requires #585 to be merged first.

devcrocod and others added 30 commits March 6, 2026 18:32
… directory resolution and disabling redundant shellcheck warning
fixes #589 

## How Has This Been Tested?
conformance tests 

## Breaking Changes
NaN

## 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
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed
fixes #588 

## How Has This Been Tested?
conformance test

## Breaking Changes
NaN

## 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
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed
…rios to matrix, and update conformance test baseline
Add configurable SSE reconnection with exponential backoff and
server-driven retry delays to `StreamableHttpClientTransport`

closes #590
closes #420 

## How Has This Been Tested?
New unit tests and pass conformance test 

## Breaking Changes
old constructors are Deprecated
`close` no longer calls `terminateSession`

## Types of changes
- [x] Bug fix (non-breaking change which fixes an issue)
- [x] 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
- Introduced `list` command in `run-conformance.sh` to display available scenarios.
- Updated README with details about the new `list` command and its purpose.
… troubleshooting documentation

- Integrate KotlinLogging for debug messages in `test_tool_with_logging`.
- Add logging configuration via `simplelogger.properties`.
- Expand README with network traffic capture tools and usage examples.
kpavlov added 2 commits March 12, 2026 09:52
- Add `awaitCancellation()` to prevent premature stream closure in SSE handler.
…selines

Following tests are now passing:
- tools-call-with-logging
- tools-call-with-progress
- tools-call-sampling
- tools-call-elicitation
- elicitation-sep1034-defaults
@kpavlov kpavlov changed the base branch from devcrocod/conformance-tests to main March 12, 2026 08:10
@kpavlov kpavlov changed the title Kpavlov/fix sse notifications fix(server): notifications not delivered over Streamable HTTP Mar 12, 2026
@codecov-commenter
Copy link

codecov-commenter commented Mar 12, 2026

Codecov Report

❌ Patch coverage is 20.00000% with 4 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...kotlin/sdk/server/StreamableHttpServerTransport.kt 20.00% 3 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@kpavlov kpavlov changed the base branch from main to devcrocod/conformance-tests March 12, 2026 08:28
@kpavlov kpavlov requested a review from e5l March 12, 2026 09:46
@kpavlov kpavlov changed the title fix(server): notifications not delivered over Streamable HTTP fix(server): notifications not delivered over Streamable HTTP (#587) Mar 12, 2026
@e5l e5l removed their request for review March 12, 2026 12:08
kpavlov added a commit that referenced this pull request Mar 12, 2026
…th retry support (#596) (#585)

Adds a comprehensive conformance test suite for the Kotlin MCP SDK,
covering core protocol operations, tool calls, elicitation, resources,
prompts, and 20 OAuth/auth scenarios

- Conformance server and client implementations
- OAuth/auth test scenarios: JWT, authorization code flow, client
credentials, PKCE, scope handling, cross-app access, client registration
- CI workflow
- Baseline file for tracking expected failures
- Shell script

fixes:
- #592
- #593
- #596


## Remaining known failures (tracked issues, will be fixed directly in
`main`)

- [x] `tools-call-with-logging`, `tools-call-with-progress`,
`tools-call-sampling`, `tools-call-elicitation`,
`elicitation-sep1034-defaults`-  see #599,
- [x] `elicitation-sep1330-enums` - #587 #600
- [x] `initialize` - #588 
- [x] `tools_call`, `auth/scope-step-up`, `auth/scope-retry-limit` -
#589
- [ ] `elicitation-sep1034-client-defaults` - #414 
- [x] `sse-retry` - #590 
- [ ] `resources-templates-read` - #591 

## Breaking Changes
from #596 
- `StreamableHttpClientTransport` and
`mcpStreamableHttp`/`mcpStreamableHttpTransport`: old constructors
accepting `Duration` timeout are now `@Deprecated` — use the new
overloads with `ReconnectionOptions` instead
- `StreamableHttpClientTransport.close()` no longer calls
`terminateSession()` automatically

## Types of changes
- [x] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [x] 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

---------

Co-authored-by: Konstantin Pavlov <1517853+kpavlov@users.noreply.github.com>
Base automatically changed from devcrocod/conformance-tests to main March 12, 2026 13:45
# Conflicts:
#	conformance-test/conformance-baseline.yml
#	conformance-test/src/main/kotlin/io/modelcontextprotocol/kotlin/sdk/conformance/ConformanceTools.kt
#	conformance-test/src/main/resources/simplelogger.properties
@kpavlov kpavlov marked this pull request as ready for review March 12, 2026 13:50
…scenarios

- Removed 5 server tests (`tools-call-with-logging`, `tools-call-with-progress`, `tools-call-sampling`, `tools-call-elicitation`, `elicitation-sep1034-defaults`) that now pass.
@kpavlov kpavlov requested a review from devcrocod March 12, 2026 14:10
@kpavlov kpavlov added the bugfix Something was fixed 🎉 label Mar 12, 2026
Copy link
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.

lgtm

@@ -114,16 +114,11 @@ Tests the conformance server against all server scenarios:
8 scenarios are expected to fail due to current SDK limitations (tracked in [
Copy link
Contributor

Choose a reason for hiding this comment

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

Please reduce the number of expected failed scenarios

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do it in the next PR

@kpavlov kpavlov merged commit 736efe9 into main Mar 12, 2026
24 of 25 checks passed
@kpavlov kpavlov deleted the kpavlov/fix-sse-notifications branch March 12, 2026 14:52
kpavlov added a commit that referenced this pull request Mar 12, 2026
…ep1330_enums (#600)

## Correct SEP-1330 enum schemas in test_elicitation_sep1330_enums

**NB! This PR contains changes from #599 and should be rebased and
merged after #599 is merged.**

Update conformance test according to [test
requirements](https://github.com/modelcontextprotocol/conformance/blob/main/src/scenarios/server/elicitation-enums.ts#L14C1-L35C9).

- Fix legacyEnum: was using `oneOf` with const/title pairs; now
correctly uses `enum` + `enumNames` arrays per LegacyEnumSchema spec
- Fix titledMulti: items were using `oneOf` with extra `type:"string"`;
now correctly uses `anyOf` per TitledMultiSelectEnumSchema spec
- Fix return text format to match expected "Elicitation completed:
action=..., content=..."
- Remove _elicitation-sep1330-enums_ from conformance baseline (test now
passes)

## How Has This Been Tested?

```shell
./conformance-test/run-conformance.sh server
```

## Breaking Changes
No

## 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
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [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
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

---------

Co-authored-by: devcrocod <devcrocod@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Something was fixed 🎉

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Server-initiated notifications from tool handlers are not delivered to the client

3 participants