universal-mcp 0.1.24rc22__tar.gz → 0.1.24rc23__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 (64) hide show
  1. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/PKG-INFO +1 -1
  2. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/pyproject.toml +1 -1
  3. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/agentr/README.md +30 -34
  4. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/agentr/client.py +6 -4
  5. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/agentr/registry.py +6 -2
  6. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/applications/application.py +4 -1
  7. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/tools/registry.py +4 -2
  8. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/.gitignore +0 -0
  9. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/LICENSE +0 -0
  10. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/README.md +0 -0
  11. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/tests/__init__.py +0 -0
  12. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/tests/conftest.py +0 -0
  13. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/tests/test_api_generator.py +0 -0
  14. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/tests/test_apps.py +0 -0
  15. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/tests/test_local_registry.py +0 -0
  16. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/tests/test_localserver.py +0 -0
  17. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/tests/test_stores.py +0 -0
  18. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/tests/test_tool.py +0 -0
  19. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/tests/test_tool_manager.py +0 -0
  20. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/agentr/__init__.py +0 -0
  21. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/agentr/integration.py +0 -0
  22. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/agentr/server.py +0 -0
  23. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/applications/sample/app.py +0 -0
  24. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/applications/utils.py +0 -0
  25. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/cli.py +0 -0
  26. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/client/oauth.py +0 -0
  27. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/client/token_store.py +0 -0
  28. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/client/transport.py +0 -0
  29. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/config.py +0 -0
  30. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/exceptions.py +0 -0
  31. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/integrations/__init__.py +0 -0
  32. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/integrations/integration.py +0 -0
  33. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/logger.py +0 -0
  34. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/py.typed +0 -0
  35. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/servers/__init__.py +0 -0
  36. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/servers/server.py +0 -0
  37. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/stores/__init__.py +0 -0
  38. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/stores/store.py +0 -0
  39. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/tools/__init__.py +0 -0
  40. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/tools/adapters.py +0 -0
  41. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/tools/docstring_parser.py +0 -0
  42. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/tools/func_metadata.py +0 -0
  43. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/tools/local_registry.py +0 -0
  44. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/tools/manager.py +0 -0
  45. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/tools/tools.py +0 -0
  46. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/types.py +0 -0
  47. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/__init__.py +0 -0
  48. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/installation.py +0 -0
  49. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/__inti__.py +0 -0
  50. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/api_generator.py +0 -0
  51. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/api_splitter.py +0 -0
  52. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/cli.py +0 -0
  53. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/docgen.py +0 -0
  54. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/filters.py +0 -0
  55. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/openapi.py +0 -0
  56. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/postprocessor.py +0 -0
  57. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/preprocessor.py +0 -0
  58. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/readme.py +0 -0
  59. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/openapi/test_generator.py +0 -0
  60. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/prompts.py +0 -0
  61. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/singleton.py +0 -0
  62. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/templates/README.md.j2 +0 -0
  63. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/templates/api_client.py.j2 +0 -0
  64. {universal_mcp-0.1.24rc22 → universal_mcp-0.1.24rc23}/src/universal_mcp/utils/testing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: universal-mcp
3
- Version: 0.1.24rc22
3
+ Version: 0.1.24rc23
4
4
  Summary: Universal MCP acts as a middle ware for your API applications. It can store your credentials, authorize, enable disable apps on the fly and much more.
5
5
  Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "universal-mcp"
7
- version = "0.1.24-rc22"
7
+ version = "0.1.24-rc23"
8
8
  description = "Universal MCP acts as a middle ware for your API applications. It can store your credentials, authorize, enable disable apps on the fly and much more."
9
9
  readme = "README.md"
10
10
  authors = [
@@ -14,29 +14,30 @@ pip install universal-mcp
14
14
 
15
15
  ## Usage
16
16
 
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.
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 `AgentrRegistry` class, which provides a high-level interface for loading and listing tools.
18
18
 
19
- ### High-Level Client (`Agentr`)
19
+ ### High-Level Client (`AgentrRegistry`)
20
20
 
21
- This is the recommended way to get started. It abstracts away the details of the registry and tool management.
21
+ This is the recommended way to get started. It abstracts away the details of the tool management.
22
22
 
23
23
  ```python
24
24
  import os
25
- from universal_mcp.agentr import Agentr
25
+ from universal_mcp.agentr import AgentrRegistry
26
26
  from universal_mcp.tools import ToolFormat
27
27
 
28
28
  # Initialize the main client
29
29
  # It reads from environment variables by default (AGENTR_API_KEY, AGENTR_BASE_URL)
30
- agentr = Agentr(
30
+ registry = AgentrRegistry(
31
31
  api_key=os.environ.get("AGENTR_API_KEY")
32
32
  )
33
33
 
34
34
  # Load specific tools from the AgentR server into the tool manager
35
- agentr.load_tools(["reddit__search_subreddits", "google-drive__list_files"])
36
-
37
- # List the tools that are now loaded and ready to be used
38
- # You can specify a format compatible with your LLM (e.g., OPENAI)
39
- tools = agentr.list_tools(format=ToolFormat.OPENAI)
35
+ # The export_tools method loads the tools and then exports them to the specified format.
36
+ tools_config = {
37
+ "reddit": ["search_subreddits"],
38
+ "google-drive": ["list_files"]
39
+ }
40
+ tools = await registry.export_tools(tools_config, format=ToolFormat.OPENAI)
40
41
  print(tools)
41
42
  ```
42
43
 
@@ -59,7 +60,7 @@ client = AgentrClient(
59
60
  )
60
61
 
61
62
  # Fetch a list of available applications from the AgentR server
62
- apps = client.list_apps()
63
+ apps = client.list_all_apps()
63
64
  print("Available Apps:", apps)
64
65
 
65
66
  # Get credentials for a specific app by its ID (e.g., 'reddit')
@@ -71,7 +72,7 @@ except NotAuthorizedError as e:
71
72
  print(e) # "Please ask the user to visit the following url to authorize..."
72
73
 
73
74
  # List all available tools globally
74
- all_tools = client.list_tools()
75
+ all_tools = client.list_all_tools()
75
76
  print("All Available Tools:", all_tools)
76
77
 
77
78
  # Example of fetching a single app and a single tool
@@ -80,14 +81,14 @@ if apps:
80
81
  app_id = apps[0]['id']
81
82
 
82
83
  # Fetch a single app's details
83
- app_details = client.get_app(app_id)
84
+ app_details = client.get_app_details(app_id)
84
85
  print(f"Fetched details for app '{app_id}':", app_details)
85
86
 
86
87
  if all_tools:
87
88
  tool_id = all_tools[0]['id']
88
89
 
89
90
  # Fetch a single tool's details
90
- tool_details = client.get_tool(tool_id)
91
+ tool_details = client.get_tool_details(tool_id)
91
92
  print(f"Fetched details for tool '{tool_id}':", tool_details)
92
93
  ```
93
94
 
@@ -134,7 +135,7 @@ registry = AgentrRegistry(client=client)
134
135
 
135
136
  async def main():
136
137
  # List all apps available on the AgentR platform
137
- available_apps = await registry.list_apps()
138
+ available_apps = await registry.list_all_apps()
138
139
  print(available_apps)
139
140
 
140
141
  if available_apps:
@@ -143,14 +144,6 @@ async def main():
143
144
  app_details = await registry.get_app_details(app_id)
144
145
  print(f"Details for {app_id}:", app_details)
145
146
 
146
- # The load_tools method is used internally by the high-level Agentr client
147
- # but can be called directly if needed.
148
- # from universal_mcp.tools import ToolManager
149
- # tool_manager = ToolManager()
150
- # registry.load_tools(["reddit_search_subreddits"], tool_manager)
151
- # print(tool_manager.list_tools())
152
-
153
-
154
147
  if __name__ == "__main__":
155
148
  asyncio.run(main())
156
149
  ```
@@ -179,27 +172,30 @@ print(tool_manager.list_tools())
179
172
 
180
173
  ## Executing Tools
181
174
 
182
- Once tools are loaded, you can execute them using the `call_tool` method on the `ToolManager` instance, which is available via `agentr.manager`.
175
+ Once tools are loaded, you can execute them using the `call_tool` method on the `AgentrRegistry` instance.
183
176
 
184
177
  ```python
185
178
  import os
186
179
  import asyncio
187
- from universal_mcp.agentr import Agentr
180
+ from universal_mcp.agentr import AgentrRegistry
181
+ from universal_mcp.tools import ToolFormat
188
182
 
189
183
  async def main():
190
- # 1. Initialize Agentr
191
- agentr = Agentr(api_key=os.environ.get("AGENTR_API_KEY"))
184
+ # 1. Initialize AgentrRegistry
185
+ registry = AgentrRegistry(api_key=os.environ.get("AGENTR_API_KEY"))
192
186
 
193
- # 2. Load the tool(s) you want to use
187
+ # 2. Load the tool(s) you want to use by exporting them
194
188
  tool_name = "reddit__search_subreddits"
195
- agentr.load_tools([tool_name])
189
+ tools_config = {"reddit": ["search_subreddits"]}
190
+ await registry.export_tools(tools_config, format=ToolFormat.OPENAI)
191
+
196
192
 
197
- # 3. Execute the tool using the tool manager
193
+ # 3. Execute the tool using the registry's call_tool method
198
194
  try:
199
195
  # Note the 'await' since call_tool is an async method
200
- result = await agentr.manager.call_tool(
201
- name=tool_name,
202
- arguments={"query": "elon musk", "limit": 5, "sort": "relevance"}
196
+ result = await registry.call_tool(
197
+ tool_name=tool_name,
198
+ tool_args={"query": "elon musk", "limit": 5, "sort": "relevance"}
203
199
  )
204
200
  print("Execution result:", result)
205
201
  except Exception as e:
@@ -207,4 +203,4 @@ async def main():
207
203
 
208
204
  if __name__ == "__main__":
209
205
  asyncio.run(main())
210
- ```
206
+ ```
@@ -183,7 +183,7 @@ class AgentrClient:
183
183
  response.raise_for_status()
184
184
  return response.json()
185
185
 
186
- def search_all_apps(self, query: str, limit: int = 2):
186
+ def search_all_apps(self, query: str, limit: int = 2, distance_threshold: float = 0.6):
187
187
  """Search for apps from the AgentR API.
188
188
 
189
189
  Args:
@@ -193,11 +193,13 @@ class AgentrClient:
193
193
  Returns:
194
194
  List[Dict[str, Any]]: A list of app data dictionaries.
195
195
  """
196
- response = self.client.get("/apps/", params={"search": query, "limit": limit})
196
+ response = self.client.get(
197
+ "/apps/", params={"search": query, "limit": limit, "distance_threshold": distance_threshold}
198
+ )
197
199
  response.raise_for_status()
198
200
  return response.json().get("items", [])
199
201
 
200
- def search_all_tools(self, query: str, limit: int = 2, app_id: str | None = None):
202
+ def search_all_tools(self, query: str, limit: int = 2, app_id: str | None = None, distance_threshold: float = 0.6):
201
203
  """Search for tools from the AgentR API.
202
204
 
203
205
  Args:
@@ -205,7 +207,7 @@ class AgentrClient:
205
207
  limit (int, optional): The number of tools to return. Defaults to 2.
206
208
  app_id (str, optional): The ID of the app to search tools for.
207
209
  """
208
- params = {"search": query, "limit": limit}
210
+ params = {"search": query, "limit": limit, "distance_threshold": distance_threshold}
209
211
  if app_id:
210
212
  params["app_id"] = app_id
211
213
  response = self.client.get("/tools/", params=params)
@@ -82,6 +82,7 @@ class AgentrRegistry(ToolRegistry):
82
82
  self,
83
83
  query: str,
84
84
  limit: int = 10,
85
+ distance_threshold: float = 0.6,
85
86
  ) -> list[dict[str, Any]]:
86
87
  """Search for apps by a query.
87
88
 
@@ -93,7 +94,7 @@ class AgentrRegistry(ToolRegistry):
93
94
  List of app dictionaries matching the query
94
95
  """
95
96
  try:
96
- apps = self.client.search_all_apps(query=query, limit=limit)
97
+ apps = self.client.search_all_apps(query=query, limit=limit, distance_threshold=distance_threshold)
97
98
  return apps
98
99
  except Exception as e:
99
100
  logger.error(f"Error searching apps from AgentR: {e}")
@@ -123,6 +124,7 @@ class AgentrRegistry(ToolRegistry):
123
124
  query: str,
124
125
  limit: int = 2,
125
126
  app_id: str | None = None,
127
+ distance_threshold: float = 0.6,
126
128
  ) -> list[dict[str, Any]]:
127
129
  """Search for tools by a query.
128
130
 
@@ -134,7 +136,9 @@ class AgentrRegistry(ToolRegistry):
134
136
  List of tool dictionaries matching the query
135
137
  """
136
138
  try:
137
- tools = self.client.search_all_tools(query=query, limit=limit, app_id=app_id)
139
+ tools = self.client.search_all_tools(
140
+ query=query, limit=limit, app_id=app_id, distance_threshold=distance_threshold
141
+ )
138
142
  return tools
139
143
  except Exception as e:
140
144
  logger.error(f"Error searching tools from AgentR: {e}")
@@ -11,6 +11,8 @@ from loguru import logger
11
11
 
12
12
  from universal_mcp.integrations.integration import Integration
13
13
 
14
+ DEFAULT_API_TIMEOUT = 30 # seconds
15
+
14
16
 
15
17
  class BaseApplication(ABC):
16
18
  """Defines the foundational structure for applications in Universal MCP.
@@ -90,7 +92,7 @@ class APIApplication(BaseApplication):
90
92
  BaseApplication.
91
93
  """
92
94
  super().__init__(name, **kwargs)
93
- self.default_timeout: int = 180
95
+ self.default_timeout: int = DEFAULT_API_TIMEOUT
94
96
  self.integration = integration
95
97
  logger.debug(f"Initializing APIApplication '{name}' with integration: {integration}")
96
98
  self._client: httpx.Client | None = client
@@ -452,6 +454,7 @@ class GraphQLApplication(BaseApplication):
452
454
  super().__init__(name, **kwargs)
453
455
  self.base_url = base_url
454
456
  self.integration = integration
457
+ self.default_timeout: float = DEFAULT_API_TIMEOUT
455
458
  logger.debug(f"Initializing Application '{name}' with kwargs: {kwargs}")
456
459
  self._client: GraphQLClient | None = client
457
460
 
@@ -32,7 +32,7 @@ class ToolRegistry(ABC):
32
32
  pass
33
33
 
34
34
  @abstractmethod
35
- async def search_apps(self, query: str, limit: int = 2) -> list[dict[str, Any]]:
35
+ async def search_apps(self, query: str, limit: int = 2, distance_threshold: float = 0.6) -> list[dict[str, Any]]:
36
36
  """Search for apps by a query."""
37
37
  pass
38
38
 
@@ -42,7 +42,9 @@ class ToolRegistry(ABC):
42
42
  pass
43
43
 
44
44
  @abstractmethod
45
- async def search_tools(self, query: str, limit: int = 2, app_id: str | None = None) -> list[dict[str, Any]]:
45
+ async def search_tools(
46
+ self, query: str, limit: int = 2, app_id: str | None = None, distance_threshold: float = 0.6
47
+ ) -> list[dict[str, Any]]:
46
48
  """Search for tools by a query, optionally filtered by an app."""
47
49
  pass
48
50