unique_toolkit 1.16.3__py3-none-any.whl → 1.16.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,6 @@ import logging
3
3
  from typing import Any, Dict
4
4
 
5
5
  import unique_sdk
6
- from pydantic import BaseModel, Field, create_model
7
6
 
8
7
  from unique_toolkit.agentic.evaluation.schemas import EvaluationMetricName
9
8
  from unique_toolkit.agentic.tools.mcp.models import MCPToolConfig
@@ -45,44 +44,13 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
45
44
  logger.info(
46
45
  "MCP tool %s schema %s", self._mcp_tool.name, self._mcp_tool.input_schema
47
46
  )
48
- parameters_model = self._create_parameters_model()
49
- logger.info(
50
- "MCP tool %s contructed params %s",
51
- self._mcp_tool.name,
52
- parameters_model.model_json_schema(),
53
- )
54
47
 
55
48
  return LanguageModelToolDescription(
56
49
  name=self.name,
57
50
  description=self._mcp_tool.description or "",
58
- parameters=parameters_model,
51
+ parameters=self._mcp_tool.input_schema,
59
52
  )
60
53
 
61
- def _create_parameters_model(self) -> type[BaseModel]:
62
- """Create a Pydantic model from MCP tool's input schema"""
63
- properties = self._mcp_tool.input_schema.get("properties", {})
64
- required_fields = self._mcp_tool.input_schema.get("required", [])
65
-
66
- # Convert JSON schema properties to Pydantic fields
67
- fields = {}
68
- for prop_name, prop_schema in properties.items():
69
- field_type = self._json_schema_to_python_type(prop_schema)
70
- field_description = prop_schema.get("description", "")
71
-
72
- if prop_name in required_fields:
73
- fields[prop_name] = (
74
- field_type,
75
- Field(description=field_description),
76
- )
77
- else:
78
- fields[prop_name] = (
79
- field_type,
80
- Field(default=None, description=field_description),
81
- )
82
-
83
- # Create dynamic model
84
- return create_model(f"{self.name}Parameters", **fields)
85
-
86
54
  def _json_schema_to_python_type(self, schema: Dict[str, Any]) -> type:
87
55
  """Convert JSON schema type to Python type"""
88
56
  json_type = schema.get("type", "string")
@@ -13,6 +13,8 @@ from unique_toolkit.agentic.tools.config import (
13
13
  )
14
14
  from unique_toolkit.agentic.tools.factory import ToolFactory
15
15
  from unique_toolkit.agentic.tools.mcp.manager import MCPManager
16
+ from unique_toolkit.agentic.tools.mcp.models import MCPToolConfig
17
+ from unique_toolkit.agentic.tools.mcp.tool_wrapper import MCPToolWrapper
16
18
  from unique_toolkit.agentic.tools.schemas import BaseToolConfig
17
19
  from unique_toolkit.agentic.tools.tool import Tool
18
20
  from unique_toolkit.agentic.tools.tool_manager import ToolManager, ToolManagerConfig
@@ -114,11 +116,22 @@ class TestMCPManager:
114
116
  name="mcp_test_tool",
115
117
  description="Test MCP tool",
116
118
  input_schema={
119
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
117
120
  "type": "object",
118
121
  "properties": {
119
- "query": {"type": "string", "description": "Search query"}
122
+ "folder": {
123
+ "description": "Mail folder to read mails from",
124
+ "default": "inbox",
125
+ "type": "string",
126
+ },
127
+ "limit": {
128
+ "description": "Number of emails to retrieve",
129
+ "default": 10,
130
+ "type": "number",
131
+ "minimum": 1,
132
+ "maximum": 50,
133
+ },
120
134
  },
121
- "required": ["query"],
122
135
  },
123
136
  output_schema=None,
124
137
  annotations=None,
@@ -446,3 +459,76 @@ class TestMCPManager:
446
459
  assert "internal_search" not in tool_names
447
460
  assert "mcp_test_tool" in tool_names
448
461
  assert len(tools) == 1
462
+
463
+ def test_mcp_tool_wrapper_generates_correct_parameters(
464
+ self, mcp_tools, mcp_servers, tool_progress_reporter
465
+ ):
466
+ """Test that MCPToolWrapper correctly generates parameters field from MCP tool input schema"""
467
+ # Get the first MCP tool and server from fixtures
468
+ mcp_tool = mcp_tools[0]
469
+ mcp_server = mcp_servers[0]
470
+
471
+ # Create MCPToolConfig
472
+ config = MCPToolConfig(
473
+ server_id="test_server_id",
474
+ server_name="test_server",
475
+ mcp_source_id="test_server_id",
476
+ )
477
+
478
+ # Initialize the MCPToolWrapper
479
+ tool_wrapper = MCPToolWrapper(
480
+ mcp_server=mcp_server,
481
+ mcp_tool=mcp_tool,
482
+ config=config,
483
+ event=self.event,
484
+ tool_progress_reporter=tool_progress_reporter,
485
+ )
486
+
487
+ # Call tool_description to get the LanguageModelToolDescription
488
+ tool_description = tool_wrapper.tool_description()
489
+
490
+ # Verify the basic properties
491
+ assert tool_description.name == "mcp_test_tool"
492
+ assert tool_description.description == "Test MCP tool"
493
+
494
+ # Verify that parameters field is correctly set to the input_schema
495
+ expected_parameters = {
496
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
497
+ "type": "object",
498
+ "properties": {
499
+ "folder": {
500
+ "description": "Mail folder to read mails from",
501
+ "default": "inbox",
502
+ "type": "string",
503
+ },
504
+ "limit": {
505
+ "description": "Number of emails to retrieve",
506
+ "default": 10,
507
+ "type": "number",
508
+ "minimum": 1,
509
+ "maximum": 50,
510
+ },
511
+ },
512
+ }
513
+
514
+ assert tool_description.parameters == expected_parameters
515
+
516
+ # Verify specific parameter properties
517
+ parameters = tool_description.parameters
518
+ assert isinstance(parameters, dict)
519
+ assert parameters["type"] == "object"
520
+ assert "properties" in parameters
521
+
522
+ # Check folder parameter
523
+ folder_prop = parameters["properties"]["folder"]
524
+ assert folder_prop["type"] == "string"
525
+ assert folder_prop["description"] == "Mail folder to read mails from"
526
+ assert folder_prop["default"] == "inbox"
527
+
528
+ # Check limit parameter
529
+ limit_prop = parameters["properties"]["limit"]
530
+ assert limit_prop["type"] == "number"
531
+ assert limit_prop["description"] == "Number of emails to retrieve"
532
+ assert limit_prop["default"] == 10
533
+ assert limit_prop["minimum"] == 1
534
+ assert limit_prop["maximum"] == 50
@@ -663,9 +663,10 @@ class LanguageModelToolDescription(BaseModel):
663
663
  ...,
664
664
  description="Description of what the tool is doing the tool",
665
665
  )
666
- parameters: type[BaseModel] = Field(
666
+ parameters: type[BaseModel] | dict[str, Any] = Field(
667
667
  ...,
668
668
  description="Pydantic model for the tool parameters",
669
+ union_mode="left_to_right",
669
670
  )
670
671
 
671
672
  # TODO: This should be default `True` but if this is the case the parameter_model needs to include additional properties
@@ -675,8 +676,10 @@ class LanguageModelToolDescription(BaseModel):
675
676
  )
676
677
 
677
678
  @field_serializer("parameters")
678
- def serialize_parameters(self, parameters: type[BaseModel]):
679
- return parameters.model_json_schema()
679
+ def serialize_parameters(
680
+ self, parameters: type[BaseModel] | dict[str, Any]
681
+ ) -> dict[str, Any]:
682
+ return _parameters_as_json_schema(parameters)
680
683
 
681
684
  @overload
682
685
  def to_openai(
@@ -694,7 +697,7 @@ class LanguageModelToolDescription(BaseModel):
694
697
  function=FunctionDefinition(
695
698
  name=self.name,
696
699
  description=self.description,
697
- parameters=self.parameters.model_json_schema(),
700
+ parameters=_parameters_as_json_schema(self.parameters),
698
701
  strict=self.strict,
699
702
  ),
700
703
  type="function",
@@ -703,7 +706,16 @@ class LanguageModelToolDescription(BaseModel):
703
706
  return FunctionToolParam(
704
707
  type="function",
705
708
  name=self.name,
706
- parameters=self.parameters.model_json_schema(),
709
+ parameters=_parameters_as_json_schema(self.parameters),
707
710
  strict=self.strict,
708
711
  description=self.description,
709
712
  )
713
+
714
+
715
+ def _parameters_as_json_schema(
716
+ parameters: type[BaseModel] | dict[str, Any],
717
+ ) -> dict[str, Any]:
718
+ if isinstance(parameters, dict):
719
+ return parameters
720
+
721
+ return parameters.model_json_schema()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 1.16.3
3
+ Version: 1.16.4
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Cedric Klinkert
@@ -118,6 +118,9 @@ All notable changes to this project will be documented in this file.
118
118
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
119
119
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
120
120
 
121
+ ## [1.16.4] - 2025-10-18
122
+ - Fix bug with MCP tool parameters schema
123
+
121
124
  ## [1.16.3] - 2025-10-18
122
125
  - Add logging of MCP tool schema and constructed parameters
123
126
 
@@ -84,7 +84,7 @@ unique_toolkit/agentic/tools/factory.py,sha256=A1Aliwx037UAk9ADiDsg0zjCWWnvzV_Px
84
84
  unique_toolkit/agentic/tools/mcp/__init__.py,sha256=RLF_p-LDRC7GhiB3fdCi4u3bh6V9PY_w26fg61BLyco,122
85
85
  unique_toolkit/agentic/tools/mcp/manager.py,sha256=DPYwwDe6RSZyuPaxn-je49fP_qOOs0ZV46EM6GZcV4c,2748
86
86
  unique_toolkit/agentic/tools/mcp/models.py,sha256=OyCCb7Vwv1ftzC_OCpFkf3TX9Aeb74ZZagG-qK5peIU,722
87
- unique_toolkit/agentic/tools/mcp/tool_wrapper.py,sha256=Pjgzg_Ew20-82UCh6AqTQmPSKvalMDKJtV10mRQIHiA,10304
87
+ unique_toolkit/agentic/tools/mcp/tool_wrapper.py,sha256=37nkalHNUfti9rKdCH_rLEObbYdH7kDfkbLulf_sXmQ,9027
88
88
  unique_toolkit/agentic/tools/openai_builtin/__init__.py,sha256=NdVjkTa3LbW-JHhzPRjinTmgOCtEv090Zr9jGZXmgqs,345
89
89
  unique_toolkit/agentic/tools/openai_builtin/base.py,sha256=2Lw47XworwwkIQBQW5S1T6HS2mWqx13lx50moAMekRk,808
90
90
  unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py,sha256=w2vONpnC6hKRPoJGwzDuRtNBsQd_o-gMUqArgIl_5KY,305
@@ -92,7 +92,7 @@ unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py,sha256=r-
92
92
  unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py,sha256=RKVExS1l3rJDVcu3mxKYA7SNV_Hphx2przhhiC-5PSo,7467
93
93
  unique_toolkit/agentic/tools/openai_builtin/manager.py,sha256=kU4wGit9AnDbkijB7LJEHcGXG8UeTBhiZh4a7lxTGA8,2246
94
94
  unique_toolkit/agentic/tools/schemas.py,sha256=0ZR8xCdGj1sEdPE0lfTIG2uSR5zqWoprUa3Seqez4C8,4837
95
- unique_toolkit/agentic/tools/test/test_mcp_manager.py,sha256=PVRvkK3M21rzONpy5VE_i3vEbAGIz1haW_VPVwiPDI0,15724
95
+ unique_toolkit/agentic/tools/test/test_mcp_manager.py,sha256=9q9TpzrQlxzQOwcyEGc6J7L4K55cclgvJme5jFQmc4M,19044
96
96
  unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py,sha256=dod5QPqgGUInVAGXAbsAKNTEypIi6pUEWhDbJr9YfUU,6307
97
97
  unique_toolkit/agentic/tools/tool.py,sha256=m56VLxiHuKU2_J5foZp00xhm5lTxWEW7zRLGbIE9ssU,6744
98
98
  unique_toolkit/agentic/tools/tool_manager.py,sha256=DtxJobe_7QKFe6CjnMhCP-mnKO6MjnZeDXsO3jBoC9w,16283
@@ -150,7 +150,7 @@ unique_toolkit/language_model/functions.py,sha256=LGX3rR-XjkB-R520jp4w_Azgqf7BsI
150
150
  unique_toolkit/language_model/infos.py,sha256=pGd4I7fAuy8D8iqEgKC7-grQZe4AIMebonkBBv1k37Q,59363
151
151
  unique_toolkit/language_model/prompt.py,sha256=JSawaLjQg3VR-E2fK8engFyJnNdk21zaO8pPIodzN4Q,3991
152
152
  unique_toolkit/language_model/reference.py,sha256=nkX2VFz-IrUz8yqyc3G5jUMNwrNpxITBrMEKkbqqYoI,8583
153
- unique_toolkit/language_model/schemas.py,sha256=k99I9GAR6e2rdVfbfl49ojbT7sk5xCMNYmME22RGJkk,23423
153
+ unique_toolkit/language_model/schemas.py,sha256=oHcJgmNSGpGW6ygjWvEB9iYaHgx250-Mtm-olSSJ-Ek,23760
154
154
  unique_toolkit/language_model/service.py,sha256=JkYGtCug8POQskTv_aoYkzTMOaPCWRM94y73o3bUttQ,12019
155
155
  unique_toolkit/language_model/utils.py,sha256=bPQ4l6_YO71w-zaIPanUUmtbXC1_hCvLK0tAFc3VCRc,1902
156
156
  unique_toolkit/protocols/support.py,sha256=ZEnbQL5w2-T_1AeM8OHycZJ3qbdfVI1nXe0nL9esQEw,5544
@@ -165,7 +165,7 @@ unique_toolkit/short_term_memory/service.py,sha256=5PeVBu1ZCAfyDb2HLVvlmqSbyzBBu
165
165
  unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
166
166
  unique_toolkit/smart_rules/compile.py,sha256=Ozhh70qCn2yOzRWr9d8WmJeTo7AQurwd3tStgBMPFLA,1246
167
167
  unique_toolkit/test_utilities/events.py,sha256=_mwV2bs5iLjxS1ynDCjaIq-gjjKhXYCK-iy3dRfvO3g,6410
168
- unique_toolkit-1.16.3.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
169
- unique_toolkit-1.16.3.dist-info/METADATA,sha256=-cjUgbbqgO5hXcS_7rJZII5FJLfYjVBMW8BbTFmYGzo,37687
170
- unique_toolkit-1.16.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
171
- unique_toolkit-1.16.3.dist-info/RECORD,,
168
+ unique_toolkit-1.16.4.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
169
+ unique_toolkit-1.16.4.dist-info/METADATA,sha256=56XB6tgGoHWkl0ycXsqQ3owRbEmk5uvg3eu7ogZLF88,37755
170
+ unique_toolkit-1.16.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
171
+ unique_toolkit-1.16.4.dist-info/RECORD,,