-
Notifications
You must be signed in to change notification settings - Fork 2.7k
feat: start and close ClientSession in a single task in McpSessionManager #4025
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?
feat: start and close ClientSession in a single task in McpSessionManager #4025
Conversation
Create a wrapper which wraps client creation and termination with a single task. This prevents AnyIO's CancelScope error ('Attempted to exit cancel scope in a different task than it was entered in') since creation and deletion happens in a single task.
Task throws exception when it is not done.
Test cases are copied from the existing session manager test, except the one copied from the PR google#3835.
Since we are handling AnyIO CancelScope with a background task, test cases are mostly focused on testing exception handling and resource cleanup works correctly.
By using SessionContext, we can wrap client into a single task, so that the client could be started and closed by same task.
Since transports are created inside of the SessionContext, AsyncExitStack does not return them.
Since `McpSessionManager` only references `SessionContext`, and `SessionContext` now handles `ClientSession`, validation of `ClientSession` should be executed in the test code of `SessionContext` not `McpSessionManager`. - Therefore we are moving Session state validation into test_session_context and using mockup for SessionContext. - Session open/close are still able to test since manager has own dictionary of it.
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
Summary of ChangesHello @challenger71498, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses critical issues in the Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
|
Response from ADK Triaging Agent Hello @challenger71498, thank you for your contribution! Before we can merge this PR, could you please sign the Contributor License Agreement (CLA)? You can find more information on how to do this in the "cla/google" check at the bottom of this page. Also, could you please provide details on the manual end-to-end (E2E) tests you performed for these changes? This will help the reviewers to better understand and verify your work. Thank you! |
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.
Code Review
This pull request introduces a robust solution to a tricky asyncio task management issue with anyio by encapsulating the ClientSession lifecycle within a dedicated SessionContext class. This is a great architectural improvement that correctly handles structured concurrency. The addition of timeouts for tool calls is another valuable enhancement for the tool's reliability. The new SessionContext is thoroughly tested, and existing tests are updated accordingly, which is excellent. I have a couple of minor suggestions to further improve code clarity and cleanliness.
Please ensure you have read the contribution guide before creating a pull request.
Link to Issue or Description of Change
1. Link to an existing issue (if applicable):
2. Or, if no issue exists, describe the change:
Problem:
ClientSessionof https://github.com/modelcontextprotocol/python-sdk uses AnyIO for async task management.McpSessionManagerdoes not create task per client, the client might be closed by different task, cause the error:Attempted to exit cancel scope in a different task than it was entered in.Solution:
I Suggest 2 changes:
Handling the
ClientSessionin a single taskClientSessionby the same task, we need to wrap the whole lifecycle ofClientSessionto a single task.SessionContextwraps the initialization and disposal ofClientSessionto a single task, ensures that theClientSessionwill be handled only in a dedicated task.Add timeout for
ClientSessionClientSession, task should never be leaked.McpSessionManagerdoes not deliver timeout directly toClientSessionwhen the type is not STDIO.httpxclient when MCP type is SSE or StreamableHTTP.httpxclient, so if there is an issue in MCP client itself(e.g. cannot get response from await session.call_tool() modelcontextprotocol/python-sdk#262), a tool call waits the result FOREVER!sse_read_timeouttoClientSession.timeoutis too short for timeout for tool call, since its default value is only 5s.sse_read_timeoutis originally made for read timeout of SSE(default value of 5m or 300s), but actually most of SSE implementations from server (e.g. FastAPI, etc.) sends ping periodically(about 15s I assume), so in a normal circumstances this timeout is quite useless.sse_read_timeoutas tool call timeout.tool_call_timeout).Testing Plan
initialize()called).SessionContext, we cannot validate the initialized state of the session inTestMcpSessionManager, should validate it atTestSessionContext.test_create_and_close_session_in_different_tasks).SessionContext.Unit Tests:
Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any
necessary setup or configuration. Please provide logs or screenshots to help
reviewers better understand the fix.
Checklist
Any dependent changes have been merged and published in downstream modules.no deps has been changedAdditional context
This PR is related to modelcontextprotocol/python-sdk#1817 since it also fixes endless tool call awaiting.