universal-mcp 0.1.24rc6__py3-none-any.whl → 0.1.24rc8__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.
@@ -1,20 +1,23 @@
1
1
  # AgentR Python SDK
2
2
 
3
3
  The official Python SDK for the AgentR platform, a component of the Universal MCP framework.
4
- Currently in beta, breaking changes are expected.
5
4
 
6
- The AgentR Python SDK provides convenient access to the AgentR REST API from any Python 3.10+
7
- application, allowing for dynamic loading and management of tools and integrations.
5
+ *Currently in beta, breaking changes are expected.*
6
+
7
+ The AgentR Python SDK provides convenient access to the AgentR REST API from any Python 3.10+ application, allowing for dynamic loading and management of tools and integrations.
8
8
 
9
9
  ## Installation
10
+
10
11
  ```bash
11
12
  pip install universal-mcp
12
13
  ```
13
14
 
14
15
  ## Usage
16
+
15
17
  The AgentR platform is designed to seamlessly integrate a wide array of tools into your agentic applications. The primary entry point for this is the `Agentr` class, which provides a high-level interface for loading and listing tools.
16
18
 
17
19
  ### High-Level Client (`Agentr`)
20
+
18
21
  This is the recommended way to get started. It abstracts away the details of the registry and tool management.
19
22
 
20
23
  ```python
@@ -29,7 +32,7 @@ agentr = Agentr(
29
32
  )
30
33
 
31
34
  # Load specific tools from the AgentR server into the tool manager
32
- agentr.load_tools(["reddit_search_subreddits", "google_drive_list_files"])
35
+ agentr.load_tools(["reddit__search_subreddits", "google-drive__list_files"])
33
36
 
34
37
  # List the tools that are now loaded and ready to be used
35
38
  # You can specify a format compatible with your LLM (e.g., OPENAI)
@@ -41,10 +44,10 @@ print(tools)
41
44
 
42
45
  For more granular control over the AgentR platform, you can use the lower-level components directly.
43
46
 
44
- ### AgentrClient
45
- The `AgentrClient` provides direct access to the AgentR REST API endpoints.
47
+ #### AgentrClient
48
+
49
+ The `AgentrClient` provides direct, one-to-one access to the AgentR REST API endpoints. The following examples have been updated to reflect the latest API structure.
46
50
 
47
- #### Methods
48
51
  ```python
49
52
  import os
50
53
  from universal_mcp.agentr import AgentrClient
@@ -55,39 +58,43 @@ client = AgentrClient(
55
58
  api_key=os.environ.get("AGENTR_API_KEY")
56
59
  )
57
60
 
58
- # Fetch all available applications from the AgentR server
59
- apps = client.fetch_apps()
60
- print(apps)
61
+ # Fetch a list of available applications from the AgentR server
62
+ apps = client.list_apps()
63
+ print("Available Apps:", apps)
61
64
 
62
- # Get credentials for a specific integration
63
- # This will raise a NotAuthorizedError if the user needs to authenticate
65
+ # Get credentials for a specific app by its ID (e.g., 'reddit')
66
+ # This will raise a NotAuthorizedError if the user needs to authenticate.
64
67
  try:
65
- credentials = client.get_credentials("reddit")
68
+ credentials = client.get_credentials(app_id="reddit")
66
69
  print("Reddit credentials found.")
67
70
  except NotAuthorizedError as e:
68
- print(e) # "Please ask the user to visit the following url to authorize..."
69
-
70
- # Example of fetching a single app and its actions
71
- if apps:
72
- app_id = apps[0].id # Assuming AppConfig has an 'id' attribute
71
+ print(e) # "Please ask the user to visit the following url to authorize..."
73
72
 
74
- # Fetch a single app's configuration
75
- app_config = client.fetch_app(app_id)
76
- print(f"Fetched config for app {app_id}:", app_config)
73
+ # List all available tools globally
74
+ all_tools = client.list_tools()
75
+ print("All Available Tools:", all_tools)
77
76
 
78
- # List all actions for that app
79
- actions = client.list_actions(app_id)
80
- print(f"Actions for app {app_id}:", actions)
81
-
82
- # List all apps (returns raw JSON data)
83
- all_apps = client.list_all_apps()
84
- print("All available apps:", all_apps)
77
+ # Example of fetching a single app and a single tool
78
+ if apps:
79
+ # Note: We access dictionary keys, not attributes
80
+ app_id = apps[0]['id']
81
+
82
+ # Fetch a single app's details
83
+ app_details = client.get_app(app_id)
84
+ print(f"Fetched details for app '{app_id}':", app_details)
85
+
86
+ if all_tools:
87
+ tool_id = all_tools[0]['id']
88
+
89
+ # Fetch a single tool's details
90
+ tool_details = client.get_tool(tool_id)
91
+ print(f"Fetched details for tool '{tool_id}':", tool_details)
85
92
  ```
86
93
 
87
- ### AgentrIntegration
94
+ #### AgentrIntegration
95
+
88
96
  This class handles the authentication and authorization flow for a single integration (e.g., "reddit"). It's used under the hood by applications to acquire credentials.
89
97
 
90
- #### Methods
91
98
  ```python
92
99
  from universal_mcp.agentr import AgentrIntegration, AgentrClient
93
100
  from universal_mcp.exceptions import NotAuthorizedError
@@ -114,10 +121,10 @@ except NotAuthorizedError:
114
121
  print("Still not authorized.")
115
122
  ```
116
123
 
117
- ### AgentrRegistry
124
+ #### AgentrRegistry
125
+
118
126
  The registry is responsible for discovering which tools are available on the AgentR platform.
119
127
 
120
- #### Methods
121
128
  ```python
122
129
  import asyncio
123
130
  from universal_mcp.agentr import AgentrRegistry, AgentrClient
@@ -148,7 +155,8 @@ if __name__ == "__main__":
148
155
  asyncio.run(main())
149
156
  ```
150
157
 
151
- ### AgentrServer
158
+ #### AgentrServer
159
+
152
160
  For server-side deployments, `AgentrServer` can be used to load all configured applications and their tools from an AgentR instance on startup.
153
161
 
154
162
  ```python
@@ -170,6 +178,7 @@ print(tool_manager.list_tools())
170
178
  ```
171
179
 
172
180
  ## Executing Tools
181
+
173
182
  Once tools are loaded, you can execute them using the `call_tool` method on the `ToolManager` instance, which is available via `agentr.manager`.
174
183
 
175
184
  ```python
@@ -182,7 +191,7 @@ async def main():
182
191
  agentr = Agentr(api_key=os.environ.get("AGENTR_API_KEY"))
183
192
 
184
193
  # 2. Load the tool(s) you want to use
185
- tool_name = "reddit_search_subreddits"
194
+ tool_name = "reddit__search_subreddits"
186
195
  agentr.load_tools([tool_name])
187
196
 
188
197
  # 3. Execute the tool using the tool manager
@@ -1,6 +1,5 @@
1
- from .agentr import Agentr
2
1
  from .client import AgentrClient
3
2
  from .integration import AgentrIntegration
4
3
  from .registry import AgentrRegistry
5
4
 
6
- __all__ = ["Agentr", "AgentrClient", "AgentrRegistry", "AgentrIntegration"]
5
+ __all__ = ["AgentrClient", "AgentrRegistry", "AgentrIntegration"]
@@ -1,9 +1,9 @@
1
1
  import os
2
+ from typing import Any
2
3
 
3
4
  import httpx
4
5
  from loguru import logger
5
6
 
6
- from universal_mcp.config import AppConfig
7
7
  from universal_mcp.exceptions import NotAuthorizedError
8
8
 
9
9
 
@@ -14,110 +14,196 @@ class AgentrClient:
14
14
  including authentication, authorization, and credential management.
15
15
 
16
16
  Args:
17
- api_key (str, optional): AgentR API key. If not provided, will look for AGENTR_API_KEY env var
18
- base_url (str, optional): Base URL for AgentR API. Defaults to https://api.agentr.dev
17
+ api_key (str, optional): AgentR API key. If not provided, will look for AGENTR_API_KEY env var.
18
+ base_url (str, optional): Base URL for AgentR API. Defaults to https://api.agentr.dev.
19
+ auth_token (str, optional): Auth token for AgentR API. If not provided, will look for AGENTR_AUTH_TOKEN env var.
19
20
  """
20
21
 
21
- def __init__(self, api_key: str | None = None, base_url: str | None = None):
22
+ def __init__(
23
+ self, api_key: str | None = None, base_url: str | None = None, auth_token: str | None = None, **kwargs
24
+ ):
22
25
  base_url = base_url or os.getenv("AGENTR_BASE_URL", "https://api.agentr.dev")
23
- self.base_url = base_url.rstrip("/")
24
- self.api_key = api_key or os.getenv("AGENTR_API_KEY")
25
- if not self.api_key:
26
- raise ValueError("No API key provided and AGENTR_API_KEY not found in environment variables")
27
- self.client = httpx.Client(
28
- base_url=self.base_url, headers={"X-API-KEY": self.api_key}, timeout=30, follow_redirects=True
29
- )
26
+ self.base_url = f"{base_url.rstrip('/')}/v1"
27
+ api_key = api_key or os.getenv("AGENTR_API_KEY")
28
+ if api_key:
29
+ self.client = httpx.Client(
30
+ base_url=self.base_url,
31
+ headers={"X-API-KEY": api_key, "accept": "application/json"},
32
+ timeout=30,
33
+ follow_redirects=True,
34
+ verify=False,
35
+ )
36
+ me_data = self.me()
37
+ logger.debug(f"Client initialized with user: {me_data['email']}")
38
+ elif auth_token:
39
+ logger.debug("Initializing client with auth token")
40
+ self.client = httpx.Client(
41
+ base_url=self.base_url,
42
+ headers={"Authorization": f"Bearer {auth_token}", "accept": "application/json"},
43
+ timeout=30,
44
+ follow_redirects=True,
45
+ verify=False,
46
+ )
47
+ me_data = self.me()
48
+ logger.debug(f"Client initialized with user: {me_data['email']}")
49
+ else:
50
+ raise ValueError("No API key or auth token provided")
51
+
52
+ def me(self):
53
+ response = self.client.get("/users/me")
54
+ logger.debug(f"Me response: {response.status_code}")
55
+ response.raise_for_status()
56
+ data = response.json()
57
+ return data
30
58
 
31
- def get_credentials(self, integration_name: str) -> dict:
59
+ def get_credentials(self, app_id: str) -> dict[str, Any]:
32
60
  """Get credentials for an integration from the AgentR API.
33
61
 
34
62
  Args:
35
- integration_name (str): Name of the integration to get credentials for
63
+ app_id (str): The ID of the app (e.g., 'asana', 'google-drive').
36
64
 
37
65
  Returns:
38
- dict: Credentials data from API response
66
+ dict: Credentials data from API response.
39
67
 
40
68
  Raises:
41
- NotAuthorizedError: If credentials are not found (404 response)
42
- HTTPError: For other API errors
69
+ NotAuthorizedError: If credentials are not found (404 response).
70
+ HTTPError: For other API errors.
43
71
  """
44
72
  response = self.client.get(
45
- f"/api/{integration_name}/credentials/",
73
+ "/credentials",
74
+ params={"app_id": app_id},
46
75
  )
76
+ logger.debug(f"Credentials response: {response.status_code}")
47
77
  if response.status_code == 404:
48
- logger.warning(f"No credentials found for {integration_name}. Requesting authorization...")
49
- action = self.get_authorization_url(integration_name)
50
- raise NotAuthorizedError(action)
78
+ logger.warning(f"No credentials found for app '{app_id}'. Requesting authorization...")
79
+ action_url = self.get_authorization_url(app_id)
80
+ raise NotAuthorizedError(action_url)
51
81
  response.raise_for_status()
52
82
  return response.json()
53
83
 
54
- def get_authorization_url(self, integration_name: str) -> str:
55
- """Get authorization URL for an integration.
84
+ def get_authorization_url(self, app_id: str) -> str:
85
+ """Get the authorization URL to connect an app.
56
86
 
57
87
  Args:
58
- integration_name (str): Name of the integration to get authorization URL for
88
+ app_id (str): The ID of the app to authorize.
59
89
 
60
90
  Returns:
61
- str: Message containing authorization URL
91
+ str: A message containing the authorization URL.
62
92
 
63
93
  Raises:
64
- HTTPError: If API request fails
94
+ HTTPError: If the API request fails.
65
95
  """
66
- response = self.client.get(f"/api/{integration_name}/authorize/")
96
+ response = self.client.post("/connections/authorize", json={"app_id": app_id})
67
97
  response.raise_for_status()
68
- url = response.json()
98
+ url = response.json().get("authorize_url")
69
99
  return f"Please ask the user to visit the following url to authorize the application: {url}. Render the url in proper markdown format with a clickable link."
70
100
 
71
- def fetch_apps(self) -> list[AppConfig]:
101
+ def list_all_apps(self):
72
102
  """Fetch available apps from AgentR API.
73
103
 
74
104
  Returns:
75
- List of application configurations
105
+ List[Dict[str, Any]]: A list of application data dictionaries.
76
106
 
77
107
  Raises:
78
- httpx.HTTPError: If API request fails
108
+ httpx.HTTPError: If the API request fails.
79
109
  """
80
- response = self.client.get("/api/apps/")
110
+ response = self.client.get("/apps/")
81
111
  response.raise_for_status()
82
- data = response.json()
83
- return [AppConfig.model_validate(app) for app in data]
112
+ return response.json().get("items", [])
113
+
114
+ def list_my_apps(self):
115
+ """Fetch user apps from AgentR API.
116
+
117
+ Returns:
118
+ List[Dict[str, Any]]: A list of user app data dictionaries.
119
+ """
120
+ response = self.client.get("/apps/me")
121
+ response.raise_for_status()
122
+ return response.json().get("items", [])
123
+
124
+ def list_my_connections(self):
125
+ """Fetch user connections from AgentR API.
126
+
127
+ Returns:
128
+ List[Dict[str, Any]]: A list of user connection data dictionaries.
129
+ """
130
+ response = self.client.get("/connections")
131
+ response.raise_for_status()
132
+ return response.json().get("items", [])
84
133
 
85
- def fetch_app(self, app_id: str) -> dict:
134
+ def get_app_details(self, app_id: str):
86
135
  """Fetch a specific app from AgentR API.
87
136
 
88
137
  Args:
89
- app_id (str): ID of the app to fetch
138
+ app_id (str): ID of the app to fetch.
90
139
 
91
140
  Returns:
92
- dict: App configuration data
141
+ dict: App configuration data.
93
142
 
94
143
  Raises:
95
- httpx.HTTPError: If API request fails
144
+ httpx.HTTPError: If the API request fails.
96
145
  """
97
- response = self.client.get(f"/apps/{app_id}/")
146
+ response = self.client.get(f"/apps/{app_id}")
98
147
  response.raise_for_status()
99
148
  return response.json()
100
149
 
101
- def list_all_apps(self) -> list:
102
- """List all apps from AgentR API.
150
+ def list_all_tools(self, app_id: str | None = None):
151
+ """List all available tools from the AgentR API.
152
+
153
+ Note: In the backend, tools are globally listed and not tied to a
154
+ specific app at this endpoint.
103
155
 
104
156
  Returns:
105
- List of app names
157
+ List[Dict[str, Any]]: A list of tool configurations.
106
158
  """
107
- response = self.client.get("/apps/")
159
+ params = {}
160
+ if app_id:
161
+ params["app_id"] = app_id
162
+ response = self.client.get("/tools", params=params)
163
+ response.raise_for_status()
164
+ return response.json().get("items", [])
165
+
166
+ def get_tool_details(self, tool_id: str):
167
+ """Fetch a specific tool configuration from the AgentR API.
168
+
169
+ Args:
170
+ tool_id (str): ID of the tool to fetch.
171
+
172
+ Returns:
173
+ dict: Tool configuration data.
174
+
175
+ Raises:
176
+ httpx.HTTPError: If the API request fails.
177
+ """
178
+ response = self.client.get(f"/tools/{tool_id}")
108
179
  response.raise_for_status()
109
180
  return response.json()
110
181
 
111
- def list_actions(self, app_id: str):
112
- """List actions for an app.
182
+ def search_all_apps(self, query: str, limit: int = 2):
183
+ """Search for apps from the AgentR API.
113
184
 
114
185
  Args:
115
- app_id (str): ID of the app to list actions for
186
+ query (str): The query to search for.
187
+ limit (int, optional): The number of apps to return. Defaults to 2.
116
188
 
117
189
  Returns:
118
- List of action configurations
190
+ List[Dict[str, Any]]: A list of app data dictionaries.
119
191
  """
192
+ response = self.client.get("/apps", params={"search": query, "limit": limit})
193
+ response.raise_for_status()
194
+ return response.json().get("items", [])
195
+
196
+ def search_all_tools(self, query: str, limit: int = 2, app_id: str | None = None):
197
+ """Search for tools from the AgentR API.
120
198
 
121
- response = self.client.get(f"/apps/{app_id}/actions/")
199
+ Args:
200
+ query (str): The query to search for.
201
+ limit (int, optional): The number of tools to return. Defaults to 2.
202
+ app_id (str, optional): The ID of the app to search tools for.
203
+ """
204
+ params = {"search": query, "limit": limit}
205
+ if app_id:
206
+ params["app_id"] = app_id
207
+ response = self.client.get("/tools", params=params)
122
208
  response.raise_for_status()
123
- return response.json()
209
+ return response.json().get("items", [])
@@ -1,9 +1,12 @@
1
+ from typing import Any
2
+
1
3
  from loguru import logger
2
4
 
3
5
  from universal_mcp.agentr.client import AgentrClient
4
6
  from universal_mcp.applications import app_from_slug
5
7
  from universal_mcp.tools.manager import ToolManager, _get_app_and_tool_name
6
8
  from universal_mcp.tools.registry import ToolRegistry
9
+ from universal_mcp.types import ToolConfig, ToolFormat
7
10
 
8
11
  from .integration import AgentrIntegration
9
12
 
@@ -15,28 +18,25 @@ class AgentrRegistry(ToolRegistry):
15
18
  """Initialize the AgentR platform manager."""
16
19
 
17
20
  self.client = client or AgentrClient(**kwargs)
21
+ self.tool_manager = ToolManager()
18
22
  logger.debug("AgentrRegistry initialized successfully")
19
23
 
20
- async def list_apps(self) -> list[dict[str, str]]:
24
+ async def list_all_apps(self) -> list[dict[str, Any]]:
21
25
  """Get list of available apps from AgentR.
22
26
 
23
27
  Returns:
24
28
  List of app dictionaries with id, name, description, and available fields
25
29
  """
30
+ if self.client is None:
31
+ raise ValueError("Client is not initialized")
26
32
  try:
27
- all_apps = await self.client.list_all_apps()
28
- available_apps = [
29
- {"id": app["id"], "name": app["name"], "description": app.get("description", "")}
30
- for app in all_apps
31
- if app.get("available", False)
32
- ]
33
- logger.info(f"Found {len(available_apps)} available apps from AgentR")
34
- return available_apps
33
+ all_apps = self.client.list_all_apps()
34
+ return all_apps
35
35
  except Exception as e:
36
36
  logger.error(f"Error fetching apps from AgentR: {e}")
37
37
  return []
38
38
 
39
- async def get_app_details(self, app_id: str) -> dict[str, str]:
39
+ async def get_app_details(self, app_id: str) -> dict[str, Any]:
40
40
  """Get detailed information about a specific app from AgentR.
41
41
 
42
42
  Args:
@@ -46,46 +46,137 @@ class AgentrRegistry(ToolRegistry):
46
46
  Dictionary containing app details
47
47
  """
48
48
  try:
49
- app_info = await self.client.fetch_app(app_id)
50
- return {
51
- "id": app_info.get("id"),
52
- "name": app_info.get("name"),
53
- "description": app_info.get("description"),
54
- "category": app_info.get("category"),
55
- "available": app_info.get("available", True),
56
- }
49
+ app_info = self.client.get_app_details(app_id)
50
+ return app_info
57
51
  except Exception as e:
58
52
  logger.error(f"Error getting details for app {app_id}: {e}")
59
- return {
60
- "id": app_id,
61
- "name": app_id,
62
- "description": "Error loading details",
63
- "category": "Unknown",
64
- "available": True,
65
- }
66
-
67
- def load_tools(self, tools: list[str] | None, tool_manager: ToolManager) -> None:
53
+ return {}
54
+
55
+ async def search_apps(
56
+ self,
57
+ query: str,
58
+ limit: int = 10,
59
+ ) -> list[dict[str, Any]]:
60
+ """Search for apps by a query.
61
+
62
+ Args:
63
+ query: The query to search for
64
+ limit: The number of apps to return
65
+
66
+ Returns:
67
+ List of app dictionaries matching the query
68
+ """
69
+ try:
70
+ apps = self.client.search_all_apps(query, limit)
71
+ return apps
72
+ except Exception as e:
73
+ logger.error(f"Error searching apps from AgentR: {e}")
74
+ return []
75
+
76
+ async def list_tools(
77
+ self,
78
+ app_id: str,
79
+ ) -> list[dict[str, Any]]:
80
+ """List all tools available on the platform, filter by app_id.
81
+
82
+ Args:
83
+ app_id: The ID of the app to list tools for
84
+
85
+ Returns:
86
+ List of tool dictionaries for the specified app
87
+ """
88
+ try:
89
+ all_tools = self.client.list_all_tools(app_id=app_id)
90
+ return all_tools
91
+ except Exception as e:
92
+ logger.error(f"Error listing tools for app {app_id}: {e}")
93
+ return []
94
+
95
+ async def search_tools(
96
+ self,
97
+ query: str,
98
+ limit: int = 2,
99
+ app_id: str | None = None,
100
+ ) -> list[dict[str, Any]]:
101
+ """Search for tools by a query.
102
+
103
+ Args:
104
+ query: The query to search for
105
+ limit: The number of tools to return
106
+ app_id: The ID of the app to list tools for
107
+ Returns:
108
+ List of tool dictionaries matching the query
109
+ """
110
+ try:
111
+ tools = self.client.search_all_tools(query, limit, app_id)
112
+ return tools
113
+ except Exception as e:
114
+ logger.error(f"Error searching tools from AgentR: {e}")
115
+ return []
116
+
117
+ async def export_tools(
118
+ self,
119
+ tools: list[str] | ToolConfig,
120
+ format: ToolFormat,
121
+ ) -> str:
122
+ """Export given tools to required format.
123
+
124
+ Args:
125
+ tools: List of tool identifiers to export
126
+ format: The format to export tools to (native, mcp, langchain, openai)
127
+
128
+ Returns:
129
+ String representation of tools in the specified format
130
+ """
131
+ try:
132
+ # Clear tools from tool manager before loading new tools
133
+ self.tool_manager.clear_tools()
134
+ if isinstance(tools, ToolConfig):
135
+ print("Loading tools from tool config")
136
+ self._load_tools_from_tool_config(tools, self.tool_manager)
137
+ else:
138
+ print("Loading tools from list")
139
+ self._load_agentr_tools_from_list(tools, self.tool_manager)
140
+ loaded_tools = self.tool_manager.list_tools(format=format)
141
+ logger.info(f"Exporting {len(loaded_tools)} tools to {format} format")
142
+ return loaded_tools
143
+ except Exception as e:
144
+ logger.error(f"Error exporting tools: {e}")
145
+ return ""
146
+
147
+ def _load_tools(self, app_name: str, tool_names: list[str], tool_manager: ToolManager) -> None:
148
+ """Helper method to load and register tools for an app."""
149
+ app = app_from_slug(app_name)
150
+ integration = AgentrIntegration(name=app_name, client=self.client)
151
+ app_instance = app(integration=integration)
152
+ tool_manager.register_tools_from_app(app_instance, tool_names=tool_names)
153
+
154
+ def _load_agentr_tools_from_list(self, tools: list[str], tool_manager: ToolManager) -> None:
68
155
  """Load tools from AgentR and register them as tools.
69
156
 
70
157
  Args:
71
- tools: The list of tools to load ( prefixed with app name )
158
+ tools: The list of tools to load (prefixed with app name)
72
159
  tool_manager: The tool manager to register tools with
73
160
  """
74
- if not tools:
75
- return
76
- logger.info(f"Loading all actions for app: {tools}")
77
- # Group all tools by app_name, tools
161
+ logger.info(f"Loading all tools: {tools}")
78
162
  tools_by_app = {}
79
163
  for tool_name in tools:
80
164
  app_name, _ = _get_app_and_tool_name(tool_name)
81
- if app_name not in tools_by_app:
82
- tools_by_app[app_name] = []
83
- tools_by_app[app_name].append(tool_name)
165
+ tools_by_app.setdefault(app_name, []).append(tool_name)
84
166
 
85
167
  for app_name, tool_names in tools_by_app.items():
86
- app = app_from_slug(app_name)
87
- integration = AgentrIntegration(name=app_name)
88
- # TODO: Import with name param, some apps are written incorrectly and hence passing name fails
89
- app_instance = app(integration=integration)
90
- tool_manager.register_tools_from_app(app_instance, tool_names=tool_names)
91
- return
168
+ self._load_tools(app_name, tool_names, tool_manager)
169
+
170
+ def _load_tools_from_tool_config(self, tool_config: ToolConfig, tool_manager: ToolManager) -> None:
171
+ """Load tools from ToolConfig and register them as tools.
172
+
173
+ Args:
174
+ tool_config: The tool configuration containing app names and tools
175
+ tool_manager: The tool manager to register tools with
176
+ """
177
+ for app_name, tool_data in tool_config.agentrServers.items():
178
+ self._load_tools(app_name, tool_data.tools, tool_manager)
179
+
180
+ async def call_tool(self, tool_name: str, tool_args: dict[str, Any]) -> dict[str, Any]:
181
+ """Call a tool with the given name and arguments."""
182
+ return await self.tool_manager.call_tool(tool_name, tool_args)
@@ -1,6 +1,6 @@
1
- from .auto import AutoAgent
2
- from .base import BaseAgent
3
- from .react import ReactAgent
4
- from .simple import SimpleAgent
1
+ from universal_mcp.agents.autoagent import AutoAgent
2
+ from universal_mcp.agents.base import BaseAgent
3
+ from universal_mcp.agents.react import ReactAgent
4
+ from universal_mcp.agents.simple import SimpleAgent
5
5
 
6
6
  __all__ = ["BaseAgent", "ReactAgent", "SimpleAgent", "AutoAgent"]