From 4e46913045ae74d22d8ffb1e063defd9c81ef486 Mon Sep 17 00:00:00 2001 From: Greyson LaLonde Date: Fri, 3 Apr 2026 03:21:02 +0800 Subject: [PATCH] fix: pass fingerprint metadata via config instead of tool args (#5216) security_context was being injected into tool arguments by _add_fingerprint_metadata(), causing Pydantic validation errors (extra_forbidden) on MCP and integration tools with strict schemas. Move fingerprint data to the `config` parameter that invoke/ainvoke already accept, keeping it available to consumers without polluting the tool args namespace. Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com> --- lib/crewai/src/crewai/tools/tool_usage.py | 51 +++++++++++------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/lib/crewai/src/crewai/tools/tool_usage.py b/lib/crewai/src/crewai/tools/tool_usage.py index b6ce5adb6..95adc0906 100644 --- a/lib/crewai/src/crewai/tools/tool_usage.py +++ b/lib/crewai/src/crewai/tools/tool_usage.py @@ -318,6 +318,8 @@ class ToolUsage: if self.task: self.task.increment_delegations(coworker) + fingerprint_config = self._build_fingerprint_config() + if calling.arguments: try: acceptable_args = tool.args_schema.model_json_schema()[ @@ -328,15 +330,16 @@ class ToolUsage: for k, v in calling.arguments.items() if k in acceptable_args } - arguments = self._add_fingerprint_metadata(arguments) - result = await tool.ainvoke(input=arguments) + result = await tool.ainvoke( + input=arguments, config=fingerprint_config + ) except Exception: arguments = calling.arguments - arguments = self._add_fingerprint_metadata(arguments) - result = await tool.ainvoke(input=arguments) + result = await tool.ainvoke( + input=arguments, config=fingerprint_config + ) else: - arguments = self._add_fingerprint_metadata({}) - result = await tool.ainvoke(input=arguments) + result = await tool.ainvoke(input={}, config=fingerprint_config) if self.tools_handler: should_cache = True @@ -550,6 +553,8 @@ class ToolUsage: if self.task: self.task.increment_delegations(coworker) + fingerprint_config = self._build_fingerprint_config() + if calling.arguments: try: acceptable_args = tool.args_schema.model_json_schema()[ @@ -560,15 +565,16 @@ class ToolUsage: for k, v in calling.arguments.items() if k in acceptable_args } - arguments = self._add_fingerprint_metadata(arguments) - result = tool.invoke(input=arguments) + result = tool.invoke( + input=arguments, config=fingerprint_config + ) except Exception: arguments = calling.arguments - arguments = self._add_fingerprint_metadata(arguments) - result = tool.invoke(input=arguments) + result = tool.invoke( + input=arguments, config=fingerprint_config + ) else: - arguments = self._add_fingerprint_metadata({}) - result = tool.invoke(input=arguments) + result = tool.invoke(input={}, config=fingerprint_config) if self.tools_handler: should_cache = True @@ -1008,23 +1014,16 @@ class ToolUsage: return event_data - def _add_fingerprint_metadata(self, arguments: dict[str, Any]) -> dict[str, Any]: - """Add fingerprint metadata to tool arguments if available. + def _build_fingerprint_config(self) -> dict[str, Any]: + """Build fingerprint metadata as a config dict for tool invocation. - Args: - arguments: The original tool arguments + Returns the fingerprint data in a config dict rather than injecting it + into tool arguments, so it doesn't conflict with strict tool schemas. Returns: - Updated arguments dictionary with fingerprint metadata + Config dictionary with security_context metadata. """ - # Create a shallow copy to avoid modifying the original - arguments = arguments.copy() - - # Add security metadata under a designated key - if "security_context" not in arguments: - arguments["security_context"] = {} - - security_context = arguments["security_context"] + security_context: dict[str, Any] = {} # Add agent fingerprint if available if self.agent and hasattr(self.agent, "security_config"): @@ -1048,4 +1047,4 @@ class ToolUsage: except AttributeError: pass - return arguments + return {"security_context": security_context} if security_context else {}