MCPcopy Create free account
hub / github.com/google/adk-python / _run

Method _run

src/google/adk/tools/mcp_tool/session_context.py:248–324  ·  view source on GitHub ↗

Run the complete session context within a single task.

(self)

Source from the content-addressed store, hash-verified

246 await self.close()
247
248 async def _run(self):
249 """Run the complete session context within a single task."""
250 try:
251 async with AsyncExitStack() as exit_stack:
252 if is_feature_enabled(FeatureName._MCP_GRACEFUL_ERROR_HANDLING): # pylint: disable=protected-access
253 # Post-fix: do NOT wrap in asyncio.wait_for. The MCP client uses
254 # AnyIO TaskGroup/CancelScope internally, which must be entered
255 # and exited in the same task. asyncio.wait_for runs its target
256 # in a nested task and can cancel from a different task on
257 # timeout, producing "Attempted to exit cancel scope in a
258 # different task" errors. The connection-establishment timeout
259 # is still enforced by MCPSessionManager.create_session via its
260 # outer asyncio.wait_for around
261 # exit_stack.enter_async_context(SessionContext(...)).
262 transports = await exit_stack.enter_async_context(self._client)
263 else:
264 # Pre-fix behavior: wrap with asyncio.wait_for so the inner
265 # context entry has its own timeout. Callers that depend on
266 # this inner timeout firing rely on this path; without it,
267 # mocks that delay `__aenter__` cause tests to time out at the
268 # test framework limit instead of the configured per-step timeout.
269 transports = await asyncio.wait_for(
270 exit_stack.enter_async_context(self._client),
271 timeout=self._timeout,
272 )
273 # The streamable http client returns a GetSessionCallback in addition
274 # to the read/write MemoryObjectStreams needed to build the
275 # ClientSession. We limit to the first two values to be compatible
276 # with all clients.
277 if self._is_stdio:
278 session = await exit_stack.enter_async_context(
279 ClientSession(
280 *transports[:2],
281 read_timeout_seconds=timedelta(seconds=self._timeout)
282 if self._timeout is not None
283 else None,
284 sampling_callback=self._sampling_callback,
285 sampling_capabilities=self._sampling_capabilities,
286 )
287 )
288 else:
289 # For SSE and Streamable HTTP clients, use the sse_read_timeout
290 # instead of the connection timeout as the read_timeout for the session.
291 session = await exit_stack.enter_async_context(
292 ClientSession(
293 *transports[:2],
294 read_timeout_seconds=timedelta(seconds=self._sse_read_timeout)
295 if self._sse_read_timeout is not None
296 else None,
297 sampling_callback=self._sampling_callback,
298 sampling_capabilities=self._sampling_capabilities,
299 )
300 )
301 # pylint: disable-next=protected-access
302 if is_feature_enabled(FeatureName._MCP_GRACEFUL_ERROR_HANDLING):
303 # Use anyio.fail_after to keep session.initialize within the AnyIO
304 # cancel scope instead of asyncio.wait_for which runs in a nested
305 # task.

Callers 1

startMethod · 0.95

Calls 4

is_feature_enabledFunction · 0.85
initializeMethod · 0.45
setMethod · 0.45
waitMethod · 0.45

Tested by

no test coverage detected