Federico Mariani created CAMEL-23957:
----------------------------------------
Summary: camel-openai: MCP reconnect mutates shared endpoint tool
state without synchronization
Key: CAMEL-23957
URL: https://issues.apache.org/jira/browse/CAMEL-23957
Project: Camel
Issue Type: Bug
Components: camel-openai
Affects Versions: 4.21.0
Reporter: Federico Mariani
{{OpenAIEndpoint}} holds the MCP tool state in plain unsynchronized collections
shared by all concurrent exchanges (lines 89-93): {{cachedMcpTools}}
({{ArrayList}}), {{toolClientMap}} ({{HashMap}}), {{returnDirectTools}}
({{HashSet}}), {{toolToServerName}} ({{HashMap}}).
When {{mcpReconnect=true}} (the default), {{reconnectMcpServer}} (lines
288-352) structurally modifies all of them at runtime —
{{toolClientMap.entrySet().removeIf(...)}}, {{cachedMcpTools.removeIf(...)}} /
{{addAll(...)}}, {{toolClientMap.put(...)}} — while other exchanges
concurrently:
* iterate {{getMcpTools()}} in {{OpenAIProducer.processInternal}} (for-each
over the same {{ArrayList}}) to build the request →
{{ConcurrentModificationException}} or a request with a partially rebuilt tool
list;
* read {{toolClientMap}} (unsynchronized {{HashMap}} read during structural
modification is undefined behavior);
* potentially enter {{reconnectMcpServer}} for the same server simultaneously
(no mutual exclusion), closing each other's fresh clients and leaking
connections/stdio subprocesses.
Additional inconsistencies in the same code path:
* {{returnDirectTools}} entries of the old server are never removed on
reconnect — if a tool dropped its {{returnDirect}} annotation (or disappeared),
the stale entry keeps short-circuiting the loop;
* {{toolToServerName}} keeps entries for tools that no longer exist after
re-listing.
This is the same defect class as CAMEL-23945 (producer state race in
camel-langchain4j-agent). Producers are endpoint singletons and {{process()}}
runs concurrently, so this is reachable in any multi-threaded route that hits
an MCP transport error.
h3. Suggested fix
Guard the reconnect with a per-server lock ({{ReentrantLock}} per the project's
virtual-thread guidance, not {{synchronized}}), swap the collections atomically
(build new immutable snapshots and replace {{volatile}} references instead of
mutating in place), and clean {{returnDirectTools}}/{{toolToServerName}} for
the reconnected server. This fits naturally into the {{McpServerManager}}
extraction proposed by CAMEL-23396 and should be coordinated with the
parallel-tool-execution work in CAMEL-23078, which will widen the concurrency
window.
_This issue was drafted by Claude Code on behalf of Federico Mariani_
--
This message was sent by Atlassian Jira
(v8.20.10#820010)