Transient integration-loader failures disable tools until process restart
Summary
DynamicToolMiddleware permanently caches an empty tool set when an integration loader fails once.
Code reference
agent/middleware/dynamic_tools.py:165-179
_resolve() catches every loader exception, stores tools = [], and sets resolved.done = True. All later calls return the cached empty result without attempting another handshake.
Reproduction
Use an IntegrationGroup whose loader raises on its first call and returns a valid tool on its second call. Call _build(["working_tool"]) twice. The second call still reports the tool unavailable and the loader invocation count remains one.
Expected behavior
Transient MCP, credential, or network failures should be retried on a later request, ideally with bounded backoff/TTL to avoid a thundering herd.
Actual behavior
The first failure is treated as a permanent process-lifetime result. Recovery requires restarting the application.
Why it matters
A short-lived integration outage can silently disable connected tools for every thread handled by that process.
Suggested fix
Do not mark failed resolutions as complete, or cache failures with an expiry and retry policy. Add a regression test where the first load fails and the next load succeeds.
Source: langchain-ai/open-swe