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 +2 -5
- universal_mcp/exceptions.py +4 -0
- universal_mcp/servers/server.py +127 -55
- universal_mcp/tools/manager.py +0 -2
- universal_mcp/utils/agentr.py +16 -17
- universal_mcp/utils/openapi/openapi.py +6 -1
- {universal_mcp-0.1.18rc3.dist-info → universal_mcp-0.1.19.dist-info}/METADATA +1 -1
- {universal_mcp-0.1.18rc3.dist-info → universal_mcp-0.1.19.dist-info}/RECORD +11 -11
- {universal_mcp-0.1.18rc3.dist-info → universal_mcp-0.1.19.dist-info}/WHEEL +0 -0
- {universal_mcp-0.1.18rc3.dist-info → universal_mcp-0.1.19.dist-info}/entry_points.txt +0 -0
- {universal_mcp-0.1.18rc3.dist-info → universal_mcp-0.1.19.dist-info}/licenses/LICENSE +0 -0
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:
|
universal_mcp/exceptions.py
CHANGED
universal_mcp/servers/server.py
CHANGED
@@ -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
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
89
|
-
|
90
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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
|
-
|
135
|
-
|
136
|
-
|
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
|
-
|
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
|
-
|
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,
|
161
|
-
self.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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)
|
universal_mcp/tools/manager.py
CHANGED
@@ -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:
|
universal_mcp/utils/agentr.py
CHANGED
@@ -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
|
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
|
-
|
24
|
-
|
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 =
|
45
|
-
f"
|
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 =
|
68
|
-
f"
|
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[
|
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 =
|
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("
|
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.
|
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=
|
5
|
-
universal_mcp/exceptions.py,sha256
|
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=
|
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=
|
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=
|
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=
|
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.
|
42
|
-
universal_mcp-0.1.
|
43
|
-
universal_mcp-0.1.
|
44
|
-
universal_mcp-0.1.
|
45
|
-
universal_mcp-0.1.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|