universal-mcp 0.1.18rc3__py3-none-any.whl → 0.1.19__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.
universal_mcp/config.py CHANGED
@@ -38,7 +38,6 @@ class ServerConfig(BaseSettings):
38
38
  """Main server configuration."""
39
39
 
40
40
  model_config = SettingsConfigDict(
41
- env_prefix="MCP_",
42
41
  env_file=".env",
43
42
  env_file_encoding="utf-8",
44
43
  case_sensitive=True,
@@ -47,19 +46,17 @@ class ServerConfig(BaseSettings):
47
46
 
48
47
  name: str = Field(default="Universal MCP", description="Name of the MCP server")
49
48
  description: str = Field(default="Universal MCP", description="Description of the MCP server")
50
- api_key: SecretStr | None = Field(default=None, description="API key for authentication")
49
+ api_key: SecretStr | None = Field(default=None, description="API key for authentication", alias="AGENTR_API_KEY")
51
50
  type: Literal["local", "agentr"] = Field(default="agentr", description="Type of server deployment")
52
51
  transport: Literal["stdio", "sse", "streamable-http"] = Field(
53
52
  default="stdio", description="Transport protocol to use"
54
53
  )
55
- port: int = Field(default=8005, description="Port to run the server on (if applicable)")
54
+ port: int = Field(default=8005, description="Port to run the server on (if applicable)", ge=1024, le=65535)
56
55
  host: str = Field(default="localhost", description="Host to bind the server to (if applicable)")
57
56
  apps: list[AppConfig] | None = Field(default=None, description="List of configured applications")
58
57
  store: StoreConfig | None = Field(default=None, description="Default store configuration")
59
58
  debug: bool = Field(default=False, description="Enable debug mode")
60
59
  log_level: str = Field(default="INFO", description="Logging level")
61
- max_connections: int = Field(default=100, description="Maximum number of concurrent connections")
62
- request_timeout: int = Field(default=60, description="Default request timeout in seconds")
63
60
 
64
61
  @field_validator("log_level", mode="before")
65
62
  def validate_log_level(cls, v: str) -> str:
@@ -19,3 +19,7 @@ class StoreError(Exception):
19
19
 
20
20
  class KeyNotFoundError(StoreError):
21
21
  """Exception raised when a key is not found in the store."""
22
+
23
+
24
+ class ConfigurationError(Exception):
25
+ """Exception raised when a configuration error occurs."""
@@ -1,4 +1,3 @@
1
- from abc import ABC, abstractmethod
2
1
  from collections.abc import Callable
3
2
  from typing import Any
4
3
 
@@ -6,16 +5,18 @@ import httpx
6
5
  from loguru import logger
7
6
  from mcp.server.fastmcp import FastMCP
8
7
  from mcp.types import TextContent
8
+ from pydantic import ValidationError
9
9
 
10
10
  from universal_mcp.applications import BaseApplication, app_from_slug
11
11
  from universal_mcp.config import AppConfig, ServerConfig, StoreConfig
12
+ from universal_mcp.exceptions import ConfigurationError, ToolError
12
13
  from universal_mcp.integrations import AgentRIntegration, integration_from_config
13
14
  from universal_mcp.stores import BaseStore, store_from_config
14
15
  from universal_mcp.tools import ToolManager
15
16
  from universal_mcp.utils.agentr import AgentrClient
16
17
 
17
18
 
18
- class BaseServer(FastMCP, ABC):
19
+ class BaseServer(FastMCP):
19
20
  """Base server class with common functionality.
20
21
 
21
22
  This class provides core server functionality including store setup,
@@ -26,24 +27,27 @@ class BaseServer(FastMCP, ABC):
26
27
  **kwargs: Additional keyword arguments passed to FastMCP
27
28
  """
28
29
 
29
- def __init__(self, config: ServerConfig, **kwargs):
30
- super().__init__(config.name, config.description, port=config.port, **kwargs)
31
- logger.info(f"Initializing server: {config.name} ({config.type}) with store: {config.store}")
32
-
33
- self.config = config # Store config at base level for consistency
34
- self._tool_manager = ToolManager(warn_on_duplicate_tools=True)
35
-
36
- @abstractmethod
37
- def _load_apps(self) -> None:
38
- """Load and register applications."""
39
- pass
30
+ def __init__(self, config: ServerConfig, tool_manager: ToolManager | None = None, **kwargs):
31
+ try:
32
+ super().__init__(config.name, config.description, port=config.port, **kwargs)
33
+ logger.info(f"Initializing server: {config.name} ({config.type}) with store: {config.store}")
34
+ self.config = config
35
+ self._tool_manager = tool_manager or ToolManager(warn_on_duplicate_tools=True)
36
+ ServerConfig.model_validate(config)
37
+ except Exception as e:
38
+ logger.error(f"Failed to initialize server: {e}", exc_info=True)
39
+ raise ConfigurationError(f"Server initialization failed: {str(e)}") from e
40
40
 
41
41
  def add_tool(self, tool: Callable) -> None:
42
42
  """Add a tool to the server.
43
43
 
44
44
  Args:
45
45
  tool: Tool to add
46
+
47
+ Raises:
48
+ ValueError: If tool is invalid
46
49
  """
50
+
47
51
  self._tool_manager.add_tool(tool)
48
52
 
49
53
  async def list_tools(self) -> list[dict]:
@@ -83,11 +87,21 @@ class BaseServer(FastMCP, ABC):
83
87
 
84
88
  Raises:
85
89
  ToolError: If tool execution fails
90
+ ValueError: If tool name is invalid or arguments are malformed
86
91
  """
92
+ if not name:
93
+ raise ValueError("Tool name is required")
94
+ if not isinstance(arguments, dict):
95
+ raise ValueError("Arguments must be a dictionary")
96
+
87
97
  logger.info(f"Calling tool: {name} with arguments: {arguments}")
88
- result = await self._tool_manager.call_tool(name, arguments)
89
- logger.info(f"Tool '{name}' completed successfully")
90
- return self._format_tool_result(result)
98
+ try:
99
+ result = await self._tool_manager.call_tool(name, arguments)
100
+ logger.info(f"Tool '{name}' completed successfully")
101
+ return self._format_tool_result(result)
102
+ except Exception as e:
103
+ logger.error(f"Tool '{name}' failed: {e}", exc_info=True)
104
+ raise ToolError(f"Tool execution failed: {str(e)}") from e
91
105
 
92
106
 
93
107
  class LocalServer(BaseServer):
@@ -111,14 +125,23 @@ class LocalServer(BaseServer):
111
125
 
112
126
  Returns:
113
127
  Configured store instance or None if no config provided
128
+
129
+ Raises:
130
+ ConfigurationError: If store configuration is invalid
114
131
  """
115
132
  if not store_config:
133
+ logger.info("No store configuration provided")
116
134
  return None
117
135
 
118
- store = store_from_config(store_config)
119
- self.add_tool(store.set)
120
- self.add_tool(store.delete)
121
- return store
136
+ try:
137
+ store = store_from_config(store_config)
138
+ self.add_tool(store.set)
139
+ self.add_tool(store.delete)
140
+ logger.info(f"Successfully configured store: {store_config.type}")
141
+ return store
142
+ except Exception as e:
143
+ logger.error(f"Failed to setup store: {e}", exc_info=True)
144
+ raise ConfigurationError(f"Store setup failed: {str(e)}") from e
122
145
 
123
146
  def _load_app(self, app_config: AppConfig) -> BaseApplication | None:
124
147
  """Load a single application with its integration.
@@ -129,22 +152,57 @@ class LocalServer(BaseServer):
129
152
  Returns:
130
153
  Configured application instance or None if loading fails
131
154
  """
155
+ if not app_config.name:
156
+ logger.error("App configuration missing name")
157
+ return None
158
+
132
159
  try:
133
- integration = (
134
- integration_from_config(app_config.integration, store=self.store) if app_config.integration else None
135
- )
136
- return app_from_slug(app_config.name)(integration=integration)
160
+ integration = None
161
+ if app_config.integration:
162
+ try:
163
+ integration = integration_from_config(app_config.integration, store=self.store)
164
+ logger.debug(f"Successfully configured integration for {app_config.name}")
165
+ except Exception as e:
166
+ logger.error(f"Failed to setup integration for {app_config.name}: {e}", exc_info=True)
167
+ # Continue without integration if it fails
168
+
169
+ app = app_from_slug(app_config.name)(integration=integration)
170
+ logger.info(f"Successfully loaded app: {app_config.name}")
171
+ return app
137
172
  except Exception as e:
138
173
  logger.error(f"Failed to load app {app_config.name}: {e}", exc_info=True)
139
174
  return None
140
175
 
141
176
  def _load_apps(self) -> None:
142
- """Load all configured applications."""
143
- logger.info(f"Loading apps: {self.config.apps}")
177
+ """Load all configured applications with graceful degradation."""
178
+ if not self.config.apps:
179
+ logger.warning("No applications configured")
180
+ return
181
+
182
+ logger.info(f"Loading {len(self.config.apps)} apps")
183
+ loaded_apps = 0
184
+ failed_apps = []
185
+
144
186
  for app_config in self.config.apps:
145
187
  app = self._load_app(app_config)
146
188
  if app:
147
- self._tool_manager.register_tools_from_app(app, app_config.actions)
189
+ try:
190
+ self._tool_manager.register_tools_from_app(app, app_config.actions)
191
+ loaded_apps += 1
192
+ logger.info(f"Successfully registered tools for {app_config.name}")
193
+ except Exception as e:
194
+ logger.error(f"Failed to register tools for {app_config.name}: {e}", exc_info=True)
195
+ failed_apps.append(app_config.name)
196
+ else:
197
+ failed_apps.append(app_config.name)
198
+
199
+ if failed_apps:
200
+ logger.warning(f"Failed to load {len(failed_apps)} apps: {', '.join(failed_apps)}")
201
+
202
+ if loaded_apps == 0:
203
+ logger.error("No apps were successfully loaded")
204
+ else:
205
+ logger.info(f"Successfully loaded {loaded_apps}/{len(self.config.apps)} apps")
148
206
 
149
207
 
150
208
  class AgentRServer(BaseServer):
@@ -154,27 +212,39 @@ class AgentRServer(BaseServer):
154
212
  config: Server configuration
155
213
  api_key: Optional API key for AgentR authentication. If not provided,
156
214
  will attempt to read from AGENTR_API_KEY environment variable.
215
+ max_retries: Maximum number of retries for API calls (default: 3)
216
+ retry_delay: Delay between retries in seconds (default: 1)
157
217
  **kwargs: Additional keyword arguments passed to FastMCP
158
218
  """
159
219
 
160
- def __init__(self, config: ServerConfig, api_key: str | None = None, **kwargs):
161
- self.client = AgentrClient(api_key=api_key)
220
+ def __init__(self, config: ServerConfig, **kwargs):
221
+ self.api_key = config.api_key.get_secret_value() if config.api_key else None
222
+ logger.info(f"Initializing AgentR server with API key: {self.api_key}")
223
+ self.client = AgentrClient(api_key=self.api_key)
162
224
  super().__init__(config, **kwargs)
163
225
  self.integration = AgentRIntegration(name="agentr", api_key=self.client.api_key)
164
226
  self._load_apps()
165
227
 
166
228
  def _fetch_apps(self) -> list[AppConfig]:
167
- """Fetch available apps from AgentR API.
229
+ """Fetch available apps from AgentR API with retry logic.
168
230
 
169
231
  Returns:
170
232
  List of application configurations
171
233
 
172
234
  Raises:
173
- httpx.HTTPError: If API request fails
235
+ httpx.HTTPError: If API request fails after all retries
236
+ ValidationError: If app configuration validation fails
174
237
  """
175
238
  try:
176
239
  apps = self.client.fetch_apps()
177
- return [AppConfig.model_validate(app) for app in apps]
240
+ validated_apps = []
241
+ for app in apps:
242
+ try:
243
+ validated_apps.append(AppConfig.model_validate(app))
244
+ except ValidationError as e:
245
+ logger.error(f"Failed to validate app config: {e}", exc_info=True)
246
+ continue
247
+ return validated_apps
178
248
  except httpx.HTTPError as e:
179
249
  logger.error(f"Failed to fetch apps from AgentR: {e}", exc_info=True)
180
250
  raise
@@ -194,21 +264,37 @@ class AgentRServer(BaseServer):
194
264
  if app_config.integration
195
265
  else None
196
266
  )
197
- return app_from_slug(app_config.name)(integration=integration)
267
+ app = app_from_slug(app_config.name)(integration=integration)
268
+ logger.info(f"Successfully loaded app: {app_config.name}")
269
+ return app
198
270
  except Exception as e:
199
271
  logger.error(f"Failed to load app {app_config.name}: {e}", exc_info=True)
200
272
  return None
201
273
 
202
274
  def _load_apps(self) -> None:
203
- """Load all apps available from AgentR."""
275
+ """Load all apps available from AgentR with graceful degradation."""
204
276
  try:
205
- for app_config in self._fetch_apps():
277
+ app_configs = self._fetch_apps()
278
+ if not app_configs:
279
+ logger.warning("No apps found from AgentR API")
280
+ return
281
+
282
+ loaded_apps = 0
283
+ for app_config in app_configs:
206
284
  app = self._load_app(app_config)
207
285
  if app:
208
286
  self._tool_manager.register_tools_from_app(app, app_config.actions)
287
+ loaded_apps += 1
288
+
289
+ if loaded_apps == 0:
290
+ logger.error("Failed to load any apps from AgentR")
291
+ else:
292
+ logger.info(f"Successfully loaded {loaded_apps}/{len(app_configs)} apps from AgentR")
293
+
209
294
  except Exception:
210
295
  logger.error("Failed to load apps", exc_info=True)
211
- raise
296
+ # Don't raise the exception to allow server to start with partial functionality
297
+ logger.warning("Server will start with limited functionality due to app loading failures")
212
298
 
213
299
 
214
300
  class SingleMCPServer(BaseServer):
@@ -234,27 +320,13 @@ class SingleMCPServer(BaseServer):
234
320
  config: ServerConfig | None = None,
235
321
  **kwargs,
236
322
  ):
323
+ if not app_instance:
324
+ raise ValueError("app_instance is required")
237
325
  if not config:
238
326
  config = ServerConfig(
239
327
  type="local",
240
- name=f"{app_instance.name.title()} MCP Server for Local Development"
241
- if app_instance
242
- else "Unnamed MCP Server",
243
- description=f"Minimal MCP server for the local {app_instance.name} application."
244
- if app_instance
245
- else "Minimal MCP server with no application loaded.",
328
+ name=f"{app_instance.name.title()} MCP Server for Local Development",
329
+ description=f"Minimal MCP server for the local {app_instance.name} application.",
246
330
  )
247
331
  super().__init__(config, **kwargs)
248
-
249
- self.app_instance = app_instance
250
- self._load_apps()
251
-
252
- def _load_apps(self) -> None:
253
- """Registers tools from the single provided application instance."""
254
- if not self.app_instance:
255
- logger.warning("No app_instance provided. No tools registered.")
256
- return
257
-
258
- tool_functions = self.app_instance.list_tools()
259
- for tool_func in tool_functions:
260
- self._tool_manager.add_tool(tool_func)
332
+ self._tool_manager.register_tools_from_app(app_instance)
@@ -85,7 +85,6 @@ class ToolManager:
85
85
  tools = list(self._tools.values())
86
86
  if tags:
87
87
  tools = _filter_by_tags(tools, tags)
88
-
89
88
  if format == ToolFormat.MCP:
90
89
  tools = [convert_tool_to_mcp_tool(tool) for tool in tools]
91
90
  elif format == ToolFormat.LANGCHAIN:
@@ -94,7 +93,6 @@ class ToolManager:
94
93
  tools = [convert_tool_to_openai_tool(tool) for tool in tools]
95
94
  else:
96
95
  raise ValueError(f"Invalid format: {format}")
97
-
98
96
  return tools
99
97
 
100
98
  def add_tool(self, fn: Callable[..., Any] | Tool, name: str | None = None) -> Tool:
@@ -5,10 +5,9 @@ from loguru import logger
5
5
 
6
6
  from universal_mcp.config import AppConfig
7
7
  from universal_mcp.exceptions import NotAuthorizedError
8
- from universal_mcp.utils.singleton import Singleton
9
8
 
10
9
 
11
- class AgentrClient(metaclass=Singleton):
10
+ class AgentrClient:
12
11
  """Helper class for AgentR API operations.
13
12
 
14
13
  This class provides utility methods for interacting with the AgentR API,
@@ -19,14 +18,20 @@ class AgentrClient(metaclass=Singleton):
19
18
  base_url (str, optional): Base URL for AgentR API. Defaults to https://api.agentr.dev
20
19
  """
21
20
 
22
- def __init__(self, api_key: str = None, base_url: str = None):
23
- self.api_key = api_key or os.getenv("AGENTR_API_KEY")
24
- if not self.api_key:
21
+ def __init__(self, api_key: str | None = None, base_url: str | None = None):
22
+ if api_key:
23
+ self.api_key = api_key
24
+ elif os.getenv("AGENTR_API_KEY"):
25
+ self.api_key = os.getenv("AGENTR_API_KEY")
26
+ else:
25
27
  logger.error(
26
28
  "API key for AgentR is missing. Please visit https://agentr.dev to create an API key, then set it as AGENTR_API_KEY environment variable."
27
29
  )
28
30
  raise ValueError("AgentR API key required - get one at https://agentr.dev")
29
31
  self.base_url = (base_url or os.getenv("AGENTR_BASE_URL", "https://api.agentr.dev")).rstrip("/")
32
+ self.client = httpx.Client(
33
+ base_url=self.base_url, headers={"X-API-KEY": self.api_key}, timeout=30, follow_redirects=True
34
+ )
30
35
 
31
36
  def get_credentials(self, integration_name: str) -> dict:
32
37
  """Get credentials for an integration from the AgentR API.
@@ -41,9 +46,8 @@ class AgentrClient(metaclass=Singleton):
41
46
  NotAuthorizedError: If credentials are not found (404 response)
42
47
  HTTPError: For other API errors
43
48
  """
44
- response = httpx.get(
45
- f"{self.base_url}/api/{integration_name}/credentials/",
46
- headers={"accept": "application/json", "X-API-KEY": self.api_key},
49
+ response = self.client.get(
50
+ f"/api/{integration_name}/credentials/",
47
51
  )
48
52
  if response.status_code == 404:
49
53
  logger.warning(f"No credentials found for {integration_name}. Requesting authorization...")
@@ -64,15 +68,14 @@ class AgentrClient(metaclass=Singleton):
64
68
  Raises:
65
69
  HTTPError: If API request fails
66
70
  """
67
- response = httpx.get(
68
- f"{self.base_url}/api/{integration_name}/authorize/",
69
- headers={"X-API-KEY": self.api_key},
71
+ response = self.client.get(
72
+ f"/api/{integration_name}/authorize/",
70
73
  )
71
74
  response.raise_for_status()
72
75
  url = response.json()
73
76
  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."
74
77
 
75
- def fetch_apps(self) -> list[dict]:
78
+ def fetch_apps(self) -> list[AppConfig]:
76
79
  """Fetch available apps from AgentR API.
77
80
 
78
81
  Returns:
@@ -81,11 +84,7 @@ class AgentrClient(metaclass=Singleton):
81
84
  Raises:
82
85
  httpx.HTTPError: If API request fails
83
86
  """
84
- response = httpx.get(
85
- f"{self.base_url}/api/apps/",
86
- headers={"X-API-KEY": self.api_key},
87
- timeout=10,
88
- )
87
+ response = self.client.get("/api/apps/")
89
88
  response.raise_for_status()
90
89
  data = response.json()
91
90
  return [AppConfig.model_validate(app) for app in data]
@@ -897,7 +897,12 @@ def _generate_method_code(path, method, operation):
897
897
 
898
898
  # --- Handle Response ---
899
899
  body_lines.append(" response.raise_for_status()")
900
- body_lines.append(" return response.json()")
900
+ body_lines.append(" if response.status_code == 204 or not response.content or not response.text.strip():")
901
+ body_lines.append(" return None")
902
+ body_lines.append(" try:")
903
+ body_lines.append(" return response.json()")
904
+ body_lines.append(" except ValueError:")
905
+ body_lines.append(" return None")
901
906
 
902
907
  # --- Combine Signature, Docstring, and Body for Final Method Code ---
903
908
  method_code = signature + formatted_docstring + "\n" + "\n".join(body_lines)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: universal-mcp
3
- Version: 0.1.18rc3
3
+ Version: 0.1.19
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
@@ -1,8 +1,8 @@
1
1
  universal_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  universal_mcp/analytics.py,sha256=Dkv8mkc_2T2t5NxLSZzcr3BlmOispj1RKtbB86V1i4M,2306
3
3
  universal_mcp/cli.py,sha256=Xcdm4UMIlwxK6f0FHvmu5b6lZ8q14S3vZexRM32zAK4,10298
4
- universal_mcp/config.py,sha256=EbLtv1j7-0y2pI4-2lRFtTBXaVkEoiBhPm2jqeaVRQU,3502
5
- universal_mcp/exceptions.py,sha256=2A_aIzcwjB99tR4xCFjPkWPf10rBK_785FerJI7Tzns,564
4
+ universal_mcp/config.py,sha256=HaAZvf-XzQZpqGGWUuT5zojWloO8GL5Acfa5_0sDs_Q,3321
5
+ universal_mcp/exceptions.py,sha256=-pbeZhpNieJfnSd2-WM80pU8W8mK8VHXcSjky0BHwdk,665
6
6
  universal_mcp/logger.py,sha256=VmH_83efpErLEDTJqz55Dp0dioTXfGvMBLZUx5smOLc,2116
7
7
  universal_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  universal_mcp/applications/README.md,sha256=eqbizxaTxKH2O1tyIJR2yI0Db5TQxtgPd_vbpWyCa2Y,3527
@@ -13,7 +13,7 @@ universal_mcp/integrations/__init__.py,sha256=X8iEzs02IlXfeafp6GMm-cOkg70QdjnlTR
13
13
  universal_mcp/integrations/integration.py,sha256=QvZlq3G5OU4tHPv9uq9Nv5NFe30NdUsJU-Av474n0_o,13154
14
14
  universal_mcp/servers/README.md,sha256=ytFlgp8-LO0oogMrHkMOp8SvFTwgsKgv7XhBVZGNTbM,2284
15
15
  universal_mcp/servers/__init__.py,sha256=eBZCsaZjiEv6ZlRRslPKgurQxmpHLQyiXv2fTBygHnM,532
16
- universal_mcp/servers/server.py,sha256=1UWvywUzgGVYyIGlaES9tgj_xP_f6EC4bK_vM0nE_tE,9237
16
+ universal_mcp/servers/server.py,sha256=X-CM5bCbMUVm7NkAT5RNeiyc38MbiFrwlZE3dbX10SM,12810
17
17
  universal_mcp/stores/README.md,sha256=jrPh_ow4ESH4BDGaSafilhOVaN8oQ9IFlFW-j5Z5hLA,2465
18
18
  universal_mcp/stores/__init__.py,sha256=quvuwhZnpiSLuojf0NfmBx2xpaCulv3fbKtKaSCEmuM,603
19
19
  universal_mcp/stores/store.py,sha256=mxnmOVlDNrr8OKhENWDtCIfK7YeCBQcGdS6I2ogRCsU,6756
@@ -21,10 +21,10 @@ universal_mcp/tools/README.md,sha256=RuxliOFqV1ZEyeBdj3m8UKfkxAsfrxXh-b6V4ZGAk8I
21
21
  universal_mcp/tools/__init__.py,sha256=Fatza_R0qYWmNF1WQSfUZZKQFu5qf-16JhZzdmyx3KY,333
22
22
  universal_mcp/tools/adapters.py,sha256=gz_sNDc_bseMHWmpQmqhOq65veE-DuK_kJYXGIx0Wi8,1427
23
23
  universal_mcp/tools/func_metadata.py,sha256=zIDXgIBvu5Gh8aNlg-Q7cZZos9Iky75MS0Me0BraXeM,8086
24
- universal_mcp/tools/manager.py,sha256=GMBKPl-W6zoyK6Hisiz-i9WROsV8W7VC9Vou8d55rXA,7983
24
+ universal_mcp/tools/manager.py,sha256=eNYEGCeTvtSsyPkPWo4ciuJEqNw4ux-XCr0r5OyBejg,7981
25
25
  universal_mcp/tools/tools.py,sha256=8YBTaJCM38Nhan9Al6Vlq4FtSULrKlxg1q_o8OL1_FM,3322
26
26
  universal_mcp/utils/__init__.py,sha256=8wi4PGWu-SrFjNJ8U7fr2iFJ1ktqlDmSKj1xYd7KSDc,41
27
- universal_mcp/utils/agentr.py,sha256=GlFK5_RJXP3XpIGKLzkIe5nu2rfT6bqSoT0h1hipy9g,3438
27
+ universal_mcp/utils/agentr.py,sha256=YmX6hvFW84keJKTZqP3jPz4rP9DM5wHZ0vTMHfxO6AI,3360
28
28
  universal_mcp/utils/common.py,sha256=HEZC2Mhilb8DrGXQG2tboAIw1r4veGilGWjfnPF1lyA,888
29
29
  universal_mcp/utils/docstring_parser.py,sha256=6oIeCjOUirFdVpXdGZt5zDKje6jmCY42-GeYOc_7r2I,11317
30
30
  universal_mcp/utils/installation.py,sha256=ItOfBFhKOh4DLz237jgAz_Fn0uOMdrKXw0n5BaUZZNs,7286
@@ -33,13 +33,13 @@ universal_mcp/utils/openapi/__inti__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
33
33
  universal_mcp/utils/openapi/api_generator.py,sha256=FjtvbnWuI1P8W8wXuKLCirUtsqQ4HI_TuQrhpA4SqTs,4749
34
34
  universal_mcp/utils/openapi/api_splitter.py,sha256=6O2y7fcCo2k3ixLr6_9-aAZx2kas3UAxQhqJy1esNkE,18829
35
35
  universal_mcp/utils/openapi/docgen.py,sha256=DNmwlhg_-TRrHa74epyErMTRjV2nutfCQ7seb_Rq5hE,21366
36
- universal_mcp/utils/openapi/openapi.py,sha256=6uH24mI_02yHBfz3dSsYZFpxy9G_dGr0mvDJFZ0JnvA,46547
36
+ universal_mcp/utils/openapi/openapi.py,sha256=8XCIkJuwTN0UUcrBslQxitvz4y0NItBtuIgxdvb-Gdg,46857
37
37
  universal_mcp/utils/openapi/preprocessor.py,sha256=qLYv4ekors5B2OU_YUvXICYQ7XYhAOEPyAnKtnBvNpM,46699
38
38
  universal_mcp/utils/openapi/readme.py,sha256=R2Jp7DUXYNsXPDV6eFTkLiy7MXbSULUj1vHh4O_nB4c,2974
39
39
  universal_mcp/utils/templates/README.md.j2,sha256=Mrm181YX-o_-WEfKs01Bi2RJy43rBiq2j6fTtbWgbTA,401
40
40
  universal_mcp/utils/templates/api_client.py.j2,sha256=972Im7LNUAq3yZTfwDcgivnb-b8u6_JLKWXwoIwXXXQ,908
41
- universal_mcp-0.1.18rc3.dist-info/METADATA,sha256=tTHxjWlSvE9VwhtC70HT_VenfsAgCeR0s-2PPNIsXyo,12125
42
- universal_mcp-0.1.18rc3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
43
- universal_mcp-0.1.18rc3.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
44
- universal_mcp-0.1.18rc3.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
45
- universal_mcp-0.1.18rc3.dist-info/RECORD,,
41
+ universal_mcp-0.1.19.dist-info/METADATA,sha256=wPKF-GWj2l1ZK430vl25Su_RCi56JiyzV4opj_Lp4Rs,12122
42
+ universal_mcp-0.1.19.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
43
+ universal_mcp-0.1.19.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
44
+ universal_mcp-0.1.19.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
45
+ universal_mcp-0.1.19.dist-info/RECORD,,