camel-ai 0.2.37__py3-none-any.whl → 0.2.39__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.

Potentially problematic release.


This version of camel-ai might be problematic. Click here for more details.

Files changed (122) hide show
  1. camel/__init__.py +1 -1
  2. camel/agents/chat_agent.py +4 -0
  3. camel/agents/repo_agent.py +2 -2
  4. camel/benchmarks/apibank.py +1 -1
  5. camel/benchmarks/apibench.py +1 -1
  6. camel/configs/__init__.py +3 -0
  7. camel/configs/modelscope_config.py +59 -0
  8. camel/datagen/evol_instruct/__init__.py +20 -0
  9. camel/datagen/evol_instruct/evol_instruct.py +424 -0
  10. camel/datagen/evol_instruct/scorer.py +166 -0
  11. camel/datagen/evol_instruct/templates.py +268 -0
  12. camel/datagen/self_improving_cot.py +1 -1
  13. camel/datasets/__init__.py +2 -0
  14. camel/datasets/base_generator.py +22 -9
  15. camel/datasets/few_shot_generator.py +2 -3
  16. camel/datasets/self_instruct_generator.py +415 -0
  17. camel/embeddings/openai_compatible_embedding.py +13 -5
  18. camel/environments/models.py +10 -4
  19. camel/environments/single_step.py +181 -41
  20. camel/interpreters/docker_interpreter.py +2 -2
  21. camel/interpreters/e2b_interpreter.py +1 -1
  22. camel/interpreters/internal_python_interpreter.py +1 -1
  23. camel/interpreters/subprocess_interpreter.py +1 -1
  24. camel/loaders/__init__.py +2 -2
  25. camel/loaders/{panda_reader.py → pandas_reader.py} +61 -30
  26. camel/loaders/unstructured_io.py +2 -1
  27. camel/memories/blocks/chat_history_block.py +1 -1
  28. camel/memories/context_creators/score_based.py +198 -67
  29. camel/models/__init__.py +2 -0
  30. camel/models/aiml_model.py +9 -3
  31. camel/models/anthropic_model.py +11 -3
  32. camel/models/azure_openai_model.py +9 -3
  33. camel/models/base_audio_model.py +6 -0
  34. camel/models/base_model.py +4 -0
  35. camel/models/deepseek_model.py +9 -3
  36. camel/models/gemini_model.py +9 -3
  37. camel/models/groq_model.py +9 -3
  38. camel/models/internlm_model.py +8 -2
  39. camel/models/model_factory.py +123 -0
  40. camel/models/modelscope_model.py +208 -0
  41. camel/models/moonshot_model.py +8 -2
  42. camel/models/nemotron_model.py +9 -3
  43. camel/models/nvidia_model.py +9 -3
  44. camel/models/ollama_model.py +9 -3
  45. camel/models/openai_audio_models.py +7 -5
  46. camel/models/openai_compatible_model.py +9 -3
  47. camel/models/openai_model.py +58 -5
  48. camel/models/openrouter_model.py +9 -3
  49. camel/models/qwen_model.py +9 -3
  50. camel/models/samba_model.py +9 -3
  51. camel/models/sglang_model.py +11 -4
  52. camel/models/siliconflow_model.py +8 -2
  53. camel/models/stub_model.py +2 -1
  54. camel/models/togetherai_model.py +11 -5
  55. camel/models/vllm_model.py +10 -4
  56. camel/models/yi_model.py +9 -3
  57. camel/models/zhipuai_model.py +11 -5
  58. camel/retrievers/auto_retriever.py +14 -0
  59. camel/retrievers/vector_retriever.py +1 -1
  60. camel/storages/__init__.py +2 -0
  61. camel/storages/graph_storages/neo4j_graph.py +1 -1
  62. camel/storages/vectordb_storages/__init__.py +2 -0
  63. camel/storages/vectordb_storages/base.py +2 -2
  64. camel/storages/vectordb_storages/milvus.py +2 -2
  65. camel/storages/vectordb_storages/qdrant.py +2 -2
  66. camel/storages/vectordb_storages/tidb.py +332 -0
  67. camel/tasks/task.py +2 -2
  68. camel/toolkits/__init__.py +9 -1
  69. camel/toolkits/arxiv_toolkit.py +2 -1
  70. camel/toolkits/ask_news_toolkit.py +11 -3
  71. camel/toolkits/audio_analysis_toolkit.py +2 -0
  72. camel/toolkits/base.py +3 -0
  73. camel/toolkits/browser_toolkit.py +84 -61
  74. camel/toolkits/code_execution.py +3 -1
  75. camel/toolkits/dappier_toolkit.py +2 -1
  76. camel/toolkits/data_commons_toolkit.py +2 -0
  77. camel/toolkits/excel_toolkit.py +2 -0
  78. camel/toolkits/file_write_toolkit.py +2 -0
  79. camel/toolkits/github_toolkit.py +6 -4
  80. camel/toolkits/google_scholar_toolkit.py +2 -0
  81. camel/toolkits/human_toolkit.py +17 -1
  82. camel/toolkits/image_analysis_toolkit.py +2 -0
  83. camel/toolkits/linkedin_toolkit.py +2 -1
  84. camel/toolkits/math_toolkit.py +2 -0
  85. camel/toolkits/mcp_toolkit.py +42 -52
  86. camel/toolkits/meshy_toolkit.py +20 -2
  87. camel/toolkits/networkx_toolkit.py +2 -0
  88. camel/toolkits/notion_toolkit.py +7 -0
  89. camel/toolkits/openai_agent_toolkit.py +131 -0
  90. camel/toolkits/openbb_toolkit.py +2 -1
  91. camel/toolkits/pubmed_toolkit.py +2 -0
  92. camel/toolkits/reddit_toolkit.py +2 -1
  93. camel/toolkits/retrieval_toolkit.py +2 -1
  94. camel/toolkits/search_toolkit.py +2 -1
  95. camel/toolkits/searxng_toolkit.py +207 -0
  96. camel/toolkits/semantic_scholar_toolkit.py +2 -0
  97. camel/toolkits/slack_toolkit.py +2 -0
  98. camel/toolkits/stripe_toolkit.py +2 -1
  99. camel/toolkits/sympy_toolkit.py +2 -0
  100. camel/toolkits/terminal_toolkit.py +2 -0
  101. camel/toolkits/thinking_toolkit.py +168 -12
  102. camel/toolkits/twitter_toolkit.py +2 -1
  103. camel/toolkits/video_analysis_toolkit.py +2 -1
  104. camel/toolkits/video_download_toolkit.py +2 -1
  105. camel/toolkits/weather_toolkit.py +2 -0
  106. camel/toolkits/whatsapp_toolkit.py +2 -1
  107. camel/toolkits/zapier_toolkit.py +2 -1
  108. camel/types/enums.py +66 -0
  109. camel/types/unified_model_type.py +5 -0
  110. camel/utils/__init__.py +2 -0
  111. camel/utils/chunker/code_chunker.py +9 -9
  112. camel/utils/commons.py +50 -30
  113. camel/utils/constants.py +2 -2
  114. camel/utils/mcp.py +79 -0
  115. camel/verifiers/__init__.py +2 -0
  116. camel/verifiers/base.py +15 -15
  117. camel/verifiers/math_verifier.py +182 -0
  118. camel/verifiers/python_verifier.py +28 -28
  119. {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/METADATA +54 -4
  120. {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/RECORD +122 -110
  121. {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/WHEEL +0 -0
  122. {camel_ai-0.2.37.dist-info → camel_ai-0.2.39.dist-info}/licenses/LICENSE +0 -0
@@ -14,6 +14,7 @@
14
14
  import inspect
15
15
  import json
16
16
  import os
17
+ import shlex
17
18
  from contextlib import AsyncExitStack, asynccontextmanager
18
19
  from typing import (
19
20
  TYPE_CHECKING,
@@ -25,11 +26,12 @@ from typing import (
25
26
  Optional,
26
27
  Set,
27
28
  Union,
29
+ cast,
28
30
  )
29
31
  from urllib.parse import urlparse
30
32
 
31
33
  if TYPE_CHECKING:
32
- from mcp import ListToolsResult, Tool
34
+ from mcp import ClientSession, ListToolsResult, Tool
33
35
 
34
36
  from camel.logger import get_logger
35
37
  from camel.toolkits import BaseToolkit, FunctionTool
@@ -37,7 +39,7 @@ from camel.toolkits import BaseToolkit, FunctionTool
37
39
  logger = get_logger(__name__)
38
40
 
39
41
 
40
- class _MCPServer(BaseToolkit):
42
+ class MCPClient(BaseToolkit):
41
43
  r"""Internal class that provides an abstraction layer to interact with
42
44
  external tools using the Model Context Protocol (MCP). It supports two
43
45
  modes of connection:
@@ -69,7 +71,6 @@ class _MCPServer(BaseToolkit):
69
71
  headers: Optional[Dict[str, str]] = None,
70
72
  ):
71
73
  from mcp import Tool
72
- from mcp.client.session import ClientSession
73
74
 
74
75
  super().__init__(timeout=timeout)
75
76
 
@@ -87,7 +88,7 @@ class _MCPServer(BaseToolkit):
87
88
  r"""Explicitly connect to the MCP server.
88
89
 
89
90
  Returns:
90
- _MCPServer: The connected server instance
91
+ MCPClient: The client used to connect to the server.
91
92
  """
92
93
  from mcp.client.session import ClientSession
93
94
  from mcp.client.sse import sse_client
@@ -110,11 +111,20 @@ class _MCPServer(BaseToolkit):
110
111
  )
111
112
  else:
112
113
  command = self.command_or_url
114
+ arguments = self.args
115
+ if not self.args:
116
+ argv = shlex.split(command)
117
+ if not argv:
118
+ raise ValueError("Command is empty")
119
+
120
+ command = argv[0]
121
+ arguments = argv[1:]
122
+
113
123
  if os.name == "nt" and command.lower() == "npx":
114
124
  command = "npx.cmd"
115
125
 
116
126
  server_parameters = StdioServerParameters(
117
- command=command, args=self.args, env=self.env
127
+ command=command, args=arguments, env=self.env
118
128
  )
119
129
  (
120
130
  read_stream,
@@ -135,6 +145,7 @@ class _MCPServer(BaseToolkit):
135
145
  # Ensure resources are cleaned up on connection failure
136
146
  await self.disconnect()
137
147
  logger.error(f"Failed to connect to MCP server: {e}")
148
+ raise e
138
149
 
139
150
  async def disconnect(self):
140
151
  r"""Explicitly disconnect from the MCP server."""
@@ -149,7 +160,7 @@ class _MCPServer(BaseToolkit):
149
160
  on the provided `command_or_url`.
150
161
 
151
162
  Yields:
152
- _MCPServer: Instance with active connection ready for tool
163
+ MCPClient: Instance with active connection ready for tool
153
164
  interaction.
154
165
  """
155
166
  try:
@@ -170,7 +181,8 @@ class _MCPServer(BaseToolkit):
170
181
  try:
171
182
  return await self._session.list_tools()
172
183
  except Exception as e:
173
- return f"Failed to list MCP tools: {e!s}"
184
+ logger.exception("Failed to list MCP tools")
185
+ raise e
174
186
 
175
187
  def generate_function_from_mcp_tool(self, mcp_tool: "Tool") -> Callable:
176
188
  r"""Dynamically generates a Python callable function corresponding to
@@ -235,7 +247,7 @@ class _MCPServer(BaseToolkit):
235
247
  logger.error(
236
248
  "MCP Client is not connected. Call `connection()` first."
237
249
  )
238
- return (
250
+ raise RuntimeError(
239
251
  "MCP Client is not connected. Call `connection()` first."
240
252
  )
241
253
 
@@ -245,7 +257,7 @@ class _MCPServer(BaseToolkit):
245
257
  )
246
258
  except Exception as e:
247
259
  logger.error(f"Failed to call MCP tool '{func_name}': {e!s}")
248
- return f"Failed to call MCP tool '{func_name}': {e!s}"
260
+ raise e
249
261
 
250
262
  if not result.content or len(result.content) == 0:
251
263
  return "No data available for this request."
@@ -272,7 +284,7 @@ class _MCPServer(BaseToolkit):
272
284
  logger.error(
273
285
  f"Error processing content from MCP tool response: {e!s}"
274
286
  )
275
- return "Error processing content from MCP tool response"
287
+ raise e
276
288
 
277
289
  dynamic_function.__name__ = func_name
278
290
  dynamic_function.__doc__ = func_desc
@@ -331,6 +343,10 @@ class _MCPServer(BaseToolkit):
331
343
  for mcp_tool in self._mcp_tools
332
344
  ]
333
345
 
346
+ @property
347
+ def session(self) -> Optional["ClientSession"]:
348
+ return self._session
349
+
334
350
 
335
351
  class MCPToolkit(BaseToolkit):
336
352
  r"""MCPToolkit provides a unified interface for managing multiple
@@ -341,7 +357,7 @@ class MCPToolkit(BaseToolkit):
341
357
  MCP services.
342
358
 
343
359
  Args:
344
- servers (Optional[List[_MCPServer]]): List of _MCPServer
360
+ servers (Optional[List[MCPClient]]): List of MCPClient
345
361
  instances to manage.
346
362
  config_path (Optional[str]): Path to a JSON configuration file
347
363
  defining MCP servers.
@@ -359,7 +375,7 @@ class MCPToolkit(BaseToolkit):
359
375
  .. code-block:: json
360
376
 
361
377
  {
362
- "mcpWebServers": {
378
+ "mcpServers": {
363
379
  "protected-server": {
364
380
  "url": "https://example.com/mcp",
365
381
  "timeout": 30,
@@ -372,12 +388,12 @@ class MCPToolkit(BaseToolkit):
372
388
  }
373
389
 
374
390
  Attributes:
375
- servers (List[_MCPServer]): List of _MCPServer instances being managed.
391
+ servers (List[MCPClient]): List of MCPClient instances being managed.
376
392
  """
377
393
 
378
394
  def __init__(
379
395
  self,
380
- servers: Optional[List[_MCPServer]] = None,
396
+ servers: Optional[List[MCPClient]] = None,
381
397
  config_path: Optional[str] = None,
382
398
  ):
383
399
  super().__init__()
@@ -388,7 +404,7 @@ class MCPToolkit(BaseToolkit):
388
404
  "Servers from both sources will be combined."
389
405
  )
390
406
 
391
- self.servers = servers or []
407
+ self.servers: List[MCPClient] = servers or []
392
408
 
393
409
  if config_path:
394
410
  self.servers.extend(self._load_servers_from_config(config_path))
@@ -396,14 +412,14 @@ class MCPToolkit(BaseToolkit):
396
412
  self._exit_stack = AsyncExitStack()
397
413
  self._connected = False
398
414
 
399
- def _load_servers_from_config(self, config_path: str) -> List[_MCPServer]:
415
+ def _load_servers_from_config(self, config_path: str) -> List[MCPClient]:
400
416
  r"""Loads MCP server configurations from a JSON file.
401
417
 
402
418
  Args:
403
419
  config_path (str): Path to the JSON configuration file.
404
420
 
405
421
  Returns:
406
- List[_MCPServer]: List of configured _MCPServer instances.
422
+ List[MCPClient]: List of configured MCPClient instances.
407
423
  """
408
424
  try:
409
425
  with open(config_path, "r", encoding="utf-8") as f:
@@ -413,14 +429,13 @@ class MCPToolkit(BaseToolkit):
413
429
  logger.warning(
414
430
  f"Invalid JSON in config file '{config_path}': {e!s}"
415
431
  )
416
- return []
417
- except FileNotFoundError:
432
+ raise e
433
+ except FileNotFoundError as e:
418
434
  logger.warning(f"Config file not found: '{config_path}'")
419
- return []
435
+ raise e
420
436
 
421
437
  all_servers = []
422
438
 
423
- # Process local MCP servers
424
439
  mcp_servers = data.get("mcpServers", {})
425
440
  if not isinstance(mcp_servers, dict):
426
441
  logger.warning("'mcpServers' is not a dictionary, skipping...")
@@ -433,47 +448,21 @@ class MCPToolkit(BaseToolkit):
433
448
  )
434
449
  continue
435
450
 
436
- if "command" not in cfg:
451
+ if "command" not in cfg and "url" not in cfg:
437
452
  logger.warning(
438
- f"Missing required 'command' field for server '{name}'"
453
+ f"Missing required 'command' or 'url' field for server "
454
+ f"'{name}'"
439
455
  )
440
456
  continue
441
457
 
442
- server = _MCPServer(
443
- command_or_url=cfg["command"],
458
+ server = MCPClient(
459
+ command_or_url=cast(str, cfg.get("command") or cfg.get("url")),
444
460
  args=cfg.get("args", []),
445
461
  env={**os.environ, **cfg.get("env", {})},
446
462
  timeout=cfg.get("timeout", None),
447
463
  )
448
464
  all_servers.append(server)
449
465
 
450
- # Process remote MCP web servers
451
- mcp_web_servers = data.get("mcpWebServers", {})
452
- if not isinstance(mcp_web_servers, dict):
453
- logger.warning("'mcpWebServers' is not a dictionary, skipping...")
454
- mcp_web_servers = {}
455
-
456
- for name, cfg in mcp_web_servers.items():
457
- if not isinstance(cfg, dict):
458
- logger.warning(
459
- f"Configuration for web server '{name}' must"
460
- "be a dictionary"
461
- )
462
- continue
463
-
464
- if "url" not in cfg:
465
- logger.warning(
466
- f"Missing required 'url' field for web server '{name}'"
467
- )
468
- continue
469
-
470
- server = _MCPServer(
471
- command_or_url=cfg["url"],
472
- timeout=cfg.get("timeout", None),
473
- headers=cfg.get("headers", {}),
474
- )
475
- all_servers.append(server)
476
-
477
466
  return all_servers
478
467
 
479
468
  async def connect(self):
@@ -497,6 +486,7 @@ class MCPToolkit(BaseToolkit):
497
486
  # Ensure resources are cleaned up on connection failure
498
487
  await self.disconnect()
499
488
  logger.error(f"Failed to connect to one or more MCP servers: {e}")
489
+ raise e
500
490
 
501
491
  async def disconnect(self):
502
492
  r"""Explicitly disconnect from all MCP servers."""
@@ -13,14 +13,16 @@
13
13
  # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
14
 
15
15
  import os
16
- from typing import Any, Dict, Optional
16
+ from typing import Any, Dict, List, Optional
17
17
 
18
18
  import requests
19
19
 
20
+ from camel.toolkits import FunctionTool
20
21
  from camel.toolkits.base import BaseToolkit
21
- from camel.utils import api_keys_required
22
+ from camel.utils import MCPServer, api_keys_required
22
23
 
23
24
 
25
+ @MCPServer()
24
26
  class MeshyToolkit(BaseToolkit):
25
27
  r"""A class representing a toolkit for 3D model generation using Meshy.
26
28
 
@@ -188,3 +190,19 @@ class MeshyToolkit(BaseToolkit):
188
190
 
189
191
  # Wait for refinement completion and return final result
190
192
  return self.wait_for_task_completion(refine_task_id)
193
+
194
+ def get_tools(self) -> List[FunctionTool]:
195
+ r"""Returns a list of FunctionTool objects representing the
196
+ functions in the toolkit.
197
+
198
+ Returns:
199
+ List[FunctionTool]: A list of FunctionTool objects
200
+ representing the functions in the toolkit.
201
+ """
202
+ return [
203
+ FunctionTool(self.generate_3d_preview),
204
+ FunctionTool(self.refine_3d_model),
205
+ FunctionTool(self.get_task_status),
206
+ FunctionTool(self.wait_for_task_completion),
207
+ FunctionTool(self.generate_3d_model_complete),
208
+ ]
@@ -18,10 +18,12 @@ from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Union
18
18
  from camel.logger import get_logger
19
19
  from camel.toolkits import FunctionTool
20
20
  from camel.toolkits.base import BaseToolkit
21
+ from camel.utils import MCPServer
21
22
 
22
23
  logger = get_logger(__name__)
23
24
 
24
25
 
26
+ @MCPServer()
25
27
  class NetworkXToolkit(BaseToolkit):
26
28
  _nx = None # Class variable to store the networkx module
27
29
 
@@ -16,6 +16,7 @@ from typing import List, Optional, cast
16
16
 
17
17
  from camel.toolkits import FunctionTool
18
18
  from camel.toolkits.base import BaseToolkit
19
+ from camel.utils import MCPServer, api_keys_required
19
20
 
20
21
 
21
22
  def get_plain_text_from_rich_text(rich_text: List[dict]) -> str:
@@ -66,6 +67,7 @@ def get_media_source_text(block: dict) -> str:
66
67
  return source
67
68
 
68
69
 
70
+ @MCPServer()
69
71
  class NotionToolkit(BaseToolkit):
70
72
  r"""A toolkit for retrieving information from the user's notion pages.
71
73
 
@@ -76,6 +78,11 @@ class NotionToolkit(BaseToolkit):
76
78
  the notion APIs.
77
79
  """
78
80
 
81
+ @api_keys_required(
82
+ [
83
+ ("notion_token", 'NOTION_TOKEN'),
84
+ ]
85
+ )
79
86
  def __init__(
80
87
  self,
81
88
  notion_token: Optional[str] = None,
@@ -0,0 +1,131 @@
1
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ # ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14
+
15
+ import os
16
+ from typing import List, Optional
17
+
18
+ from openai import OpenAI
19
+
20
+ from camel.logger import get_logger
21
+ from camel.models import BaseModelBackend, ModelFactory
22
+ from camel.toolkits.base import BaseToolkit
23
+ from camel.toolkits.function_tool import FunctionTool
24
+ from camel.types import ModelPlatformType, ModelType
25
+ from camel.utils import api_keys_required
26
+
27
+ logger = get_logger(__name__)
28
+
29
+
30
+ class OpenAIAgentToolkit(BaseToolkit):
31
+ r"""Toolkit for accessing OpenAI's agent tools including web search and
32
+ file search.
33
+
34
+ Provides access to OpenAI's web search and file search capabilities
35
+ through the Responses API, allowing agents to retrieve information from
36
+ the web and search through uploaded files.
37
+ """
38
+
39
+ @api_keys_required(
40
+ [
41
+ (None, "OPENAI_API_KEY"),
42
+ ]
43
+ )
44
+ def __init__(
45
+ self,
46
+ model: Optional[BaseModelBackend] = None,
47
+ api_key: Optional[str] = None,
48
+ ) -> None:
49
+ r"""Initialize the OpenAI agent toolkit.
50
+
51
+ Args:
52
+ model (BaseModelBackend): The OpenAI model to use for responses.
53
+ If None, defaults to gpt-4o-mini. (default: :obj:`None`)
54
+ api_key (str): OpenAI API key. If not provided, will attempt to
55
+ use OPENAI_API_KEY environment variable. (default: :obj:`None`)
56
+ """
57
+ super().__init__()
58
+ self.api_key = api_key or os.getenv("OPENAI_API_KEY")
59
+ self.client = OpenAI(api_key=self.api_key)
60
+ self.model = model or ModelFactory.create(
61
+ model_platform=ModelPlatformType.OPENAI,
62
+ model_type=ModelType.GPT_4O_MINI,
63
+ )
64
+
65
+ def web_search(self, query: str) -> str:
66
+ r"""Perform a web search using OpenAI's web search tool.
67
+
68
+ Args:
69
+ query (str): The search query.
70
+
71
+ Returns:
72
+ str: The search result or error message.
73
+ """
74
+ try:
75
+ response = self.client.responses.create(
76
+ model=str(self.model.model_type),
77
+ tools=[{"type": "web_search_preview"}],
78
+ input=query,
79
+ )
80
+ return response.output_text
81
+
82
+ except Exception as e:
83
+ logger.error(f"Web search failed: {e!s}")
84
+ return f"Web search failed: {e!s}"
85
+
86
+ def file_search(
87
+ self,
88
+ query: str,
89
+ vector_store_id: str,
90
+ ) -> str:
91
+ r"""Search through files using OpenAI's file search tool.
92
+
93
+ Args:
94
+ query (str): The search query.
95
+ vector_store_id (str): The vector store ID to search in.
96
+
97
+ Returns:
98
+ str: The search result or error message.
99
+ """
100
+ if not vector_store_id.strip():
101
+ logger.error("Empty vector store ID provided.")
102
+ return "Empty vector store ID provided, it cannot be empty."
103
+
104
+ try:
105
+ response = self.client.responses.create(
106
+ model=str(self.model.model_type),
107
+ tools=[
108
+ {
109
+ "type": "file_search",
110
+ "vector_store_ids": [vector_store_id],
111
+ }
112
+ ],
113
+ input=query,
114
+ )
115
+ return response.output_text
116
+
117
+ except Exception as e:
118
+ logger.error(f"File search failed: {e!s}")
119
+ return f"File search failed: {e!s}"
120
+
121
+ def get_tools(self) -> List[FunctionTool]:
122
+ r"""Retrieve available toolkit functions as FunctionTool objects.
123
+
124
+ Returns:
125
+ List[FunctionTool]: Collection of FunctionTool objects representing
126
+ the available search functions in this toolkit.
127
+ """
128
+ return [
129
+ FunctionTool(self.web_search),
130
+ FunctionTool(self.file_search),
131
+ ]
@@ -17,9 +17,10 @@ from typing import List, Literal, Optional
17
17
 
18
18
  from camel.toolkits.base import BaseToolkit
19
19
  from camel.toolkits.function_tool import FunctionTool
20
- from camel.utils import api_keys_required, dependencies_required
20
+ from camel.utils import MCPServer, api_keys_required, dependencies_required
21
21
 
22
22
 
23
+ @MCPServer()
23
24
  class OpenBBToolkit(BaseToolkit):
24
25
  r"""A toolkit for accessing financial data and analysis through OpenBB
25
26
  Platform.
@@ -18,10 +18,12 @@ import requests
18
18
 
19
19
  from camel.logger import get_logger
20
20
  from camel.toolkits import BaseToolkit, FunctionTool
21
+ from camel.utils import MCPServer
21
22
 
22
23
  logger = get_logger(__name__)
23
24
 
24
25
 
26
+ @MCPServer()
25
27
  class PubMedToolkit(BaseToolkit):
26
28
  r"""A toolkit for interacting with PubMed's E-utilities API to access
27
29
  MEDLINE data.
@@ -18,9 +18,10 @@ from typing import Any, Dict, List, Optional, Union
18
18
 
19
19
  from camel.toolkits import FunctionTool
20
20
  from camel.toolkits.base import BaseToolkit
21
- from camel.utils import retry_on_error
21
+ from camel.utils import MCPServer, retry_on_error
22
22
 
23
23
 
24
+ @MCPServer()
24
25
  class RedditToolkit(BaseToolkit):
25
26
  r"""A class representing a toolkit for Reddit operations.
26
27
 
@@ -17,9 +17,10 @@ from camel.retrievers import AutoRetriever
17
17
  from camel.toolkits import FunctionTool
18
18
  from camel.toolkits.base import BaseToolkit
19
19
  from camel.types import StorageType
20
- from camel.utils import Constants
20
+ from camel.utils import Constants, MCPServer
21
21
 
22
22
 
23
+ @MCPServer()
23
24
  class RetrievalToolkit(BaseToolkit):
24
25
  r"""A class representing a toolkit for information retrieval.
25
26
 
@@ -19,9 +19,10 @@ import requests
19
19
 
20
20
  from camel.toolkits.base import BaseToolkit
21
21
  from camel.toolkits.function_tool import FunctionTool
22
- from camel.utils import api_keys_required, dependencies_required
22
+ from camel.utils import MCPServer, api_keys_required, dependencies_required
23
23
 
24
24
 
25
+ @MCPServer()
25
26
  class SearchToolkit(BaseToolkit):
26
27
  r"""A class representing a toolkit for web search.
27
28