unique_toolkit 0.8.25__tar.gz → 0.8.27__tar.gz

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.
Files changed (124) hide show
  1. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/CHANGELOG.md +6 -0
  2. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/PKG-INFO +7 -1
  3. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/pyproject.toml +1 -1
  4. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/history_manager/history_manager.py +7 -0
  5. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/language_model/functions.py +1 -1
  6. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/language_model/service.py +1 -1
  7. unique_toolkit-0.8.27/unique_toolkit/tools/mcp/__init__.py +4 -0
  8. unique_toolkit-0.8.27/unique_toolkit/tools/mcp/manager.py +67 -0
  9. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/mcp/models.py +2 -12
  10. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/mcp/tool_wrapper.py +39 -55
  11. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/schemas.py +4 -1
  12. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/tool.py +10 -4
  13. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/tool_manager.py +1 -3
  14. unique_toolkit-0.8.25/unique_toolkit/tools/mcp/__init__.py +0 -4
  15. unique_toolkit-0.8.25/unique_toolkit/tools/mcp/manager.py +0 -82
  16. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/LICENSE +0 -0
  17. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/README.md +0 -0
  18. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/__init__.py +0 -0
  19. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/_common/_base_service.py +0 -0
  20. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/_common/_time_utils.py +0 -0
  21. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/_common/default_language_model.py +0 -0
  22. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/_common/endpoint_builder.py +0 -0
  23. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/_common/exception.py +0 -0
  24. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/_common/token/image_token_counting.py +0 -0
  25. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/_common/token/token_counting.py +0 -0
  26. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/_common/validate_required_values.py +0 -0
  27. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/_common/validators.py +0 -0
  28. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/app/__init__.py +0 -0
  29. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/app/dev_util.py +0 -0
  30. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/app/init_logging.py +0 -0
  31. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/app/init_sdk.py +0 -0
  32. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/app/performance/async_tasks.py +0 -0
  33. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/app/performance/async_wrapper.py +0 -0
  34. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/app/schemas.py +0 -0
  35. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/app/unique_settings.py +0 -0
  36. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/app/verification.py +0 -0
  37. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/chat/__init__.py +0 -0
  38. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/chat/constants.py +0 -0
  39. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/chat/functions.py +0 -0
  40. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/chat/schemas.py +0 -0
  41. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/chat/service.py +0 -0
  42. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/chat/state.py +0 -0
  43. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/chat/utils.py +0 -0
  44. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/content/__init__.py +0 -0
  45. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/content/constants.py +0 -0
  46. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/content/functions.py +0 -0
  47. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/content/schemas.py +0 -0
  48. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/content/service.py +0 -0
  49. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/content/utils.py +0 -0
  50. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/debug_info_manager/debug_info_manager.py +0 -0
  51. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/embedding/__init__.py +0 -0
  52. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/embedding/constants.py +0 -0
  53. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/embedding/functions.py +0 -0
  54. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/embedding/schemas.py +0 -0
  55. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/embedding/service.py +0 -0
  56. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/embedding/utils.py +0 -0
  57. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/config.py +0 -0
  58. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/context_relevancy/prompts.py +0 -0
  59. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/context_relevancy/schema.py +0 -0
  60. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/context_relevancy/service.py +0 -0
  61. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/evaluation_manager.py +0 -0
  62. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/exception.py +0 -0
  63. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/hallucination/constants.py +0 -0
  64. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/hallucination/hallucination_evaluation.py +0 -0
  65. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/hallucination/prompts.py +0 -0
  66. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/hallucination/service.py +0 -0
  67. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/hallucination/utils.py +0 -0
  68. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/output_parser.py +0 -0
  69. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/schemas.py +0 -0
  70. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/tests/test_context_relevancy_service.py +0 -0
  71. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evals/tests/test_output_parser.py +0 -0
  72. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/__init__.py +0 -0
  73. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/config.py +0 -0
  74. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/constants.py +0 -0
  75. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/context_relevancy/constants.py +0 -0
  76. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/context_relevancy/prompts.py +0 -0
  77. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/context_relevancy/service.py +0 -0
  78. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/context_relevancy/utils.py +0 -0
  79. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/exception.py +0 -0
  80. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/hallucination/constants.py +0 -0
  81. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/hallucination/prompts.py +0 -0
  82. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/hallucination/service.py +0 -0
  83. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/hallucination/utils.py +0 -0
  84. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/output_parser.py +0 -0
  85. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/evaluators/schemas.py +0 -0
  86. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/framework_utilities/__init__.py +0 -0
  87. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/framework_utilities/langchain/client.py +0 -0
  88. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/framework_utilities/langchain/history.py +0 -0
  89. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/framework_utilities/openai/__init__.py +0 -0
  90. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/framework_utilities/openai/client.py +0 -0
  91. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/framework_utilities/openai/message_builder.py +0 -0
  92. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/framework_utilities/utils.py +0 -0
  93. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/history_manager/history_construction_with_contents.py +0 -0
  94. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/history_manager/loop_token_reducer.py +0 -0
  95. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/history_manager/utils.py +0 -0
  96. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/language_model/__init__.py +0 -0
  97. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/language_model/builder.py +0 -0
  98. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/language_model/constants.py +0 -0
  99. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/language_model/infos.py +0 -0
  100. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/language_model/prompt.py +0 -0
  101. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/language_model/reference.py +0 -0
  102. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/language_model/schemas.py +0 -0
  103. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/language_model/utils.py +0 -0
  104. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/postprocessor/postprocessor_manager.py +0 -0
  105. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/protocols/support.py +0 -0
  106. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/reference_manager/reference_manager.py +0 -0
  107. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/short_term_memory/__init__.py +0 -0
  108. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/short_term_memory/constants.py +0 -0
  109. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/short_term_memory/functions.py +0 -0
  110. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/short_term_memory/persistent_short_term_memory_manager.py +0 -0
  111. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/short_term_memory/schemas.py +0 -0
  112. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/short_term_memory/service.py +0 -0
  113. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/smart_rules/__init__.py +0 -0
  114. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/smart_rules/compile.py +0 -0
  115. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/thinking_manager/thinking_manager.py +0 -0
  116. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/config.py +0 -0
  117. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/factory.py +0 -0
  118. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/test/test_mcp_manager.py +0 -0
  119. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/test/test_tool_progress_reporter.py +0 -0
  120. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/tool_progress_reporter.py +0 -0
  121. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/utils/execution/execution.py +0 -0
  122. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/utils/source_handling/schema.py +0 -0
  123. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/utils/source_handling/source_formatting.py +0 -0
  124. {unique_toolkit-0.8.25 → unique_toolkit-0.8.27}/unique_toolkit/tools/utils/source_handling/tests/test_source_formatting.py +0 -0
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.8.27] - 2025-08-28
9
+ - Fixed function "create_async" in language_model.functions : "user_id" argument should be optional.
10
+
11
+ ## [0.8.26] - 2025-08-27
12
+ - Optimized MCP manager
13
+
8
14
  ## [0.8.25] - 2025-08-27
9
15
  - Load environment variables automatically from plattform dirs or environment
10
16
  - General Endpoint definition utility
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 0.8.25
3
+ Version: 0.8.27
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Martin Fadler
@@ -115,6 +115,12 @@ All notable changes to this project will be documented in this file.
115
115
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
116
116
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
117
117
 
118
+ ## [0.8.27] - 2025-08-28
119
+ - Fixed function "create_async" in language_model.functions : "user_id" argument should be optional.
120
+
121
+ ## [0.8.26] - 2025-08-27
122
+ - Optimized MCP manager
123
+
118
124
  ## [0.8.25] - 2025-08-27
119
125
  - Load environment variables automatically from plattform dirs or environment
120
126
  - General Endpoint definition utility
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "unique_toolkit"
3
- version = "0.8.25"
3
+ version = "0.8.27"
4
4
  description = ""
5
5
  authors = [
6
6
  "Martin Fadler <martin.fadler@unique.ch>",
@@ -158,6 +158,13 @@ class HistoryManager:
158
158
  f"Appending tool call result to history: {tool_response.name}"
159
159
  )
160
160
 
161
+ if tool_response.content != "":
162
+ return LanguageModelToolMessage(
163
+ content=tool_response.content,
164
+ tool_call_id=tool_response.id, # type: ignore
165
+ name=tool_response.name,
166
+ )
167
+
161
168
  content_chunks = (
162
169
  tool_response.content_chunks or []
163
170
  ) # it can be that the tool response does not have content chunks
@@ -94,9 +94,9 @@ def complete(
94
94
 
95
95
  async def complete_async(
96
96
  company_id: str,
97
- user_id: str,
98
97
  messages: LanguageModelMessages | list[ChatCompletionMessageParam],
99
98
  model_name: LanguageModelName | str,
99
+ user_id: str | None = None,
100
100
  temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
101
101
  timeout: int = DEFAULT_COMPLETE_TIMEOUT,
102
102
  tools: list[LanguageModelTool | LanguageModelToolDescription] | None = None,
@@ -277,9 +277,9 @@ class LanguageModelService:
277
277
  async def complete_async_util(
278
278
  cls,
279
279
  company_id: str,
280
- user_id: str,
281
280
  messages: LanguageModelMessages,
282
281
  model_name: LanguageModelName | str,
282
+ user_id: str | None = None,
283
283
  temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
284
284
  timeout: int = DEFAULT_COMPLETE_TIMEOUT,
285
285
  tools: Optional[list[LanguageModelTool | LanguageModelToolDescription]] = None,
@@ -0,0 +1,4 @@
1
+ from .models import MCPToolConfig
2
+ from .tool_wrapper import MCPToolWrapper
3
+
4
+ __all__ = ["MCPToolWrapper", "MCPToolConfig"]
@@ -0,0 +1,67 @@
1
+ import logging
2
+
3
+ from unique_toolkit.app.schemas import ChatEvent, McpServer
4
+ from unique_toolkit.tools.config import ToolBuildConfig, ToolIcon, ToolSelectionPolicy
5
+ from unique_toolkit.tools.mcp.models import MCPToolConfig
6
+ from unique_toolkit.tools.mcp.tool_wrapper import MCPToolWrapper
7
+ from unique_toolkit.tools.schemas import BaseToolConfig
8
+ from unique_toolkit.tools.tool import Tool
9
+ from unique_toolkit.tools.tool_progress_reporter import ToolProgressReporter
10
+
11
+
12
+ class MCPManager:
13
+ def __init__(
14
+ self,
15
+ mcp_servers: list[McpServer],
16
+ event: ChatEvent,
17
+ tool_progress_reporter: ToolProgressReporter,
18
+ ):
19
+ self._mcp_servers = mcp_servers
20
+ self._event = event
21
+ self._tool_progress_reporter = tool_progress_reporter
22
+
23
+ def get_mcp_servers(self):
24
+ return self._mcp_servers
25
+
26
+ def get_mcp_server_by_id(self, id: str):
27
+ return next((server for server in self._mcp_servers if server.id == id), None)
28
+
29
+ def get_all_mcp_tools(self) -> list[Tool[BaseToolConfig]]:
30
+ selected_tools = []
31
+ for server in self._mcp_servers:
32
+ if not hasattr(server, "tools"):
33
+ continue
34
+ if not server.tools:
35
+ continue
36
+
37
+ for tool in server.tools:
38
+ try:
39
+ config = MCPToolConfig(
40
+ server_id=server.id,
41
+ server_name=server.name,
42
+ server_system_prompt=server.system_prompt,
43
+ server_user_prompt=server.user_prompt,
44
+ mcp_source_id=server.id,
45
+ )
46
+ wrapper = MCPToolWrapper(
47
+ mcp_server=server,
48
+ mcp_tool=tool,
49
+ config=config,
50
+ event=self._event,
51
+ tool_progress_reporter=self._tool_progress_reporter,
52
+ )
53
+ wrapper.settings = ToolBuildConfig( # TODO: this must be refactored to behave like the other tools.
54
+ name=tool.name,
55
+ configuration=config,
56
+ display_name=tool.title or tool.name,
57
+ is_exclusive=False,
58
+ is_enabled=True,
59
+ icon=ToolIcon.BOOK,
60
+ selection_policy=ToolSelectionPolicy.BY_USER,
61
+ )
62
+ selected_tools.append(wrapper)
63
+ except Exception as e:
64
+ logging.error(
65
+ f"Error creating MCP tool wrapper for {tool.name}: {e}"
66
+ )
67
+ return selected_tools
@@ -1,9 +1,9 @@
1
- from typing import Any, Dict, Optional, Protocol
1
+ from typing import Any, Dict, Optional
2
2
 
3
3
  from unique_toolkit.tools.schemas import BaseToolConfig
4
4
 
5
5
 
6
- class MCPTool(Protocol):
6
+ class MCPTool:
7
7
  """Protocol defining the expected structure of an MCP tool."""
8
8
 
9
9
  name: str
@@ -18,16 +18,6 @@ class MCPTool(Protocol):
18
18
  is_connected: bool
19
19
 
20
20
 
21
- class EnrichedMCPTool(MCPTool, Protocol):
22
- """Protocol for MCP tools enriched with server information."""
23
-
24
- server_id: str
25
- server_name: str
26
- server_system_prompt: Optional[str]
27
- server_user_prompt: Optional[str]
28
- mcp_source_id: str
29
-
30
-
31
21
  class MCPToolConfig(BaseToolConfig):
32
22
  """Configuration for MCP tools"""
33
23
 
@@ -4,15 +4,14 @@ from typing import Any, Dict
4
4
  import unique_sdk
5
5
  from pydantic import BaseModel, Field, create_model
6
6
 
7
- from unique_toolkit.app.schemas import ChatEvent
7
+ from unique_toolkit.app.schemas import ChatEvent, McpServer, McpTool
8
8
  from unique_toolkit.evals.schemas import EvaluationMetricName
9
9
  from unique_toolkit.language_model import LanguageModelMessage
10
10
  from unique_toolkit.language_model.schemas import (
11
11
  LanguageModelFunction,
12
12
  LanguageModelToolDescription,
13
- LanguageModelToolMessage,
14
13
  )
15
- from unique_toolkit.tools.mcp.models import EnrichedMCPTool, MCPToolConfig
14
+ from unique_toolkit.tools.mcp.models import MCPToolConfig
16
15
  from unique_toolkit.tools.schemas import ToolCallResponse
17
16
  from unique_toolkit.tools.tool import Tool
18
17
  from unique_toolkit.tools.tool_progress_reporter import (
@@ -26,24 +25,16 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
26
25
 
27
26
  def __init__(
28
27
  self,
29
- mcp_tool: EnrichedMCPTool,
28
+ mcp_server: McpServer,
29
+ mcp_tool: McpTool,
30
30
  config: MCPToolConfig,
31
31
  event: ChatEvent,
32
32
  tool_progress_reporter: ToolProgressReporter | None = None,
33
33
  ):
34
34
  self.name = mcp_tool.name
35
35
  super().__init__(config, event, tool_progress_reporter)
36
- self.mcp_tool = mcp_tool
37
- self._tool_description = mcp_tool.description or ""
38
- self._parameters_schema = mcp_tool.input_schema
39
-
40
- # Set the display name for user-facing messages
41
- # Priority: title > annotations.title > name
42
- self.display_name = (
43
- getattr(mcp_tool, "title", None)
44
- or (getattr(mcp_tool, "annotations", {}) or {}).get("title")
45
- or mcp_tool.name
46
- )
36
+ self._mcp_tool = mcp_tool
37
+ self._mcp_server = mcp_server
47
38
 
48
39
  def tool_description(self) -> LanguageModelToolDescription:
49
40
  """Convert MCP tool schema to LanguageModelToolDescription"""
@@ -52,14 +43,14 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
52
43
 
53
44
  return LanguageModelToolDescription(
54
45
  name=self.name,
55
- description=self._tool_description,
46
+ description=self._mcp_tool.description or "",
56
47
  parameters=parameters_model,
57
48
  )
58
49
 
59
50
  def _create_parameters_model(self) -> type[BaseModel]:
60
51
  """Create a Pydantic model from MCP tool's input schema"""
61
- properties = self._parameters_schema.get("properties", {})
62
- required_fields = self._parameters_schema.get("required", [])
52
+ properties = self._mcp_tool.input_schema.get("properties", {})
53
+ required_fields = self._mcp_tool.input_schema.get("required", [])
63
54
 
64
55
  # Convert JSON schema properties to Pydantic fields
65
56
  fields = {}
@@ -96,20 +87,30 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
96
87
 
97
88
  return type_mapping.get(json_type, str)
98
89
 
99
- def display_name(self) -> str:
100
- """The display name of the tool."""
101
- return self._display_name
102
-
103
90
  def tool_description_for_system_prompt(self) -> str:
104
91
  """Return tool description for system prompt"""
105
- return self._tool_description
92
+ # Not using jinja here to keep it simple and not import new packages.
93
+ description = (
94
+ f"**MCP Server**: {self._mcp_server.name}\n"
95
+ f"**Tool Name**: {self.name}\n"
96
+ f"{self._mcp_tool.system_prompt}"
97
+ )
98
+
99
+ return description
100
+
101
+ def tool_description_for_user_prompt(self) -> str:
102
+ return self._mcp_tool.user_prompt or ""
103
+
104
+ def tool_format_information_for_user_prompt(self) -> str:
105
+ return ""
106
106
 
107
107
  def tool_format_information_for_system_prompt(self) -> str:
108
108
  """Return formatting information for system prompt"""
109
- return f"Use this MCP tool to {self._tool_description.lower()}"
109
+ return "" # this is empty for now as it requires to add this to the MCP model of the backend.
110
110
 
111
111
  def evaluation_check_list(self) -> list[EvaluationMetricName]:
112
112
  """Return evaluation check list - empty for MCP tools for now"""
113
+ # TODO: this is empty for now as it requires a setting in the backend for choosing a suitable validator.
113
114
  return []
114
115
 
115
116
  def get_evaluation_checks_based_on_tool_response(
@@ -123,35 +124,18 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
123
124
  self,
124
125
  tool_response: ToolCallResponse,
125
126
  ) -> LanguageModelMessage:
126
- """Convert tool response to message for loop history"""
127
- # Convert the tool response to a message for the conversation history
128
- content = (
129
- tool_response.error_message
130
- if tool_response.error_message
131
- else "Tool executed successfully"
132
- )
133
-
134
- if hasattr(tool_response, "content") and tool_response.content:
135
- content = str(tool_response.content)
136
- elif tool_response.debug_info:
137
- content = json.dumps(tool_response.debug_info)
138
-
139
- return LanguageModelToolMessage(
140
- content=content,
141
- tool_call_id=tool_response.id,
142
- name=tool_response.name,
143
- )
127
+ raise NotImplementedError("function is not supported")
144
128
 
145
129
  async def run(self, tool_call: LanguageModelFunction) -> ToolCallResponse:
146
130
  """Execute the MCP tool using SDK to call public API"""
147
131
  self.logger.info(f"Running MCP tool: {self.name}")
148
132
 
149
133
  # Notify progress if reporter is available
150
- if self.tool_progress_reporter:
151
- await self.tool_progress_reporter.notify_from_tool_call(
134
+ if self._tool_progress_reporter:
135
+ await self._tool_progress_reporter.notify_from_tool_call(
152
136
  tool_call=tool_call,
153
- name=f"**{self.display_name}**",
154
- message=f"Executing MCP tool: {self.display_name}",
137
+ name=f"**{self.display_name()}**",
138
+ message=f"Executing MCP tool: {self.display_name()}",
155
139
  state=ProgressState.RUNNING,
156
140
  )
157
141
 
@@ -163,23 +147,23 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
163
147
  result = await self._call_mcp_tool_via_sdk(arguments)
164
148
 
165
149
  # Create successful response
166
- tool_response = ToolCallResponse(
150
+ tool_response = ToolCallResponse( # TODO: Why result here not applied directly to the body of the tool_response? like so how does it know the results in the history?
167
151
  id=tool_call.id or "",
168
152
  name=self.name,
169
153
  debug_info={
170
154
  "mcp_tool": self.name,
171
155
  "arguments": arguments,
172
- "result": result,
173
156
  },
174
157
  error_message="",
158
+ content=json.dumps(result),
175
159
  )
176
160
 
177
161
  # Notify completion
178
- if self.tool_progress_reporter:
179
- await self.tool_progress_reporter.notify_from_tool_call(
162
+ if self._tool_progress_reporter:
163
+ await self._tool_progress_reporter.notify_from_tool_call(
180
164
  tool_call=tool_call,
181
- name=f"**{self.display_name}**",
182
- message=f"MCP tool completed: {self.display_name}",
165
+ name=f"**{self.display_name()}**",
166
+ message=f"MCP tool completed: {self.display_name()}",
183
167
  state=ProgressState.FINISHED,
184
168
  )
185
169
 
@@ -189,10 +173,10 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
189
173
  self.logger.error(f"Error executing MCP tool {self.name}: {e}")
190
174
 
191
175
  # Notify failure
192
- if self.tool_progress_reporter:
193
- await self.tool_progress_reporter.notify_from_tool_call(
176
+ if self._tool_progress_reporter:
177
+ await self._tool_progress_reporter.notify_from_tool_call(
194
178
  tool_call=tool_call,
195
- name=f"**{self.display_name}**",
179
+ name=f"**{self.display_name()}**",
196
180
  message=f"MCP tool failed: {str(e)}",
197
181
  state=ProgressState.FAILED,
198
182
  )
@@ -14,6 +14,7 @@ from unique_toolkit.tools.utils.source_handling.schema import SourceFormatConfig
14
14
  class ToolCallResponse(BaseModel):
15
15
  id: str
16
16
  name: str
17
+ content: str = ""
17
18
  debug_info: Optional[dict] = None # TODO: Make the default {}
18
19
  content_chunks: Optional[list[ContentChunk]] = None # TODO: Make the default []
19
20
  reasoning_result: Optional[dict] = None # TODO: Make the default {}
@@ -133,6 +134,8 @@ class ToolPrompts(BaseModel):
133
134
  name: str
134
135
  display_name: str
135
136
  tool_system_prompt: str
136
- tool_description: str
137
137
  tool_format_information_for_system_prompt: str
138
+ tool_user_prompt: str
139
+ tool_format_information_for_user_prompt: str
140
+ tool_description: str
138
141
  input_model: dict[str, Any]
@@ -57,13 +57,17 @@ class Tool(ABC, Generic[ConfigType]):
57
57
  else:
58
58
  return cast("dict[str, Any]", parameters)
59
59
 
60
- @abstractmethod
61
60
  def tool_description_for_system_prompt(self) -> str:
62
- raise NotImplementedError
61
+ return ""
63
62
 
64
- @abstractmethod
65
63
  def tool_format_information_for_system_prompt(self) -> str:
66
- raise NotImplementedError
64
+ return ""
65
+
66
+ def tool_description_for_user_prompt(self) -> str:
67
+ return ""
68
+
69
+ def tool_format_information_for_user_prompt(self) -> str:
70
+ return ""
67
71
 
68
72
  def tool_format_reminder_for_user_prompt(self) -> str:
69
73
  """A short reminder for the user prompt for formatting rules for the tool.
@@ -112,6 +116,8 @@ class Tool(ABC, Generic[ConfigType]):
112
116
  tool_system_prompt=self.tool_description_for_system_prompt(),
113
117
  tool_format_information_for_system_prompt=self.tool_format_information_for_system_prompt(),
114
118
  input_model=self.tool_description_as_json(),
119
+ tool_user_prompt=self.tool_description_for_user_prompt(),
120
+ tool_format_information_for_user_prompt=self.tool_format_information_for_user_prompt(),
115
121
  )
116
122
 
117
123
  # Properties that we should soon deprecate
@@ -103,7 +103,7 @@ class ToolManager:
103
103
  ]
104
104
 
105
105
  # Get MCP tools (these are already properly instantiated)
106
- mcp_tools = self._mcp_manager.get_all_mcp_tools(tool_choices)
106
+ mcp_tools = self._mcp_manager.get_all_mcp_tools()
107
107
  # Combine both types of tools
108
108
  self.available_tools = internal_tools + mcp_tools
109
109
 
@@ -277,8 +277,6 @@ class ToolManager:
277
277
  )
278
278
  return unique_tool_calls
279
279
 
280
- from typing import Any
281
-
282
280
  def _convert_to_forced_tool(self, tool_name: str) -> dict[str, Any]:
283
281
  return {
284
282
  "type": "function",
@@ -1,4 +0,0 @@
1
- from .models import EnrichedMCPTool, MCPToolConfig
2
- from .tool_wrapper import MCPToolWrapper
3
-
4
- __all__ = ["MCPToolWrapper", "MCPToolConfig", "EnrichedMCPTool"]
@@ -1,82 +0,0 @@
1
- import logging
2
-
3
- from unique_toolkit.app.schemas import ChatEvent, McpServer, McpTool
4
- from unique_toolkit.tools.mcp.models import EnrichedMCPTool, MCPToolConfig
5
- from unique_toolkit.tools.mcp.tool_wrapper import MCPToolWrapper
6
- from unique_toolkit.tools.tool_progress_reporter import ToolProgressReporter
7
-
8
-
9
- class MCPManager:
10
- def __init__(
11
- self,
12
- mcp_servers: list[McpServer],
13
- event: ChatEvent,
14
- tool_progress_reporter: ToolProgressReporter,
15
- ):
16
- self._mcp_servers = mcp_servers
17
- self._event = event
18
- self._tool_progress_reporter = tool_progress_reporter
19
-
20
- def get_mcp_servers(self):
21
- return self._mcp_servers
22
-
23
- def get_mcp_server_by_id(self, id: str):
24
- return next((server for server in self._mcp_servers if server.id == id), None)
25
-
26
- def _enrich_tool_with_mcp_info(
27
- self, mcp_tool: McpTool, server: McpServer
28
- ) -> EnrichedMCPTool:
29
- enriched_tool = type("EnrichedMcpTool", (), {})()
30
-
31
- # Copy all attributes from the original tool
32
- for attr in dir(mcp_tool):
33
- if not attr.startswith("_"):
34
- setattr(enriched_tool, attr, getattr(mcp_tool, attr))
35
-
36
- # Add server-specific attributes
37
- enriched_tool.server_id = server.id
38
- enriched_tool.server_name = server.name
39
- enriched_tool.server_system_prompt = getattr(server, "system_prompt", None)
40
- enriched_tool.server_user_prompt = getattr(server, "user_prompt", None)
41
- enriched_tool.mcp_source_id = server.id
42
-
43
- return enriched_tool
44
-
45
- def create_mcp_tool_wrapper(
46
- self, mcp_tool: EnrichedMCPTool, tool_progress_reporter: ToolProgressReporter
47
- ) -> MCPToolWrapper:
48
- """Create MCP tool wrapper that behave like internal tools"""
49
- try:
50
- config = MCPToolConfig(
51
- server_id=mcp_tool.server_id,
52
- server_name=mcp_tool.server_name,
53
- server_system_prompt=mcp_tool.server_system_prompt,
54
- server_user_prompt=mcp_tool.server_user_prompt,
55
- mcp_source_id=mcp_tool.mcp_source_id,
56
- )
57
- wrapper = MCPToolWrapper(
58
- mcp_tool=mcp_tool,
59
- config=config,
60
- event=self._event,
61
- tool_progress_reporter=tool_progress_reporter,
62
- )
63
- return wrapper
64
- except Exception as e:
65
- import traceback
66
-
67
- logging.error(f"Error creating MCP tool wrapper for {mcp_tool.name}: {e}")
68
- logging.error(f"Full traceback: {traceback.format_exc()}")
69
- return None
70
-
71
- def get_all_mcp_tools(self, selected_by_user: list[str]) -> list[MCPToolWrapper]:
72
- selected_tools = []
73
- for server in self._mcp_servers:
74
- if hasattr(server, "tools") and server.tools:
75
- for tool in server.tools:
76
- enriched_tool = self._enrich_tool_with_mcp_info(tool, server)
77
- wrapper = self.create_mcp_tool_wrapper(
78
- enriched_tool, self._tool_progress_reporter
79
- )
80
- if wrapper is not None:
81
- selected_tools.append(wrapper)
82
- return selected_tools
File without changes