File: src/entrabot/a365/mcp_client.py
Location: L56-L94 (init + call_tool)
Category: leak
Priority: low
Description
WorkIqMcpClient stores transport once and on every call_tool does "async with httpx.AsyncClient(transport=self._transport) as client". httpx closes mounted transports (including the injected default) when the AsyncClient context exits. Because WorkIqProvider holds a single WorkIqMcpClient instance for the life of the provider (provider.py:30), any production caller that injects a transport for reuse will get a closed transport on the second call. Default-path callers (no transport) are unaffected; respx tests unaffected.
Suggested fix
Either build a single httpx.AsyncClient once in WorkIqMcpClient (own its lifecycle via an explicit aclose) and reuse it across calls, or stop passing self._transport into a context-managed AsyncClient when it was externally provided.
Filed automatically by a thorough code-review pass over src/entrabot/ on 2026-06-13. Internal review id: #27.
File:
src/entrabot/a365/mcp_client.pyLocation: L56-L94 (init + call_tool)
Category: leak
Priority: low
Description
WorkIqMcpClient stores transport once and on every call_tool does "async with httpx.AsyncClient(transport=self._transport) as client". httpx closes mounted transports (including the injected default) when the AsyncClient context exits. Because WorkIqProvider holds a single WorkIqMcpClient instance for the life of the provider (provider.py:30), any production caller that injects a transport for reuse will get a closed transport on the second call. Default-path callers (no transport) are unaffected; respx tests unaffected.
Suggested fix
Either build a single httpx.AsyncClient once in WorkIqMcpClient (own its lifecycle via an explicit aclose) and reuse it across calls, or stop passing self._transport into a context-managed AsyncClient when it was externally provided.
Filed automatically by a thorough code-review pass over
src/entrabot/on 2026-06-13. Internal review id: #27.