universal-mcp 0.1.16__tar.gz → 0.1.18rc2__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.
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/.gitignore +0 -1
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/PKG-INFO +2 -2
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/pyproject.toml +2 -2
- universal_mcp-0.1.18rc2/src/tests/test_tool_manager.py +185 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/applications/application.py +1 -1
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/integrations/integration.py +9 -9
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/servers/__init__.py +2 -2
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/tools/manager.py +24 -8
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/LICENSE +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/README.md +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/tests/__init__.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/tests/conftest.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/tests/test_api_generator.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/tests/test_api_integration.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/tests/test_applications.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/tests/test_localserver.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/tests/test_stores.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/tests/test_tool.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/tests/test_zenquotes.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/__init__.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/analytics.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/applications/README.md +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/applications/__init__.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/cli.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/config.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/exceptions.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/integrations/README.md +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/integrations/__init__.py +1 -1
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/logger.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/py.typed +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/servers/README.md +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/servers/server.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/stores/README.md +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/stores/__init__.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/stores/store.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/tools/README.md +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/tools/__init__.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/tools/adapters.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/tools/func_metadata.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/tools/tools.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/__init__.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/agentr.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/common.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/docstring_parser.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/installation.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/openapi/__inti__.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/openapi/api_generator.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/openapi/docgen.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/openapi/openapi.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/openapi/preprocessor.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/openapi/readme.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/singleton.py +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/templates/README.md.j2 +0 -0
- {universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/templates/api_client.py.j2 +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: universal-mcp
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.18rc2
|
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
|
@@ -14,7 +14,7 @@ Requires-Dist: keyring>=25.6.0
|
|
14
14
|
Requires-Dist: langchain-mcp-adapters>=0.0.3
|
15
15
|
Requires-Dist: litellm>=1.30.7
|
16
16
|
Requires-Dist: loguru>=0.7.3
|
17
|
-
Requires-Dist: mcp>=1.
|
17
|
+
Requires-Dist: mcp>=1.8.1
|
18
18
|
Requires-Dist: posthog>=3.24.0
|
19
19
|
Requires-Dist: pydantic-settings>=2.8.1
|
20
20
|
Requires-Dist: pydantic>=2.11.1
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "universal-mcp"
|
7
|
-
version = "0.1.
|
7
|
+
version = "0.1.18-rc2"
|
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 = [
|
@@ -21,7 +21,7 @@ dependencies = [
|
|
21
21
|
"langchain-mcp-adapters>=0.0.3",
|
22
22
|
"litellm>=1.30.7",
|
23
23
|
"loguru>=0.7.3",
|
24
|
-
"mcp>=1.
|
24
|
+
"mcp>=1.8.1",
|
25
25
|
"posthog>=3.24.0",
|
26
26
|
"pydantic>=2.11.1",
|
27
27
|
"pydantic-settings>=2.8.1",
|
@@ -0,0 +1,185 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from universal_mcp.applications.application import BaseApplication
|
4
|
+
from universal_mcp.exceptions import ToolError
|
5
|
+
from universal_mcp.tools.adapters import ToolFormat
|
6
|
+
from universal_mcp.tools.manager import Tool, ToolManager
|
7
|
+
|
8
|
+
|
9
|
+
# Dummy tools for testing
|
10
|
+
async def dummy_add(a: int, b: int) -> int:
|
11
|
+
"""
|
12
|
+
Adds two integers asynchronously.
|
13
|
+
|
14
|
+
Args:
|
15
|
+
a: The first integer.
|
16
|
+
b: The second integer.
|
17
|
+
|
18
|
+
Returns:
|
19
|
+
The sum of a and b.
|
20
|
+
|
21
|
+
Tags:
|
22
|
+
math, important
|
23
|
+
"""
|
24
|
+
return a + b
|
25
|
+
|
26
|
+
|
27
|
+
async def dummy_multiply(a: int, b: int) -> int:
|
28
|
+
"""
|
29
|
+
Multiplies two integers asynchronously.
|
30
|
+
|
31
|
+
Args:
|
32
|
+
a: The first integer.
|
33
|
+
b: The second integer.
|
34
|
+
|
35
|
+
Returns:
|
36
|
+
The product of a and b.
|
37
|
+
|
38
|
+
Tags:
|
39
|
+
math
|
40
|
+
"""
|
41
|
+
return a * b
|
42
|
+
|
43
|
+
|
44
|
+
async def dummy_error() -> None:
|
45
|
+
"""
|
46
|
+
Raises a ValueError for testing error handling.
|
47
|
+
|
48
|
+
Raises:
|
49
|
+
ValueError: Always raised with the message "Test error".
|
50
|
+
|
51
|
+
Tags:
|
52
|
+
test
|
53
|
+
"""
|
54
|
+
raise ValueError("Test error")
|
55
|
+
|
56
|
+
|
57
|
+
@pytest.fixture
|
58
|
+
def tool_manager():
|
59
|
+
return ToolManager()
|
60
|
+
|
61
|
+
|
62
|
+
@pytest.fixture
|
63
|
+
def dummy_tools():
|
64
|
+
return [Tool.from_function(dummy_add), Tool.from_function(dummy_multiply), Tool.from_function(dummy_error)]
|
65
|
+
|
66
|
+
|
67
|
+
class ExampleApp(BaseApplication):
|
68
|
+
def __init__(self):
|
69
|
+
super().__init__(name="example_app")
|
70
|
+
|
71
|
+
def list_tools(self):
|
72
|
+
return [dummy_add, dummy_multiply, dummy_error]
|
73
|
+
|
74
|
+
|
75
|
+
def test_add_tool(tool_manager):
|
76
|
+
tool = tool_manager.add_tool(dummy_add)
|
77
|
+
assert tool.name == "dummy_add"
|
78
|
+
assert tool.name in [t.name for t in tool_manager.list_tools()]
|
79
|
+
|
80
|
+
|
81
|
+
def test_add_duplicate_tool(tool_manager):
|
82
|
+
tool1 = tool_manager.add_tool(dummy_add)
|
83
|
+
tool2 = tool_manager.add_tool(dummy_add)
|
84
|
+
assert tool1 is tool2 # Should return existing tool
|
85
|
+
assert len(tool_manager.list_tools()) == 1
|
86
|
+
|
87
|
+
|
88
|
+
def test_remove_tool(tool_manager):
|
89
|
+
tool = tool_manager.add_tool(dummy_add)
|
90
|
+
assert tool_manager.remove_tool(tool.name) is True
|
91
|
+
assert tool_manager.get_tool(tool.name) is None
|
92
|
+
assert tool_manager.remove_tool("nonexistent") is False
|
93
|
+
|
94
|
+
|
95
|
+
def test_clear_tools(tool_manager, dummy_tools):
|
96
|
+
for tool in dummy_tools:
|
97
|
+
tool_manager.add_tool(tool)
|
98
|
+
assert len(tool_manager.list_tools()) == 3
|
99
|
+
tool_manager.clear_tools()
|
100
|
+
assert len(tool_manager.list_tools()) == 0
|
101
|
+
|
102
|
+
|
103
|
+
def test_list_tools_format(tool_manager, dummy_tools):
|
104
|
+
for tool in dummy_tools:
|
105
|
+
tool_manager.add_tool(tool)
|
106
|
+
|
107
|
+
# Test MCP format
|
108
|
+
mcp_tools = tool_manager.list_tools(format=ToolFormat.MCP)
|
109
|
+
assert len(mcp_tools) == 3
|
110
|
+
|
111
|
+
# Test LangChain format
|
112
|
+
langchain_tools = tool_manager.list_tools(format=ToolFormat.LANGCHAIN)
|
113
|
+
assert len(langchain_tools) == 3
|
114
|
+
|
115
|
+
# Test OpenAI format
|
116
|
+
openai_tools = tool_manager.list_tools(format=ToolFormat.OPENAI)
|
117
|
+
assert len(openai_tools) == 3
|
118
|
+
|
119
|
+
|
120
|
+
def test_filter_tools_by_tags(tool_manager, dummy_tools):
|
121
|
+
for tool in dummy_tools:
|
122
|
+
tool_manager.add_tool(tool)
|
123
|
+
|
124
|
+
# Test filtering by important tag
|
125
|
+
important_tools = tool_manager.list_tools(tags=["important"])
|
126
|
+
assert len(important_tools) == 1
|
127
|
+
assert important_tools[0].name == "dummy_add"
|
128
|
+
|
129
|
+
# Test filtering by math tag
|
130
|
+
math_tools = tool_manager.list_tools(tags=["math"])
|
131
|
+
assert len(math_tools) == 2
|
132
|
+
|
133
|
+
|
134
|
+
@pytest.mark.asyncio
|
135
|
+
async def test_call_tool_success(tool_manager):
|
136
|
+
tool_manager.add_tool(dummy_add)
|
137
|
+
result = await tool_manager.call_tool("dummy_add", {"a": 2, "b": 3})
|
138
|
+
assert result == 5
|
139
|
+
|
140
|
+
|
141
|
+
@pytest.mark.asyncio
|
142
|
+
async def test_call_tool_error(tool_manager):
|
143
|
+
tool_manager.add_tool(dummy_error)
|
144
|
+
with pytest.raises(ToolError):
|
145
|
+
await tool_manager.call_tool("dummy_error", {})
|
146
|
+
|
147
|
+
|
148
|
+
@pytest.mark.asyncio
|
149
|
+
async def test_call_nonexistent_tool(tool_manager):
|
150
|
+
with pytest.raises(ToolError):
|
151
|
+
await tool_manager.call_tool("nonexistent", {})
|
152
|
+
|
153
|
+
|
154
|
+
@pytest.mark.asyncio
|
155
|
+
async def test_call_tool_from_app(tool_manager):
|
156
|
+
app = ExampleApp()
|
157
|
+
# Only important are added by default
|
158
|
+
tool_manager.register_tools_from_app(app)
|
159
|
+
tools = tool_manager.list_tools()
|
160
|
+
assert len(tools) == 1
|
161
|
+
assert "example_app_dummy_add" in [t.name for t in tools]
|
162
|
+
result = await tool_manager.call_tool("example_app_dummy_add", {"a": 2, "b": 3})
|
163
|
+
assert result == 5
|
164
|
+
|
165
|
+
|
166
|
+
@pytest.mark.asyncio
|
167
|
+
async def test_call_tool_from_app_with_tags(tool_manager):
|
168
|
+
app = ExampleApp()
|
169
|
+
# Only important are added by default
|
170
|
+
tool_manager.register_tools_from_app(app, tags=["math"])
|
171
|
+
tools = tool_manager.list_tools()
|
172
|
+
assert len(tools) == 2
|
173
|
+
assert "example_app_dummy_add" in [t.name for t in tools]
|
174
|
+
assert "example_app_dummy_multiply" in [t.name for t in tools]
|
175
|
+
|
176
|
+
|
177
|
+
@pytest.mark.asyncio
|
178
|
+
async def test_load_tool_from_name(tool_manager):
|
179
|
+
app = ExampleApp()
|
180
|
+
# Only important are added by default
|
181
|
+
tool_manager.register_tools_from_app(app, tool_names=["dummy_multiply", "dummy_add"])
|
182
|
+
tools = tool_manager.list_tools()
|
183
|
+
assert len(tools) == 2
|
184
|
+
assert "example_app_dummy_multiply" in [t.name for t in tools]
|
185
|
+
assert "example_app_dummy_add" in [t.name for t in tools]
|
{universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/applications/application.py
RENAMED
@@ -81,7 +81,7 @@ class APIApplication(BaseApplication):
|
|
81
81
|
"""
|
82
82
|
super().__init__(name, **kwargs)
|
83
83
|
self.default_timeout: int = 180
|
84
|
-
self.integration
|
84
|
+
self.integration = integration
|
85
85
|
logger.debug(f"Initializing APIApplication '{name}' with integration: {integration}")
|
86
86
|
self._client: httpx.Client | None = client
|
87
87
|
self.base_url: str = ""
|
{universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/integrations/integration.py
RENAMED
@@ -1,4 +1,3 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
1
|
from typing import Any
|
3
2
|
|
4
3
|
import httpx
|
@@ -18,7 +17,7 @@ def sanitize_api_key_name(name: str) -> str:
|
|
18
17
|
return f"{name.upper()}{suffix}"
|
19
18
|
|
20
19
|
|
21
|
-
class Integration
|
20
|
+
class Integration:
|
22
21
|
"""Abstract base class for handling application integrations and authentication.
|
23
22
|
|
24
23
|
This class defines the interface for different types of integrations that handle
|
@@ -35,9 +34,11 @@ class Integration(ABC):
|
|
35
34
|
|
36
35
|
def __init__(self, name: str, store: BaseStore | None = None):
|
37
36
|
self.name = name
|
38
|
-
|
37
|
+
if store is None:
|
38
|
+
self.store = MemoryStore()
|
39
|
+
else:
|
40
|
+
self.store = store
|
39
41
|
|
40
|
-
@abstractmethod
|
41
42
|
def authorize(self) -> str | dict[str, Any]:
|
42
43
|
"""Authorize the integration.
|
43
44
|
|
@@ -49,7 +50,6 @@ class Integration(ABC):
|
|
49
50
|
"""
|
50
51
|
pass
|
51
52
|
|
52
|
-
@abstractmethod
|
53
53
|
def get_credentials(self) -> dict[str, Any]:
|
54
54
|
"""Get credentials for the integration.
|
55
55
|
|
@@ -59,9 +59,9 @@ class Integration(ABC):
|
|
59
59
|
Raises:
|
60
60
|
NotAuthorizedError: If credentials are not found or invalid.
|
61
61
|
"""
|
62
|
-
|
62
|
+
credentials = self.store.get(self.name)
|
63
|
+
return credentials
|
63
64
|
|
64
|
-
@abstractmethod
|
65
65
|
def set_credentials(self, credentials: dict[str, Any]) -> None:
|
66
66
|
"""Set credentials for the integration.
|
67
67
|
|
@@ -71,7 +71,7 @@ class Integration(ABC):
|
|
71
71
|
Raises:
|
72
72
|
ValueError: If credentials are invalid or missing required fields.
|
73
73
|
"""
|
74
|
-
|
74
|
+
self.store.set(self.name, credentials)
|
75
75
|
|
76
76
|
|
77
77
|
class ApiKeyIntegration(Integration):
|
@@ -91,7 +91,7 @@ class ApiKeyIntegration(Integration):
|
|
91
91
|
store: Store instance for persisting credentials and other data
|
92
92
|
"""
|
93
93
|
|
94
|
-
def __init__(self, name: str, store: BaseStore =
|
94
|
+
def __init__(self, name: str, store: BaseStore | None = None, **kwargs):
|
95
95
|
self.type = "api_key"
|
96
96
|
sanitized_name = sanitize_api_key_name(name)
|
97
97
|
super().__init__(sanitized_name, store, **kwargs)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from universal_mcp.config import ServerConfig
|
2
|
-
from universal_mcp.servers.server import AgentRServer, LocalServer, SingleMCPServer
|
2
|
+
from universal_mcp.servers.server import AgentRServer, BaseServer, LocalServer, SingleMCPServer
|
3
3
|
|
4
4
|
|
5
5
|
def server_from_config(config: ServerConfig):
|
@@ -12,4 +12,4 @@ def server_from_config(config: ServerConfig):
|
|
12
12
|
raise ValueError(f"Unsupported server type: {config.type}")
|
13
13
|
|
14
14
|
|
15
|
-
__all__ = [AgentRServer, LocalServer, SingleMCPServer, server_from_config]
|
15
|
+
__all__ = [AgentRServer, LocalServer, SingleMCPServer, BaseServer, server_from_config]
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import re
|
1
2
|
from collections.abc import Callable
|
2
3
|
from typing import Any
|
3
4
|
|
@@ -19,14 +20,21 @@ DEFAULT_IMPORTANT_TAG = "important"
|
|
19
20
|
TOOL_NAME_SEPARATOR = "_"
|
20
21
|
|
21
22
|
|
22
|
-
def _filter_by_name(tools: list[Tool], tool_names: list[str]) -> list[Tool]:
|
23
|
+
def _filter_by_name(tools: list[Tool], tool_names: list[str] | None) -> list[Tool]:
|
23
24
|
if not tool_names:
|
24
25
|
return tools
|
25
|
-
|
26
|
+
logger.debug(f"Filtering tools by name: {tool_names}")
|
27
|
+
filtered_tools = []
|
28
|
+
for tool in tools:
|
29
|
+
for name in tool_names:
|
30
|
+
if re.search(name, tool.name):
|
31
|
+
filtered_tools.append(tool)
|
32
|
+
return filtered_tools
|
26
33
|
|
27
34
|
|
28
35
|
def _filter_by_tags(tools: list[Tool], tags: list[str] | None) -> list[Tool]:
|
29
|
-
|
36
|
+
if not tags:
|
37
|
+
return tools
|
30
38
|
return [tool for tool in tools if any(tag in tool.tags for tag in tags)]
|
31
39
|
|
32
40
|
|
@@ -148,14 +156,14 @@ class ToolManager:
|
|
148
156
|
def register_tools_from_app(
|
149
157
|
self,
|
150
158
|
app: BaseApplication,
|
151
|
-
tool_names: list[str] = None,
|
152
|
-
tags: list[str] = None,
|
159
|
+
tool_names: list[str] | None = None,
|
160
|
+
tags: list[str] | None = None,
|
153
161
|
) -> None:
|
154
162
|
"""Register tools from an application.
|
155
163
|
|
156
164
|
Args:
|
157
165
|
app: The application to register tools from.
|
158
|
-
|
166
|
+
tool_names: Optional list of specific tool names to register.
|
159
167
|
tags: Optional list of tags to filter tools by.
|
160
168
|
"""
|
161
169
|
try:
|
@@ -186,8 +194,16 @@ class ToolManager:
|
|
186
194
|
tool_name = getattr(function, "__name__", "unknown")
|
187
195
|
logger.error(f"Failed to create Tool from '{tool_name}' in {app.name}: {e}")
|
188
196
|
|
189
|
-
|
190
|
-
|
197
|
+
if tags:
|
198
|
+
tools = _filter_by_tags(tools, tags)
|
199
|
+
|
200
|
+
if tool_names:
|
201
|
+
tools = _filter_by_name(tools, tool_names)
|
202
|
+
|
203
|
+
# If no tool names or tags are provided, use the default important tag
|
204
|
+
if not tool_names and not tags:
|
205
|
+
tools = _filter_by_tags(tools, [DEFAULT_IMPORTANT_TAG])
|
206
|
+
|
191
207
|
self.register_tools(tools)
|
192
208
|
return
|
193
209
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/docstring_parser.py
RENAMED
File without changes
|
File without changes
|
{universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/openapi/__inti__.py
RENAMED
File without changes
|
{universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/openapi/api_generator.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/openapi/preprocessor.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/templates/README.md.j2
RENAMED
File without changes
|
{universal_mcp-0.1.16 → universal_mcp-0.1.18rc2}/src/universal_mcp/utils/templates/api_client.py.j2
RENAMED
File without changes
|