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

@@ -0,0 +1,456 @@
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 TYPE_CHECKING, Dict, List, Optional, Union
17
+
18
+ if TYPE_CHECKING:
19
+ from aci.types.app_configurations import AppConfiguration
20
+ from aci.types.apps import AppBasic, AppDetails
21
+ from aci.types.linked_accounts import LinkedAccount
22
+
23
+ from camel.logger import get_logger
24
+ from camel.toolkits import FunctionTool
25
+ from camel.toolkits.base import BaseToolkit
26
+ from camel.utils import api_keys_required, dependencies_required
27
+
28
+ logger = get_logger(__name__)
29
+
30
+
31
+ @api_keys_required(
32
+ [
33
+ (None, 'ACI_API_KEY'),
34
+ ]
35
+ )
36
+ class ACIToolkit(BaseToolkit):
37
+ r"""A toolkit for interacting with the ACI API."""
38
+
39
+ @dependencies_required('aci')
40
+ def __init__(
41
+ self,
42
+ api_key: Optional[str] = None,
43
+ base_url: Optional[str] = None,
44
+ linked_account_owner_id: Optional[str] = None,
45
+ timeout: Optional[float] = None,
46
+ ) -> None:
47
+ r"""Initialize the ACI toolkit.
48
+
49
+ Args:
50
+ api_key (Optional[str]): The API key for authentication.
51
+ (default: :obj: `None`)
52
+ base_url (Optional[str]): The base URL for the ACI API.
53
+ (default: :obj: `None`)
54
+ linked_account_owner_id (Optional[str]): ID of the owner of the
55
+ linked account, e.g., "johndoe"
56
+ (default: :obj: `None`)
57
+ timeout (Optional[float]): Request timeout.
58
+ (default: :obj: `None`)
59
+ """
60
+ from aci import ACI
61
+
62
+ super().__init__(timeout)
63
+
64
+ self._api_key = api_key or os.getenv("ACI_API_KEY")
65
+ self._base_url = base_url or os.getenv("ACI_BASE_URL")
66
+ self.client = ACI(api_key=self._api_key, base_url=self._base_url)
67
+ self.linked_account_owner_id = linked_account_owner_id
68
+
69
+ def search_tool(
70
+ self,
71
+ intent: Optional[str] = None,
72
+ allowed_app_only: bool = True,
73
+ include_functions: bool = False,
74
+ categories: Optional[List[str]] = None,
75
+ limit: Optional[int] = 10,
76
+ offset: Optional[int] = 0,
77
+ ) -> Union[List["AppBasic"], str]:
78
+ r"""Search for apps based on intent.
79
+
80
+ Args:
81
+ intent (Optional[str]): Search results will be sorted by relevance
82
+ to this intent.
83
+ (default: :obj: `None`)
84
+ allowed_app_only (bool): If true, only return apps that
85
+ are allowed by the agent/accessor, identified by the api key.
86
+ (default: :obj: `True`)
87
+ include_functions (bool): If true, include functions
88
+ (name and description) in the search results.
89
+ (default: :obj: `False`)
90
+ categories (Optional[List[str]]): List of categories to filter the
91
+ search results. Defaults to an empty list.
92
+ (default: :obj: `None`)
93
+ limit (Optional[int]): Maximum number of results to return.
94
+ (default: :obj: `10`)
95
+ offset (Optional[int]): Offset for pagination.
96
+ (default: :obj: `0`)
97
+
98
+ Returns:
99
+ Optional[List[AppBasic]]: List of matching apps if successful,
100
+ error message otherwise.
101
+ """
102
+ try:
103
+ apps = self.client.apps.search(
104
+ intent=intent,
105
+ allowed_apps_only=allowed_app_only,
106
+ include_functions=include_functions,
107
+ categories=categories,
108
+ limit=limit,
109
+ offset=offset,
110
+ )
111
+ return apps
112
+ except Exception as e:
113
+ logger.error(f"Error: {e}")
114
+ return str(e)
115
+
116
+ def list_configured_apps(
117
+ self,
118
+ app_names: Optional[List[str]] = None,
119
+ limit: Optional[int] = 10,
120
+ offset: Optional[int] = 0,
121
+ ) -> Union[List["AppConfiguration"], str]:
122
+ r"""List all configured apps.
123
+
124
+ Args:
125
+ app_names (Optional[List[str]]): List of app names to filter the
126
+ results. (default: :obj: `None`)
127
+ limit (Optional[int]): Maximum number of results to return.
128
+ (default: :obj: `10`)
129
+ offset (Optional[int]): Offset for pagination. (default: :obj: `0`)
130
+
131
+ Returns:
132
+ Union[List[AppConfiguration], str]: List of configured apps if
133
+ successful, error message otherwise.
134
+ """
135
+ try:
136
+ apps = self.client.app_configurations.list(
137
+ app_names=app_names, limit=limit, offset=offset
138
+ )
139
+ return apps
140
+ except Exception as e:
141
+ logger.error(f"Error: {e}")
142
+ return str(e)
143
+
144
+ def configure_app(self, app_name: str) -> Union[Dict, str]:
145
+ r"""Configure an app with specified authentication type.
146
+
147
+ Args:
148
+ app_name (str): Name of the app to configure.
149
+
150
+ Returns:
151
+ Union[Dict, str]: Configuration result or error message.
152
+ """
153
+ from aci.types.enums import SecurityScheme
154
+
155
+ try:
156
+ app_details = self.get_app_details(app_name)
157
+ if app_details and app_details.security_schemes[0] == "api_key":
158
+ security_scheme = SecurityScheme.API_KEY
159
+ elif app_details and app_details.security_schemes[0] == "oauth2":
160
+ security_scheme = SecurityScheme.OAUTH2
161
+ else:
162
+ security_scheme = SecurityScheme.NO_AUTH
163
+ configuration = self.client.app_configurations.create(
164
+ app_name=app_name, security_scheme=security_scheme
165
+ )
166
+ return configuration
167
+ except Exception as e:
168
+ logger.error(f"Error: {e}")
169
+ return str(e)
170
+
171
+ def get_app_configuration(
172
+ self, app_name: str
173
+ ) -> Union["AppConfiguration", str]:
174
+ r"""Get app configuration by app name.
175
+
176
+ Args:
177
+ app_name (str): Name of the app to get configuration for.
178
+
179
+ Returns:
180
+ Union[AppConfiguration, str]: App configuration if successful,
181
+ error message otherwise.
182
+ """
183
+ try:
184
+ app = self.client.app_configurations.get(app_name=app_name)
185
+ return app
186
+ except Exception as e:
187
+ logger.error(f"Error: {e}")
188
+ return str(e)
189
+
190
+ def delete_app(self, app_name: str) -> Optional[str]:
191
+ r"""Delete an app configuration.
192
+
193
+ Args:
194
+ app_name (str): Name of the app to delete.
195
+
196
+ Returns:
197
+ Optional[str]: None if successful, error message otherwise.
198
+ """
199
+ try:
200
+ self.client.app_configurations.delete(app_name=app_name)
201
+ return None
202
+ except Exception as e:
203
+ logger.error(f"Error: {e}")
204
+ return str(e)
205
+
206
+ def link_account(
207
+ self,
208
+ app_name: str,
209
+ ) -> Union["LinkedAccount", str]:
210
+ r"""Link an account to a configured app.
211
+
212
+ Args:
213
+ app_name (str): Name of the app to link the account to.
214
+
215
+ Returns:
216
+ Union[LinkedAccount, str]: LinkedAccount object if successful,
217
+ error message otherwise.
218
+ """
219
+ from aci.types.enums import SecurityScheme
220
+
221
+ try:
222
+ security_scheme = self.client.app_configurations.get(
223
+ app_name=app_name
224
+ ).security_scheme
225
+
226
+ if security_scheme == SecurityScheme.API_KEY:
227
+ return self.client.linked_accounts.link(
228
+ app_name=app_name,
229
+ linked_account_owner_id=self.linked_account_owner_id,
230
+ security_scheme=security_scheme,
231
+ api_key=self._api_key,
232
+ )
233
+ else:
234
+ return self.client.linked_accounts.link(
235
+ app_name=app_name,
236
+ linked_account_owner_id=self.linked_account_owner_id,
237
+ security_scheme=security_scheme,
238
+ )
239
+ except Exception as e:
240
+ logger.error(f"Error linking account: {e!s}")
241
+ return str(e)
242
+
243
+ def get_app_details(self, app_name: str) -> "AppDetails":
244
+ r"""Get details of an app.
245
+
246
+ Args:
247
+ app_name (str): Name of the app to get details for.
248
+
249
+ Returns:
250
+ AppDetails: App details.
251
+ """
252
+ app = self.client.apps.get(app_name=app_name)
253
+ return app
254
+
255
+ def get_linked_accounts(
256
+ self, app_name: str
257
+ ) -> Union[List["LinkedAccount"], str]:
258
+ r"""List all linked accounts for a specific app.
259
+
260
+ Args:
261
+ app_name (str): Name of the app to get linked accounts for.
262
+
263
+ Returns:
264
+ Union[List[LinkedAccount], str]: List of linked accounts if
265
+ successful, error message otherwise.
266
+ """
267
+ try:
268
+ accounts = self.client.linked_accounts.list(app_name=app_name)
269
+ return accounts
270
+ except Exception as e:
271
+ logger.error(f"Error: {e}")
272
+ return str(e)
273
+
274
+ def enable_linked_account(
275
+ self, linked_account_id: str
276
+ ) -> Union["LinkedAccount", str]:
277
+ r"""Enable a linked account.
278
+
279
+ Args:
280
+ linked_account_id (str): ID of the linked account to enable.
281
+
282
+ Returns:
283
+ Union[LinkedAccount, str]: Linked account if successful, error
284
+ message otherwise.
285
+ """
286
+ try:
287
+ linked_account = self.client.linked_accounts.enable(
288
+ linked_account_id=linked_account_id
289
+ )
290
+ return linked_account
291
+ except Exception as e:
292
+ logger.error(f"Error: {e}")
293
+ return str(e)
294
+
295
+ def disable_linked_account(
296
+ self, linked_account_id: str
297
+ ) -> Union["LinkedAccount", str]:
298
+ r"""Disable a linked account.
299
+
300
+ Args:
301
+ linked_account_id (str): ID of the linked account to disable.
302
+
303
+ Returns:
304
+ Union[LinkedAccount, str]: The updated linked account if
305
+ successful, error message otherwise.
306
+ """
307
+ try:
308
+ linked_account = self.client.linked_accounts.disable(
309
+ linked_account_id=linked_account_id
310
+ )
311
+ return linked_account
312
+ except Exception as e:
313
+ logger.error(f"Error: {e}")
314
+ return str(e)
315
+
316
+ def delete_linked_account(self, linked_account_id: str) -> str:
317
+ r"""Delete a linked account.
318
+
319
+ Args:
320
+ linked_account_id (str): ID of the linked account to delete.
321
+
322
+ Returns:
323
+ str: Success message if successful, error message otherwise.
324
+ """
325
+ try:
326
+ self.client.linked_accounts.delete(
327
+ linked_account_id=linked_account_id
328
+ )
329
+ return (
330
+ f"linked_account_id: {linked_account_id} deleted successfully"
331
+ )
332
+ except Exception as e:
333
+ logger.error(f"Error: {e}")
334
+ return str(e)
335
+
336
+ def function_definition(self, func_name: str) -> Dict:
337
+ r"""Get the function definition for an app.
338
+
339
+ Args:
340
+ app_name (str): Name of the app to get function definition for
341
+
342
+ Returns:
343
+ Dict: Function definition dictionary.
344
+ """
345
+ return self.client.functions.get_definition(func_name)
346
+
347
+ def search_function(
348
+ self,
349
+ app_names: Optional[List[str]] = None,
350
+ intent: Optional[str] = None,
351
+ allowed_apps_only: bool = True,
352
+ limit: Optional[int] = 10,
353
+ offset: Optional[int] = 0,
354
+ ) -> List[Dict]:
355
+ r"""Search for functions based on intent.
356
+
357
+ Args:
358
+ app_names (Optional[List[str]]): List of app names to filter the
359
+ search results. (default: :obj: `None`)
360
+ intent (Optional[str]): The search query/intent.
361
+ (default: :obj: `None`)
362
+ allowed_apps_only (bool): If true, only return
363
+ functions from allowed apps. (default: :obj: `True`)
364
+ limit (Optional[int]): Maximum number of results to return.
365
+ (default: :obj: `10`)
366
+ offset (Optional[int]): Offset for pagination.
367
+ (default: :obj: `0`)
368
+
369
+ Returns:
370
+ List[Dict]: List of matching functions
371
+ """
372
+ return self.client.functions.search(
373
+ app_names=app_names,
374
+ intent=intent,
375
+ allowed_apps_only=allowed_apps_only,
376
+ limit=limit,
377
+ offset=offset,
378
+ )
379
+
380
+ def execute_function(
381
+ self,
382
+ function_name: str,
383
+ function_arguments: Dict,
384
+ linked_account_owner_id: str,
385
+ allowed_apps_only: bool = False,
386
+ ) -> Dict:
387
+ r"""Execute a function call.
388
+
389
+ Args:
390
+ function_name (str): Name of the function to execute.
391
+ function_arguments (Dict): Arguments to pass to the function.
392
+ linked_account_owner_id (str): To specify the end-user (account
393
+ owner) on behalf of whom you want to execute functions
394
+ You need to first link corresponding account with the same
395
+ owner id in the ACI dashboard (https://platform.aci.dev).
396
+ allowed_apps_only (bool): If true, only returns functions/apps
397
+ that are allowed to be used by the agent/accessor, identified
398
+ by the api key. (default: :obj: `False`)
399
+
400
+ Returns:
401
+ Dict: Result of the function execution
402
+ """
403
+ result = self.client.handle_function_call(
404
+ function_name,
405
+ function_arguments,
406
+ linked_account_owner_id,
407
+ allowed_apps_only,
408
+ )
409
+ return result
410
+
411
+ def get_tools(self) -> List[FunctionTool]:
412
+ r"""Get a list of tools (functions) available in the configured apps.
413
+
414
+ Returns:
415
+ List[FunctionTool]: List of FunctionTool objects representing
416
+ available functions
417
+ """
418
+ _configure_app = [
419
+ app.app_name # type: ignore[union-attr]
420
+ for app in self.list_configured_apps() or []
421
+ ]
422
+ _all_function = self.search_function(app_names=_configure_app)
423
+ tools = [
424
+ FunctionTool(self.search_tool),
425
+ FunctionTool(self.list_configured_apps),
426
+ FunctionTool(self.configure_app),
427
+ FunctionTool(self.get_app_configuration),
428
+ FunctionTool(self.delete_app),
429
+ FunctionTool(self.link_account),
430
+ FunctionTool(self.get_app_details),
431
+ FunctionTool(self.get_linked_accounts),
432
+ FunctionTool(self.enable_linked_account),
433
+ FunctionTool(self.disable_linked_account),
434
+ FunctionTool(self.delete_linked_account),
435
+ FunctionTool(self.function_definition),
436
+ FunctionTool(self.search_function),
437
+ ]
438
+
439
+ for function in _all_function:
440
+ schema = self.client.functions.get_definition(
441
+ function['function']['name']
442
+ )
443
+
444
+ def dummy_func(*, schema=schema, **kwargs):
445
+ return self.execute_function(
446
+ function_name=schema['function']['name'],
447
+ function_arguments=kwargs,
448
+ linked_account_owner_id=self.linked_account_owner_id,
449
+ )
450
+
451
+ tool = FunctionTool(
452
+ func=dummy_func,
453
+ openai_tool_schema=schema,
454
+ )
455
+ tools.append(tool)
456
+ return tools
@@ -458,9 +458,11 @@ class FunctionTool:
458
458
  for param_name in properties.keys():
459
459
  param_dict = properties[param_name]
460
460
  if "description" not in param_dict:
461
- warnings.warn(f"""Parameter description is missing for
462
- {param_dict}. This may affect the quality of tool
463
- calling.""")
461
+ warnings.warn(
462
+ f"Parameter description is missing "
463
+ f"for {param_dict}. This may affect the "
464
+ f"quality of tool calling."
465
+ )
464
466
 
465
467
  def get_openai_tool_schema(self) -> Dict[str, Any]:
466
468
  r"""Gets the OpenAI tool schema for this function.
@@ -0,0 +1,228 @@
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 Any, Dict, List, Optional
17
+
18
+ import requests
19
+
20
+ from camel.logger import get_logger
21
+ from camel.toolkits.base import BaseToolkit
22
+ from camel.toolkits.function_tool import FunctionTool
23
+ from camel.utils import MCPServer, api_keys_required, dependencies_required
24
+
25
+ logger = get_logger(__name__)
26
+
27
+
28
+ @MCPServer()
29
+ class KlavisToolkit(BaseToolkit):
30
+ r"""A class representing a toolkit for interacting with Klavis API.
31
+
32
+ This class provides methods for interacting with Klavis MCP server
33
+ instances, retrieving server information, managing tools, and handling
34
+ authentication.
35
+
36
+ Attributes:
37
+ api_key (str): The API key for authenticating with Klavis API.
38
+ base_url (str): The base URL for Klavis API endpoints.
39
+ timeout (Optional[float]): The timeout value for API requests
40
+ in seconds. If None, no timeout is applied.
41
+ (default: :obj:`None`)
42
+ """
43
+
44
+ @dependencies_required("requests")
45
+ @api_keys_required(
46
+ [
47
+ (None, "KLAVIS_API_KEY"),
48
+ ]
49
+ )
50
+ def __init__(self, timeout: Optional[float] = None) -> None:
51
+ r"""Initialize the KlavisToolkit with API client. The API key is
52
+ retrieved from environment variables.
53
+ """
54
+ super().__init__(timeout=timeout)
55
+ self.api_key = os.environ.get("KLAVIS_API_KEY")
56
+ self.base_url = "https://api.klavis.ai"
57
+
58
+ def _request(
59
+ self,
60
+ method: str,
61
+ endpoint: str,
62
+ payload: Optional[Dict[str, Any]] = None,
63
+ additional_headers: Optional[Dict[str, str]] = None,
64
+ ) -> Dict[str, Any]:
65
+ r"""Make an HTTP request to the Klavis API.
66
+
67
+ Args:
68
+ method (str): HTTP method (e.g., 'GET', 'POST', 'DELETE').
69
+ endpoint (str): API endpoint path.
70
+ payload (Optional[Dict[str, Any]]): JSON payload for POST
71
+ requests.
72
+ additional_headers (Optional[Dict[str, str]]): Additional
73
+ headers to include in the request.
74
+
75
+ Returns:
76
+ Dict[str, Any]: The JSON response from the API or an error
77
+ dict.
78
+ """
79
+ url = f"{self.base_url}{endpoint}"
80
+ headers = {
81
+ 'accept': 'application/json',
82
+ 'Authorization': f'Bearer {self.api_key}',
83
+ }
84
+ if additional_headers:
85
+ headers.update(additional_headers)
86
+
87
+ logger.debug(
88
+ f"Making {method} request to {url} with payload: {payload}"
89
+ )
90
+
91
+ try:
92
+ response = requests.request(
93
+ method,
94
+ url,
95
+ headers=headers,
96
+ json=payload,
97
+ timeout=self.timeout,
98
+ )
99
+ response.raise_for_status()
100
+ return response.json()
101
+ except requests.exceptions.RequestException as e:
102
+ logger.error(f"Request failed for {method} {endpoint}: {e!s}")
103
+ return {"error": f"Request failed: {e!s}"}
104
+ except ValueError:
105
+ logger.error(f"Response for {method} {endpoint} is not valid JSON")
106
+ return {"error": "Response is not valid JSON"}
107
+
108
+ def create_server_instance(
109
+ self, server_name: str, user_id: str, platform_name: str
110
+ ) -> Dict[str, Any]:
111
+ r"""Create a Server-Sent Events (SSE) URL for a specified MCP server.
112
+
113
+ Args:
114
+ server_name (str): The name of the target MCP server.
115
+ user_id (str): The ID for the user requesting the server URL.
116
+ platform_name (str): The name of the platform associated
117
+ with the user.
118
+
119
+ Returns:
120
+ Dict[str, Any]: Response containing the server instance details.
121
+ """
122
+ endpoint = "/mcp-server/instance/create"
123
+ payload = {
124
+ "serverName": server_name,
125
+ "userId": user_id,
126
+ "platformName": platform_name,
127
+ }
128
+ headers = {'Content-Type': 'application/json'}
129
+ return self._request(
130
+ 'POST', endpoint, payload=payload, additional_headers=headers
131
+ )
132
+
133
+ def get_server_instance(self, instance_id: str) -> Dict[str, Any]:
134
+ r"""Get details of a specific server connection instance.
135
+
136
+ Args:
137
+ instance_id (str): The ID of the connection instance whose status
138
+ is being checked.
139
+
140
+ Returns:
141
+ Dict[str, Any]: Details about the server instance.
142
+ """
143
+ endpoint = f"/mcp-server/instance/get/{instance_id}"
144
+ return self._request('GET', endpoint)
145
+
146
+ def delete_auth_data(self, instance_id: str) -> Dict[str, Any]:
147
+ r"""Delete authentication metadata for a specific server
148
+ connection instance.
149
+
150
+ Args:
151
+ instance_id (str): The ID of the connection instance to
152
+ delete auth for.
153
+
154
+ Returns:
155
+ Dict[str, Any]: Status response for the operation.
156
+ """
157
+ endpoint = f"/mcp-server/instance/delete-auth/{instance_id}"
158
+ return self._request('DELETE', endpoint)
159
+
160
+ def delete_server_instance(self, instance_id: str) -> Dict[str, Any]:
161
+ r"""Completely removes a server connection instance.
162
+
163
+ Args:
164
+ instance_id (str): The ID of the connection instance to delete.
165
+
166
+ Returns:
167
+ Dict[str, Any]: Status response for the operation.
168
+ """
169
+ endpoint = f"/mcp-server/instance/delete/{instance_id}"
170
+ return self._request('DELETE', endpoint)
171
+
172
+ def get_server_tools(self, server_name: str) -> Dict[str, Any]:
173
+ r"""Get list of tool names for a specific MCP server.
174
+
175
+ Args:
176
+ server_name (str): The name of the target MCP server.
177
+
178
+ Returns:
179
+ Dict[str, Any]: List of tools available for the specified server.
180
+ """
181
+ endpoint = f"/mcp-server/tools/{server_name}"
182
+ return self._request('GET', endpoint)
183
+
184
+ def get_all_servers(self) -> Dict[str, Any]:
185
+ r"""Get all MCP servers with their basic information.
186
+
187
+ Returns:
188
+ Dict[str, Any]: Information about all available MCP servers.
189
+ """
190
+ endpoint = "/mcp-server/servers"
191
+ return self._request('GET', endpoint)
192
+
193
+ def set_auth_token(
194
+ self, instance_id: str, auth_token: str
195
+ ) -> Dict[str, Any]:
196
+ r"""Sets an authentication token for a specific instance.
197
+
198
+ Args:
199
+ instance_id (str): The ID for the connection instance.
200
+ auth_token (str): The authentication token to save.
201
+
202
+ Returns:
203
+ Dict[str, Any]: Status response for the operation.
204
+ """
205
+ endpoint = "/mcp-server/instance/set-auth-token"
206
+ payload = {"instanceId": instance_id, "authToken": auth_token}
207
+ headers = {'Content-Type': 'application/json'}
208
+ return self._request(
209
+ 'POST', endpoint, payload=payload, additional_headers=headers
210
+ )
211
+
212
+ def get_tools(self) -> List[FunctionTool]:
213
+ r"""Returns a list of FunctionTool objects representing the functions
214
+ in the toolkit.
215
+
216
+ Returns:
217
+ List[FunctionTool]: A list of FunctionTool objects representing
218
+ the functions in the toolkit.
219
+ """
220
+ return [
221
+ FunctionTool(self.create_server_instance),
222
+ FunctionTool(self.get_server_instance),
223
+ FunctionTool(self.delete_auth_data),
224
+ FunctionTool(self.delete_server_instance),
225
+ FunctionTool(self.get_server_tools),
226
+ FunctionTool(self.get_all_servers),
227
+ FunctionTool(self.set_auth_token),
228
+ ]