-
Notifications
You must be signed in to change notification settings - Fork 323
mcp: add DisableListening option to StreamableClientTransport #729
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
base: main
Are you sure you want to change the base?
Conversation
findleyr
left a comment
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.
Thanks for this PR!
|
|
||
| // DisableListening disables receiving server-to-client notifications when no request is in flight. | ||
| // | ||
| // By default, the client establishes a standalone long-live GET HTTP connection to the server |
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.
long-lived
| // It defaults to 5. To disable retries, use a negative number. | ||
| MaxRetries int | ||
|
|
||
| // DisableListening disables receiving server-to-client notifications when no request is in flight. |
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.
"disables the standalone GET request that receives server-initiated messages and notifications."
- it's not just notifications: it can also be requests
- it's not related to whether a request is in flight: a request could be in flight, and yet the server sends messages unassociated with that request.
| // It defaults to 5. To disable retries, use a negative number. | ||
| MaxRetries int | ||
|
|
||
| // DisableListening disables receiving server-to-client notifications when no request is in flight. |
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.
Should we just call this "DisableStandaloneSSE" to be clear? What do other SDKs call it, if they have such a setting?
| // If true, the client will not establish the standalone SSE stream and will only receive | ||
| // responses to its own requests. | ||
| // | ||
| // Defaults to false to maintain backward compatibility with existing behavior. |
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.
Let's omit this last sentence: it's documenting the change (adding a new field), not the steady state.
It defaults to false because we thought the SSE stream should be established by default (which IIRC is consistent with other SDKs). I don't think we need to caveat it.
| // Endpoint: "http://localhost:8080/mcp", | ||
| // } | ||
| // mcp.WithDisableListening(transport) | ||
| func WithDisableListening(transport *StreamableClientTransport) { |
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 would we have this function when there's already a field on the StreamableClientTransport?
mcp: add DisableListening option to control standalone SSE stream
Currently, StreamableClientTransport always establishes a standalone SSE connection after initialization to receive server-initiated messages. While this is useful for receiving notifications like ToolListChangedNotification, it causes problems in several real-world scenarios:
Unnecessary resource usage: Many use cases (for me), especially in scientific computing scenarios, only require simple request-response communication. Clients don't need server-initiated notifications, making the persistent SSE connection wasteful.
Server compatibility issues: Some third-party MCP servers don't properly handle GET requests for SSE streams. When the client automatically tries to establish the SSE connection, it fails or hangs, blocking the entire connection process. This is particularly problematic when using third-party servers that cannot be modified. This issue is similar to what was discussed in issue streamable HTTP client: Don't block on standalone SSE Get #634.
Lack of user control: The MCP specification states that the standalone SSE stream is optional ("The client MAY issue an HTTP GET"), but the current SDK implementation doesn't provide a way to opt out. This implementation is also inconsistent with other MCP SDKs like github.com/mark3labs/mcp-go, which provides getListeningEnabled control (defaults to false, requires explicit enablement).
This change adds a DisableListening boolean field to StreamableClientTransport that allows users to control whether the client establishes the standalone SSE stream. The default value is false, maintaining backward compatibility with current behavior. When set to true, the client skips establishing the standalone SSE connection.
The implementation includes DisableListening bool field in StreamableClientTransport, WithDisableListening() convenience function, conditional logic in sessionUpdated() to respect the option, and comprehensive tests in TestStreamableClientDisableListening.
Fixes #728