You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Matteo Minin (Jira)" <ji...@apache.org> on 2026/07/10 13:47:00 UTC
[jira] [Commented] (CAMEL-23957) camel-openai: MCP reconnect mutates shared endpoint tool state without synchronization
[ https://issues.apache.org/jira/browse/CAMEL-23957?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18095302#comment-18095302 ]
Matteo Minin commented on CAMEL-23957:
--------------------------------------
I've been working on this issue and submitted a PR on GitHub.
I hope it will be useful.
> 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
> Priority: Major
> Labels: ai
>
> {{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)