universal-mcp 0.1.24rc4__py3-none-any.whl → 0.1.24rc6__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/agents/base.py +23 -10
- universal_mcp/agents/react.py +30 -24
- universal_mcp/agents/tools.py +35 -0
- universal_mcp/config.py +0 -93
- universal_mcp/tools/manager.py +15 -22
- universal_mcp/tools/tools.py +11 -5
- universal_mcp/types.py +25 -0
- {universal_mcp-0.1.24rc4.dist-info → universal_mcp-0.1.24rc6.dist-info}/METADATA +3 -6
- {universal_mcp-0.1.24rc4.dist-info → universal_mcp-0.1.24rc6.dist-info}/RECORD +12 -11
- {universal_mcp-0.1.24rc4.dist-info → universal_mcp-0.1.24rc6.dist-info}/WHEEL +0 -0
- {universal_mcp-0.1.24rc4.dist-info → universal_mcp-0.1.24rc6.dist-info}/entry_points.txt +0 -0
- {universal_mcp-0.1.24rc4.dist-info → universal_mcp-0.1.24rc6.dist-info}/licenses/LICENSE +0 -0
universal_mcp/agents/base.py
CHANGED
@@ -3,26 +3,31 @@ from typing import cast
|
|
3
3
|
from uuid import uuid4
|
4
4
|
|
5
5
|
from langchain_core.messages import AIMessageChunk
|
6
|
+
from langgraph.checkpoint.base import BaseCheckpointSaver
|
6
7
|
from langgraph.checkpoint.memory import MemorySaver
|
7
8
|
from langgraph.types import Command
|
8
9
|
|
10
|
+
from .llm import get_llm
|
9
11
|
from .utils import RichCLI
|
10
12
|
|
11
13
|
|
12
14
|
class BaseAgent:
|
13
|
-
def __init__(self, name: str, instructions: str, model: str):
|
15
|
+
def __init__(self, name: str, instructions: str, model: str, memory: BaseCheckpointSaver | None = None, **kwargs):
|
14
16
|
self.name = name
|
15
17
|
self.instructions = instructions
|
16
18
|
self.model = model
|
17
|
-
self.memory = MemorySaver()
|
19
|
+
self.memory = memory or MemorySaver()
|
20
|
+
self._graph = None
|
21
|
+
self.llm = get_llm(model)
|
18
22
|
self.cli = RichCLI()
|
19
23
|
|
20
|
-
|
21
|
-
def graph(self):
|
24
|
+
async def _build_graph(self):
|
22
25
|
raise NotImplementedError("Subclasses must implement this method")
|
23
26
|
|
24
27
|
async def stream(self, thread_id: str, user_input: str):
|
25
|
-
|
28
|
+
if self._graph is None:
|
29
|
+
self._graph = await self._build_graph()
|
30
|
+
async for event, _ in self._graph.astream(
|
26
31
|
{"messages": [{"role": "user", "content": user_input}]},
|
27
32
|
config={"configurable": {"thread_id": thread_id}},
|
28
33
|
stream_mode="messages",
|
@@ -32,25 +37,33 @@ class BaseAgent:
|
|
32
37
|
|
33
38
|
async def stream_interactive(self, thread_id: str, user_input: str):
|
34
39
|
with self.cli.display_agent_response_streaming(self.name) as stream_updater:
|
35
|
-
async for event in self.
|
40
|
+
async for event in self.astream(thread_id, user_input):
|
36
41
|
stream_updater.update(event.content)
|
37
42
|
|
38
|
-
async def
|
39
|
-
"""
|
43
|
+
async def run(self, user_input: str, thread_id: str = str(uuid4())):
|
44
|
+
"""Run the agent"""
|
45
|
+
if not self._graph:
|
46
|
+
self._graph = await self._build_graph()
|
47
|
+
return await self._graph.ainvoke(
|
48
|
+
{"messages": [{"role": "user", "content": user_input}]},
|
49
|
+
config={"configurable": {"thread_id": thread_id}},
|
50
|
+
)
|
40
51
|
|
41
52
|
async def run_interactive(self, thread_id: str = str(uuid4())):
|
42
53
|
"""Main application loop"""
|
43
54
|
|
55
|
+
if not self._graph:
|
56
|
+
self._graph = await self._build_graph()
|
44
57
|
# Display welcome
|
45
58
|
self.cli.display_welcome(self.name)
|
46
59
|
|
47
60
|
# Main loop
|
48
61
|
while True:
|
49
62
|
try:
|
50
|
-
state = self.
|
63
|
+
state = self._graph.get_state(config={"configurable": {"thread_id": thread_id}})
|
51
64
|
if state.interrupts:
|
52
65
|
value = self.cli.handle_interrupt(state.interrupts[0])
|
53
|
-
self.
|
66
|
+
self._graph.invoke(Command(resume=value), config={"configurable": {"thread_id": thread_id}})
|
54
67
|
continue
|
55
68
|
|
56
69
|
user_input = self.cli.get_user_input()
|
universal_mcp/agents/react.py
CHANGED
@@ -1,34 +1,36 @@
|
|
1
|
+
from langgraph.checkpoint.base import BaseCheckpointSaver
|
1
2
|
from langgraph.prebuilt import create_react_agent
|
2
3
|
from loguru import logger
|
3
4
|
|
4
|
-
from universal_mcp.
|
5
|
-
from universal_mcp.tools
|
6
|
-
from universal_mcp.
|
7
|
-
|
8
|
-
from .base import BaseAgent
|
9
|
-
from .llm import get_llm
|
5
|
+
from universal_mcp.agents.base import BaseAgent
|
6
|
+
from universal_mcp.agents.tools import load_agentr_tools, load_mcp_tools
|
7
|
+
from universal_mcp.types import ToolConfig
|
10
8
|
|
11
9
|
|
12
10
|
class ReactAgent(BaseAgent):
|
13
11
|
def __init__(
|
14
|
-
self,
|
12
|
+
self,
|
13
|
+
name: str,
|
14
|
+
instructions: str,
|
15
|
+
model: str,
|
16
|
+
memory: BaseCheckpointSaver | None = None,
|
17
|
+
tools: ToolConfig | None = None,
|
18
|
+
max_iterations: int = 10,
|
19
|
+
**kwargs,
|
15
20
|
):
|
16
|
-
super().__init__(name, instructions, model)
|
17
|
-
self.
|
21
|
+
super().__init__(name, instructions, model, memory, **kwargs)
|
22
|
+
self.tools = tools
|
18
23
|
self.max_iterations = max_iterations
|
19
|
-
|
20
|
-
|
21
|
-
if tools:
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def _build_graph(self):
|
31
|
-
tools = self.tool_manager.list_tools(format=ToolFormat.LANGCHAIN) if self.tool_manager else []
|
24
|
+
|
25
|
+
async def _build_graph(self):
|
26
|
+
if self.tools:
|
27
|
+
config = self.tools.model_dump(exclude_none=True)
|
28
|
+
agentr_tools = await load_agentr_tools(config["agentrServers"]) if config.get("agentrServers") else []
|
29
|
+
mcp_tools = await load_mcp_tools(config["mcpServers"]) if config.get("mcpServers") else []
|
30
|
+
tools = agentr_tools + mcp_tools
|
31
|
+
else:
|
32
|
+
tools = []
|
33
|
+
logger.debug(f"Initialized ReactAgent: name={self.name}, model={self.model}")
|
32
34
|
return create_react_agent(
|
33
35
|
self.llm,
|
34
36
|
tools,
|
@@ -53,6 +55,10 @@ if __name__ == "__main__":
|
|
53
55
|
import asyncio
|
54
56
|
|
55
57
|
agent = ReactAgent(
|
56
|
-
"Universal React Agent",
|
58
|
+
"Universal React Agent",
|
59
|
+
instructions="",
|
60
|
+
model="gpt-4o",
|
61
|
+
tools=ToolConfig(agentrServers={"google-mail": {"tools": ["send_email"]}}),
|
57
62
|
)
|
58
|
-
asyncio.run(agent.
|
63
|
+
result = asyncio.run(agent.run(user_input="Send an email with the subject 'Hello' to john.doe@example.com"))
|
64
|
+
print(result["messages"][-1].content)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import json
|
2
|
+
|
3
|
+
from langchain_mcp_adapters.client import MultiServerMCPClient
|
4
|
+
|
5
|
+
from universal_mcp.agentr.integration import AgentrIntegration
|
6
|
+
from universal_mcp.applications import app_from_slug
|
7
|
+
from universal_mcp.tools.adapters import ToolFormat
|
8
|
+
from universal_mcp.tools.manager import ToolManager
|
9
|
+
from universal_mcp.types import ToolConfig
|
10
|
+
|
11
|
+
|
12
|
+
async def load_agentr_tools(agentr_servers: dict):
|
13
|
+
tool_manager = ToolManager()
|
14
|
+
for app_name, tool_names in agentr_servers.items():
|
15
|
+
app = app_from_slug(app_name)
|
16
|
+
integration = AgentrIntegration(name=app_name)
|
17
|
+
app_instance = app(integration=integration)
|
18
|
+
tool_manager.register_tools_from_app(app_instance, tool_names=tool_names["tools"])
|
19
|
+
tools = tool_manager.list_tools(format=ToolFormat.LANGCHAIN)
|
20
|
+
return tools
|
21
|
+
|
22
|
+
|
23
|
+
async def load_mcp_tools(mcp_servers: dict):
|
24
|
+
client = MultiServerMCPClient(mcp_servers)
|
25
|
+
tools = await client.get_tools()
|
26
|
+
return tools
|
27
|
+
|
28
|
+
|
29
|
+
async def load_tools(path: str) -> ToolConfig:
|
30
|
+
with open(path) as f:
|
31
|
+
data = json.load(f)
|
32
|
+
config = ToolConfig.model_validate(data)
|
33
|
+
agentr_tools = await load_agentr_tools(config.model_dump(exclude_none=True)["agentrServers"])
|
34
|
+
mcp_tools = await load_mcp_tools(config.model_dump(exclude_none=True)["mcpServers"])
|
35
|
+
return agentr_tools + mcp_tools
|
universal_mcp/config.py
CHANGED
@@ -176,96 +176,3 @@ class ServerConfig(BaseSettings):
|
|
176
176
|
with open(path) as f:
|
177
177
|
data = json.load(f)
|
178
178
|
return cls.model_validate(data)
|
179
|
-
|
180
|
-
|
181
|
-
class ClientTransportConfig(BaseModel):
|
182
|
-
"""Configuration for how an MCP client connects to an MCP server.
|
183
|
-
|
184
|
-
Specifies the transport protocol and its associated parameters, such as
|
185
|
-
the command for stdio, URL for HTTP-based transports (SSE, streamable_http),
|
186
|
-
and any necessary headers or environment variables.
|
187
|
-
"""
|
188
|
-
|
189
|
-
transport: str | None = Field(
|
190
|
-
default=None,
|
191
|
-
description="The transport protocol (e.g., 'stdio', 'sse', 'streamable_http'). Auto-detected in model_validate if not set.",
|
192
|
-
)
|
193
|
-
command: str | None = Field(
|
194
|
-
default=None, description="The command to execute for 'stdio' transport (e.g., 'python -m mcp_server.run')."
|
195
|
-
)
|
196
|
-
args: list[str] = Field(default=[], description="List of arguments for the 'stdio' command.")
|
197
|
-
env: dict[str, str] = Field(default={}, description="Environment variables to set for the 'stdio' command.")
|
198
|
-
url: str | None = Field(default=None, description="The URL for 'sse' or 'streamable_http' transport.")
|
199
|
-
headers: dict[str, str] = Field(
|
200
|
-
default={}, description="HTTP headers to include for 'sse' or 'streamable_http' transport."
|
201
|
-
)
|
202
|
-
|
203
|
-
@model_validator(mode="after")
|
204
|
-
def determine_transport_if_not_set(self) -> Self:
|
205
|
-
"""Determines and sets the transport type if not explicitly provided.
|
206
|
-
|
207
|
-
- If `command` is present, transport is set to 'stdio'.
|
208
|
-
- If `url` is present, transport is 'streamable_http' if URL ends with '/mcp',
|
209
|
-
otherwise 'sse' if URL ends with '/sse'.
|
210
|
-
- Raises ValueError if transport cannot be determined or if neither
|
211
|
-
`command` nor `url` is provided.
|
212
|
-
"""
|
213
|
-
if self.command:
|
214
|
-
self.transport = "stdio"
|
215
|
-
elif self.url:
|
216
|
-
# Remove search params from url
|
217
|
-
url = self.url.split("?")[0]
|
218
|
-
if url.rstrip("/").endswith("mcp"):
|
219
|
-
self.transport = "streamable_http"
|
220
|
-
elif url.rstrip("/").endswith("sse"):
|
221
|
-
self.transport = "sse"
|
222
|
-
else:
|
223
|
-
raise ValueError(f"Unknown transport: {self.url}")
|
224
|
-
else:
|
225
|
-
raise ValueError("Either command or url must be provided")
|
226
|
-
return self
|
227
|
-
|
228
|
-
|
229
|
-
class ClientConfig(BaseSettings):
|
230
|
-
"""Configuration for a client application that interacts with MCP servers and an LLM.
|
231
|
-
|
232
|
-
Defines connections to one or more MCP servers (via `mcpServers`) and
|
233
|
-
optionally, settings for an LLM to be used by the client (e.g., by an agent).
|
234
|
-
"""
|
235
|
-
|
236
|
-
mcpServers: dict[str, ClientTransportConfig] = Field(
|
237
|
-
...,
|
238
|
-
description="Dictionary of MCP server connections. Keys are descriptive names for the server, values are `ClientTransportConfig` objects defining how to connect to each server.",
|
239
|
-
)
|
240
|
-
apps: list[AppConfig] = Field(
|
241
|
-
default=[],
|
242
|
-
description="List of application configurations to load",
|
243
|
-
)
|
244
|
-
store: StoreConfig | None = Field(
|
245
|
-
default=None,
|
246
|
-
description="Default credential store configuration for applications that do not define their own specific store.",
|
247
|
-
)
|
248
|
-
model: str = Field(
|
249
|
-
default="openrouter/auto",
|
250
|
-
description="The model to use for the LLM.",
|
251
|
-
)
|
252
|
-
|
253
|
-
@classmethod
|
254
|
-
def load_json_config(cls, path: Path) -> Self:
|
255
|
-
"""Loads client configuration from a JSON file.
|
256
|
-
|
257
|
-
Args:
|
258
|
-
path (str, optional): The path to the JSON configuration file.
|
259
|
-
Defaults to "client_config.json".
|
260
|
-
|
261
|
-
Returns:
|
262
|
-
ClientConfig: An instance of ClientConfig populated with data
|
263
|
-
from the JSON file.
|
264
|
-
"""
|
265
|
-
with open(path) as f:
|
266
|
-
data = json.load(f)
|
267
|
-
return cls.model_validate(data)
|
268
|
-
|
269
|
-
def save_json_config(self, path: str) -> None:
|
270
|
-
with open(path, "w") as f:
|
271
|
-
json.dump(self.model_dump(), f, indent=4)
|
universal_mcp/tools/manager.py
CHANGED
@@ -12,12 +12,7 @@ from universal_mcp.tools.adapters import (
|
|
12
12
|
convert_tool_to_openai_tool,
|
13
13
|
)
|
14
14
|
from universal_mcp.tools.tools import Tool
|
15
|
-
from universal_mcp.types import ToolFormat
|
16
|
-
|
17
|
-
# Constants
|
18
|
-
DEFAULT_IMPORTANT_TAG = "important"
|
19
|
-
TOOL_NAME_SEPARATOR = "_"
|
20
|
-
DEFAULT_APP_NAME = "common"
|
15
|
+
from universal_mcp.types import DEFAULT_APP_NAME, DEFAULT_IMPORTANT_TAG, TOOL_NAME_SEPARATOR, ToolFormat
|
21
16
|
|
22
17
|
|
23
18
|
def _get_app_and_tool_name(tool_name: str) -> tuple[str, str]:
|
@@ -31,8 +26,13 @@ def _get_app_and_tool_name(tool_name: str) -> tuple[str, str]:
|
|
31
26
|
return app_name, tool_name_without_app_name
|
32
27
|
|
33
28
|
|
29
|
+
def _sanitize_tool_names(tool_names: list[str]) -> list[str]:
|
30
|
+
"""Sanitize tool names by removing empty strings and converting to lowercase."""
|
31
|
+
return [_get_app_and_tool_name(name)[1].lower() for name in tool_names if name]
|
32
|
+
|
33
|
+
|
34
34
|
def _filter_by_name(tools: list[Tool], tool_names: list[str] | None) -> list[Tool]:
|
35
|
-
"""Filter tools by name using
|
35
|
+
"""Filter tools by name using set comparison for efficient matching.
|
36
36
|
|
37
37
|
Args:
|
38
38
|
tools: List of tools to filter.
|
@@ -45,16 +45,14 @@ def _filter_by_name(tools: list[Tool], tool_names: list[str] | None) -> list[Too
|
|
45
45
|
return tools
|
46
46
|
|
47
47
|
logger.debug(f"Filtering tools by names: {tool_names}")
|
48
|
-
|
49
|
-
|
48
|
+
tool_names_set = set(_sanitize_tool_names(tool_names))
|
49
|
+
logger.debug(f"Tool names set: {tool_names_set}")
|
50
50
|
filtered_tools = []
|
51
51
|
for tool in tools:
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
break
|
57
|
-
|
52
|
+
if tool.tool_name.lower() in tool_names_set:
|
53
|
+
filtered_tools.append(tool)
|
54
|
+
logger.debug(f"Tool '{tool.name}' matched name filter")
|
55
|
+
logger.debug(f"Filtered tools: {[tool.name for tool in filtered_tools]}")
|
58
56
|
return filtered_tools
|
59
57
|
|
60
58
|
|
@@ -200,11 +198,6 @@ class ToolManager:
|
|
200
198
|
app_name: Application name to group the tools under.
|
201
199
|
"""
|
202
200
|
for tool in tools:
|
203
|
-
app_name, tool_name = _get_app_and_tool_name(tool.name)
|
204
|
-
|
205
|
-
# Add prefix to tool name, if not already present
|
206
|
-
tool.name = f"{app_name}{TOOL_NAME_SEPARATOR}{tool_name}"
|
207
|
-
tool.tags.append(app_name)
|
208
201
|
self.add_tool(tool)
|
209
202
|
|
210
203
|
def remove_tool(self, name: str) -> bool:
|
@@ -259,14 +252,14 @@ class ToolManager:
|
|
259
252
|
|
260
253
|
try:
|
261
254
|
tool_instance = Tool.from_function(function)
|
262
|
-
tool_instance.
|
255
|
+
tool_instance.app_name = app.name
|
263
256
|
if app.name not in tool_instance.tags:
|
264
257
|
tool_instance.tags.append(app.name)
|
265
258
|
tools.append(tool_instance)
|
266
259
|
except Exception as e:
|
267
260
|
tool_name = getattr(function, "__name__", "unknown")
|
268
261
|
logger.error(f"Failed to create Tool from '{tool_name}' in {app.name}: {e}")
|
269
|
-
|
262
|
+
print([tool.name for tool in tools])
|
270
263
|
if tags:
|
271
264
|
tools = _filter_by_tags(tools, tags)
|
272
265
|
|
universal_mcp/tools/tools.py
CHANGED
@@ -7,6 +7,7 @@ from pydantic import BaseModel, Field, create_model
|
|
7
7
|
|
8
8
|
from universal_mcp.exceptions import NotAuthorizedError, ToolError
|
9
9
|
from universal_mcp.tools.docstring_parser import parse_docstring
|
10
|
+
from universal_mcp.types import TOOL_NAME_SEPARATOR
|
10
11
|
|
11
12
|
from .func_metadata import FuncMetadata
|
12
13
|
|
@@ -31,8 +32,9 @@ class Tool(BaseModel):
|
|
31
32
|
"""Internal tool registration info."""
|
32
33
|
|
33
34
|
fn: Callable[..., Any] = Field(exclude=True)
|
34
|
-
|
35
|
-
|
35
|
+
app_name: str | None = Field(default=None, description="Name of the app that the tool belongs to")
|
36
|
+
tool_name: str = Field(description="Name of the tool")
|
37
|
+
description: str | None = Field(default=None, description="Summary line from the tool's docstring")
|
36
38
|
args_description: dict[str, str] = Field(
|
37
39
|
default_factory=dict, description="Descriptions of arguments from the docstring"
|
38
40
|
)
|
@@ -44,11 +46,15 @@ class Tool(BaseModel):
|
|
44
46
|
tags: list[str] = Field(default_factory=list, description="Tags for categorizing the tool")
|
45
47
|
parameters: dict[str, Any] = Field(description="JSON schema for tool parameters")
|
46
48
|
output_schema: dict[str, Any] | None = Field(default=None, description="JSON schema for tool output")
|
47
|
-
fn_metadata: FuncMetadata = Field(
|
48
|
-
description="Metadata about the function including a pydantic model for tool arguments"
|
49
|
+
fn_metadata: FuncMetadata | None = Field(
|
50
|
+
default=None, description="Metadata about the function including a pydantic model for tool arguments"
|
49
51
|
)
|
50
52
|
is_async: bool = Field(description="Whether the tool is async")
|
51
53
|
|
54
|
+
@property
|
55
|
+
def name(self) -> str:
|
56
|
+
return f"{self.app_name}{TOOL_NAME_SEPARATOR}{self.tool_name}" if self.app_name else self.tool_name
|
57
|
+
|
52
58
|
@classmethod
|
53
59
|
def from_function(
|
54
60
|
cls,
|
@@ -81,7 +87,7 @@ class Tool(BaseModel):
|
|
81
87
|
|
82
88
|
return cls(
|
83
89
|
fn=fn,
|
84
|
-
|
90
|
+
tool_name=func_name,
|
85
91
|
description=parsed_doc["summary"],
|
86
92
|
args_description=simple_args_descriptions,
|
87
93
|
returns_description=parsed_doc["returns"],
|
universal_mcp/types.py
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
from enum import Enum
|
2
|
+
from typing import Literal
|
3
|
+
|
4
|
+
from pydantic import BaseModel
|
5
|
+
|
6
|
+
# Constants
|
7
|
+
DEFAULT_IMPORTANT_TAG = "important"
|
8
|
+
TOOL_NAME_SEPARATOR = "__"
|
9
|
+
DEFAULT_APP_NAME = "common"
|
2
10
|
|
3
11
|
|
4
12
|
class ToolFormat(str, Enum):
|
@@ -8,3 +16,20 @@ class ToolFormat(str, Enum):
|
|
8
16
|
MCP = "mcp"
|
9
17
|
LANGCHAIN = "langchain"
|
10
18
|
OPENAI = "openai"
|
19
|
+
|
20
|
+
|
21
|
+
class AgentrConnection(BaseModel):
|
22
|
+
tools: list[str]
|
23
|
+
|
24
|
+
|
25
|
+
class MCPConnection(BaseModel):
|
26
|
+
transport: Literal["stdio", "sse", "streamable-http"]
|
27
|
+
command: str | None = None
|
28
|
+
args: list[str] | None = None
|
29
|
+
url: str | None = None
|
30
|
+
headers: dict[str, str] | None = None
|
31
|
+
|
32
|
+
|
33
|
+
class ToolConfig(BaseModel):
|
34
|
+
mcpServers: dict[str, MCPConnection] | None = None
|
35
|
+
agentrServers: dict[str, AgentrConnection] | None = None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: universal-mcp
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.24rc6
|
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
|
@@ -8,7 +8,7 @@ License-File: LICENSE
|
|
8
8
|
Requires-Python: >=3.11
|
9
9
|
Requires-Dist: black>=25.1.0
|
10
10
|
Requires-Dist: cookiecutter>=2.6.0
|
11
|
-
Requires-Dist: gql
|
11
|
+
Requires-Dist: gql>=4.0.0
|
12
12
|
Requires-Dist: jinja2>=3.1.3
|
13
13
|
Requires-Dist: jsonref>=1.1.0
|
14
14
|
Requires-Dist: keyring>=25.6.0
|
@@ -19,24 +19,21 @@ Requires-Dist: langgraph>=0.5.2
|
|
19
19
|
Requires-Dist: langsmith>=0.4.5
|
20
20
|
Requires-Dist: loguru>=0.7.3
|
21
21
|
Requires-Dist: mcp>=1.10.0
|
22
|
-
Requires-Dist: mkdocs-material>=9.6.15
|
23
|
-
Requires-Dist: mkdocs>=1.6.1
|
24
22
|
Requires-Dist: posthog>=3.24.0
|
25
23
|
Requires-Dist: pydantic-settings>=2.8.1
|
26
24
|
Requires-Dist: pydantic>=2.11.1
|
27
25
|
Requires-Dist: pyyaml>=6.0.2
|
28
26
|
Requires-Dist: rich>=14.0.0
|
29
27
|
Requires-Dist: streamlit>=1.46.1
|
30
|
-
Requires-Dist: ty>=0.0.1a17
|
31
28
|
Requires-Dist: typer>=0.15.2
|
32
29
|
Provides-Extra: dev
|
33
30
|
Requires-Dist: litellm>=1.30.7; extra == 'dev'
|
34
|
-
Requires-Dist: mypy>=1.16.0; extra == 'dev'
|
35
31
|
Requires-Dist: pre-commit>=4.2.0; extra == 'dev'
|
36
32
|
Requires-Dist: pyright>=1.1.398; extra == 'dev'
|
37
33
|
Requires-Dist: pytest-asyncio>=0.26.0; extra == 'dev'
|
38
34
|
Requires-Dist: pytest>=8.3.5; extra == 'dev'
|
39
35
|
Requires-Dist: ruff>=0.11.4; extra == 'dev'
|
36
|
+
Requires-Dist: ty>=0.0.1a17; extra == 'dev'
|
40
37
|
Provides-Extra: docs
|
41
38
|
Requires-Dist: mkdocs-glightbox>=0.4.0; extra == 'docs'
|
42
39
|
Requires-Dist: mkdocs-material[imaging]>=9.5.45; extra == 'docs'
|
@@ -1,11 +1,11 @@
|
|
1
1
|
universal_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
universal_mcp/analytics.py,sha256=RzS88HSvJRGMjdJeLHnOgWzfKSb1jVnvOcD7NHqfERw,3733
|
3
3
|
universal_mcp/cli.py,sha256=pPnIWLhSrLV9ukI8YAg2znehCR3VovhEkmh8XkRT3MU,2505
|
4
|
-
universal_mcp/config.py,sha256=
|
4
|
+
universal_mcp/config.py,sha256=lOlDAgQMT7f6VymmsuCP9sYLlxGKj0hDF3hFcJ2nzS4,8135
|
5
5
|
universal_mcp/exceptions.py,sha256=Uen8UFgLHGlSwXgRUyF-nhqTwdiBuL3okgBVRV2AgtA,2150
|
6
6
|
universal_mcp/logger.py,sha256=VmH_83efpErLEDTJqz55Dp0dioTXfGvMBLZUx5smOLc,2116
|
7
7
|
universal_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
universal_mcp/types.py,sha256=
|
8
|
+
universal_mcp/types.py,sha256=jeUEkUnwdGWo3T_qSRSF83u0fYpuydaWzdKlCYBlCQA,770
|
9
9
|
universal_mcp/agentr/README.md,sha256=xXM8JzPyrM2__pGhxHrGEUn9uP2y2bdF00wwcQtBUCI,6441
|
10
10
|
universal_mcp/agentr/__init__.py,sha256=ogOhH_OJwkoUZu_2nQJc7-vEGmYQxEjOE511-6ubrX0,217
|
11
11
|
universal_mcp/agentr/agentr.py,sha256=JfawuREfXAyeNUE7o58DzTPhmQXuwsB_Da7c1Gf3Qxw,1059
|
@@ -15,12 +15,13 @@ universal_mcp/agentr/registry.py,sha256=b9sr5JyT3HLj3e7GFpdXpT7ofGwLQc--y8k2DqF5
|
|
15
15
|
universal_mcp/agentr/server.py,sha256=bIPmHMiKKwnUYnxmfZVRh1thcn7Rytm_-bNiXTfANzc,2098
|
16
16
|
universal_mcp/agents/__init__.py,sha256=vgixOLTCcCmSweENV7GSAuOPyHXlE4XAbvOXyr4MrRA,185
|
17
17
|
universal_mcp/agents/auto.py,sha256=o__71BCOHSfaj7Xt0PhsamVXdeP4o7irhtmu1q6-3Fo,25336
|
18
|
-
universal_mcp/agents/base.py,sha256=
|
18
|
+
universal_mcp/agents/base.py,sha256=aplcZ-OKva3hFMB5uzoAPCB0ZDh3BL3FlJV39sJYYZ8,4057
|
19
19
|
universal_mcp/agents/cli.py,sha256=7GdRBpu9rhZPiC2vaNQXWI7K-0yCnvdlmE0IFpvy2Gk,539
|
20
20
|
universal_mcp/agents/hil.py,sha256=CTgX7CoFEyTFIaNaL-id2WALOPd0VBb79pHkQK8quM8,3671
|
21
21
|
universal_mcp/agents/llm.py,sha256=YNxN43bVhGfdYs09yPkdkGCKJkj-2UNqkB1EFmtnUS4,309
|
22
|
-
universal_mcp/agents/react.py,sha256=
|
22
|
+
universal_mcp/agents/react.py,sha256=cpE4wzySnyEdhz-c1T1FDA3w68nRByz7yWFt8FefUBo,2361
|
23
23
|
universal_mcp/agents/simple.py,sha256=UfmQIIff--_Y0DQ6oivRciHqSZvRqy_qwQn_UYVzYy8,1146
|
24
|
+
universal_mcp/agents/tools.py,sha256=7Vdw0VZYxXVAzAYSpRKWHzVl9Ll6NOnVRlc4cTXguUQ,1335
|
24
25
|
universal_mcp/agents/utils.py,sha256=7kwFpD0Rv6JqHG-LlNCVwSu_xRX-N119mUmiBroHJL4,4109
|
25
26
|
universal_mcp/agents/codeact/__init__.py,sha256=5D_I3lI_3tWjZERRoFav_bPe9UDaJ53pDzZYtyixg3E,10097
|
26
27
|
universal_mcp/agents/codeact/sandbox.py,sha256=lGRzhuXTHCB1qauuOI3bH1-fPTsyL6Lf9EmMIz4C2xQ,1039
|
@@ -42,9 +43,9 @@ universal_mcp/tools/__init__.py,sha256=jC8hsqfTdtn32yU57AVFUXiU3ZmUOCfCERSCaNEIH
|
|
42
43
|
universal_mcp/tools/adapters.py,sha256=YJ2oqgc8JgmtsdRRtvO-PO0Q0bKqTJ4Y3J6yxlESoTo,3947
|
43
44
|
universal_mcp/tools/docstring_parser.py,sha256=efEOE-ME7G5Jbbzpn7pN2xNuyu2M5zfZ1Tqu1lRB0Gk,8392
|
44
45
|
universal_mcp/tools/func_metadata.py,sha256=F4jd--hoZWKPBbZihVtluYKUsIdXdq4a0VWRgMl5k-Q,10838
|
45
|
-
universal_mcp/tools/manager.py,sha256=
|
46
|
+
universal_mcp/tools/manager.py,sha256=24Rkn5Uvv_AuYAtjeMq986bJ7uzTaGE1290uB9eDtRE,10435
|
46
47
|
universal_mcp/tools/registry.py,sha256=XsmVZL1rY5XgIBPTmvKKBWFLAvB3d9LfYMb11b4wSPI,1169
|
47
|
-
universal_mcp/tools/tools.py,sha256=
|
48
|
+
universal_mcp/tools/tools.py,sha256=Lk-wUO3rfhwdxaRANtC7lQr5fXi7nclf0oHzxNAb79Q,4927
|
48
49
|
universal_mcp/utils/__init__.py,sha256=8wi4PGWu-SrFjNJ8U7fr2iFJ1ktqlDmSKj1xYd7KSDc,41
|
49
50
|
universal_mcp/utils/common.py,sha256=3aJK3AnBkmYf-dbsFLaEu_dGuXQ0Qi2HuqYTueLVhXQ,10968
|
50
51
|
universal_mcp/utils/installation.py,sha256=PU_GfHPqzkumKk-xG4L9CkBzSmABxmchwblZkx-zY-I,7204
|
@@ -64,8 +65,8 @@ universal_mcp/utils/openapi/readme.py,sha256=R2Jp7DUXYNsXPDV6eFTkLiy7MXbSULUj1vH
|
|
64
65
|
universal_mcp/utils/openapi/test_generator.py,sha256=h44gQXEXmrw4pD3-XNHKB7T9c2lDomqrJxVO6oszCqM,12186
|
65
66
|
universal_mcp/utils/templates/README.md.j2,sha256=Mrm181YX-o_-WEfKs01Bi2RJy43rBiq2j6fTtbWgbTA,401
|
66
67
|
universal_mcp/utils/templates/api_client.py.j2,sha256=972Im7LNUAq3yZTfwDcgivnb-b8u6_JLKWXwoIwXXXQ,908
|
67
|
-
universal_mcp-0.1.
|
68
|
-
universal_mcp-0.1.
|
69
|
-
universal_mcp-0.1.
|
70
|
-
universal_mcp-0.1.
|
71
|
-
universal_mcp-0.1.
|
68
|
+
universal_mcp-0.1.24rc6.dist-info/METADATA,sha256=5KFnUe9auDhLti6G6uogy93a3RuJIBc9un01LNoVBgU,3015
|
69
|
+
universal_mcp-0.1.24rc6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
70
|
+
universal_mcp-0.1.24rc6.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
|
71
|
+
universal_mcp-0.1.24rc6.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
|
72
|
+
universal_mcp-0.1.24rc6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|