diff --git a/lib/crewai/src/crewai/mcp/client.py b/lib/crewai/src/crewai/mcp/client.py index f25a77112..b1c1cc8b0 100644 --- a/lib/crewai/src/crewai/mcp/client.py +++ b/lib/crewai/src/crewai/mcp/client.py @@ -461,14 +461,17 @@ class MCPClient: arguments = arguments or {} cleaned_arguments = self._clean_tool_arguments(arguments) - # Sign the outgoing message when a security manager is present + # Sign the outgoing message when a security manager is present. + # We use a shallow copy of cleaned_arguments inside the message dict + # so that storing the envelope back into cleaned_arguments does not + # create a circular reference (envelope -> message -> params -> arguments). if self.security_manager is not None: message = { "jsonrpc": "2.0", "method": "tools/call", "params": { "name": tool_name, - "arguments": cleaned_arguments, + "arguments": dict(cleaned_arguments), }, } signed_envelope = self.security_manager.sign_message(message) diff --git a/lib/crewai/tests/mcp/test_mcp_security.py b/lib/crewai/tests/mcp/test_mcp_security.py index 8ab7198e4..33de4b3f1 100644 --- a/lib/crewai/tests/mcp/test_mcp_security.py +++ b/lib/crewai/tests/mcp/test_mcp_security.py @@ -484,7 +484,7 @@ class TestToolResolverSecurityIntegration: backstory="Test backstory", mcps=[http_config], ) - tools = agent.get_mcp_tools([http_config]) + agent.get_mcp_tools([http_config]) call_kwargs = mock_client_class.call_args.kwargs assert call_kwargs.get("security_manager") is None