universal-mcp 0.1.23rc2__py3-none-any.whl → 0.1.24rc2__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/analytics.py +43 -11
- universal_mcp/applications/application.py +186 -132
- universal_mcp/applications/sample_tool_app.py +80 -0
- universal_mcp/cli.py +5 -229
- universal_mcp/client/agents/__init__.py +4 -0
- universal_mcp/client/agents/base.py +38 -0
- universal_mcp/client/agents/llm.py +115 -0
- universal_mcp/client/agents/react.py +67 -0
- universal_mcp/client/cli.py +181 -0
- universal_mcp/client/oauth.py +122 -18
- universal_mcp/client/token_store.py +62 -3
- universal_mcp/client/{client.py → transport.py} +127 -48
- universal_mcp/config.py +160 -46
- universal_mcp/exceptions.py +50 -6
- universal_mcp/integrations/__init__.py +1 -4
- universal_mcp/integrations/integration.py +220 -121
- universal_mcp/servers/__init__.py +1 -1
- universal_mcp/servers/server.py +114 -247
- universal_mcp/stores/store.py +126 -93
- universal_mcp/tools/func_metadata.py +1 -1
- universal_mcp/tools/manager.py +15 -3
- universal_mcp/tools/tools.py +2 -2
- universal_mcp/utils/agentr.py +3 -4
- universal_mcp/utils/installation.py +3 -4
- universal_mcp/utils/openapi/api_generator.py +28 -2
- universal_mcp/utils/openapi/api_splitter.py +0 -1
- universal_mcp/utils/openapi/cli.py +243 -0
- universal_mcp/utils/openapi/filters.py +114 -0
- universal_mcp/utils/openapi/openapi.py +31 -2
- universal_mcp/utils/openapi/preprocessor.py +62 -7
- universal_mcp/utils/prompts.py +787 -0
- universal_mcp/utils/singleton.py +4 -1
- universal_mcp/utils/testing.py +6 -6
- universal_mcp-0.1.24rc2.dist-info/METADATA +54 -0
- universal_mcp-0.1.24rc2.dist-info/RECORD +53 -0
- universal_mcp/applications/README.md +0 -122
- universal_mcp/client/__main__.py +0 -30
- universal_mcp/client/agent.py +0 -96
- universal_mcp/integrations/README.md +0 -25
- universal_mcp/servers/README.md +0 -79
- universal_mcp/stores/README.md +0 -74
- universal_mcp/tools/README.md +0 -86
- universal_mcp-0.1.23rc2.dist-info/METADATA +0 -283
- universal_mcp-0.1.23rc2.dist-info/RECORD +0 -51
- /universal_mcp/{utils → tools}/docstring_parser.py +0 -0
- {universal_mcp-0.1.23rc2.dist-info → universal_mcp-0.1.24rc2.dist-info}/WHEEL +0 -0
- {universal_mcp-0.1.23rc2.dist-info → universal_mcp-0.1.24rc2.dist-info}/entry_points.txt +0 -0
- {universal_mcp-0.1.23rc2.dist-info → universal_mcp-0.1.24rc2.dist-info}/licenses/LICENSE +0 -0
universal_mcp/utils/singleton.py
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
|
1
4
|
class Singleton(type):
|
2
5
|
"""Metaclass that ensures only one instance of a class exists.
|
3
6
|
|
@@ -15,7 +18,7 @@ class Singleton(type):
|
|
15
18
|
assert a is b # True
|
16
19
|
"""
|
17
20
|
|
18
|
-
_instances = {}
|
21
|
+
_instances: dict[type, Any] = {}
|
19
22
|
|
20
23
|
def __call__(cls, *args, **kwargs):
|
21
24
|
if cls not in cls._instances:
|
universal_mcp/utils/testing.py
CHANGED
@@ -5,9 +5,9 @@ from universal_mcp.tools.tools import Tool
|
|
5
5
|
|
6
6
|
def check_application_instance(app_instance, app_name):
|
7
7
|
assert app_instance is not None, f"Application object is None for {app_name}"
|
8
|
-
assert (
|
9
|
-
app_instance.name
|
10
|
-
)
|
8
|
+
assert app_instance.name == app_name, (
|
9
|
+
f"Application instance name '{app_instance.name}' does not match expected name '{app_name}'"
|
10
|
+
)
|
11
11
|
|
12
12
|
tools = app_instance.list_tools()
|
13
13
|
logger.info(f"Tools for {app_name}: {len(tools)}")
|
@@ -19,9 +19,9 @@ def check_application_instance(app_instance, app_name):
|
|
19
19
|
|
20
20
|
for tool in tools:
|
21
21
|
assert tool.name is not None, f"Tool name is None for a tool in {app_name}"
|
22
|
-
assert (
|
23
|
-
|
24
|
-
)
|
22
|
+
assert 0 < len(tool.name) <= 48, (
|
23
|
+
f"Tool name '{tool.name}' for {app_name} has invalid length (must be between 1 and 47 characters)"
|
24
|
+
)
|
25
25
|
assert tool.description is not None, f"Tool description is None for tool '{tool.name}' in {app_name}"
|
26
26
|
# assert 0 < len(tool.description) <= 255, f"Tool description for '{tool.name}' in {app_name} has invalid length (must be between 1 and 255 characters)"
|
27
27
|
assert tool.name not in seen_names, f"Duplicate tool name: '{tool.name}' found for {app_name}"
|
@@ -0,0 +1,54 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: universal-mcp
|
3
|
+
Version: 0.1.24rc2
|
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
|
+
Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
|
6
|
+
License: MIT
|
7
|
+
License-File: LICENSE
|
8
|
+
Requires-Python: >=3.11
|
9
|
+
Requires-Dist: black>=25.1.0
|
10
|
+
Requires-Dist: cookiecutter>=2.6.0
|
11
|
+
Requires-Dist: gql[all]>=3.5.2
|
12
|
+
Requires-Dist: jinja2>=3.1.3
|
13
|
+
Requires-Dist: jsonref>=1.1.0
|
14
|
+
Requires-Dist: keyring>=25.6.0
|
15
|
+
Requires-Dist: loguru>=0.7.3
|
16
|
+
Requires-Dist: mcp>=1.9.3
|
17
|
+
Requires-Dist: posthog>=3.24.0
|
18
|
+
Requires-Dist: pydantic-settings>=2.8.1
|
19
|
+
Requires-Dist: pydantic>=2.11.1
|
20
|
+
Requires-Dist: pyyaml>=6.0.2
|
21
|
+
Requires-Dist: rich>=14.0.0
|
22
|
+
Requires-Dist: typer>=0.15.2
|
23
|
+
Provides-Extra: dev
|
24
|
+
Requires-Dist: litellm>=1.30.7; extra == 'dev'
|
25
|
+
Requires-Dist: mypy>=1.16.0; extra == 'dev'
|
26
|
+
Requires-Dist: pre-commit>=4.2.0; extra == 'dev'
|
27
|
+
Requires-Dist: pyright>=1.1.398; extra == 'dev'
|
28
|
+
Requires-Dist: pytest-asyncio>=0.26.0; extra == 'dev'
|
29
|
+
Requires-Dist: pytest>=8.3.5; extra == 'dev'
|
30
|
+
Requires-Dist: ruff>=0.11.4; extra == 'dev'
|
31
|
+
Description-Content-Type: text/markdown
|
32
|
+
|
33
|
+
# Universal MCP
|
34
|
+
|
35
|
+
Universal MCP acts as a middleware layer for your API applications, enabling seamless integration with various services through the Model Control Protocol (MCP). It simplifies credential management, authorization, dynamic app enablement, and provides a robust framework for building and managing AI-powered tools.
|
36
|
+
|
37
|
+
## Documentation
|
38
|
+
|
39
|
+
The primary documentation for Universal MCP is available in `/docs` folder in this repository.
|
40
|
+
|
41
|
+
Please refer to the following for more detailed information:
|
42
|
+
|
43
|
+
* **[Main Documentation](docs/index.md)**: For an overview of the project, features, quick start, and installation.
|
44
|
+
* **[Playground Usage](docs/playground.md)**: For instructions on using the interactive playground.
|
45
|
+
* **[Applications Framework](docs/applications.md)**: For details on the applications module.
|
46
|
+
* **[Integrations & Authentication](docs/integrations.md)**: For information on integration types.
|
47
|
+
* **[Server Implementations](docs/servers.md)**: For details on server types.
|
48
|
+
* **[Credential Stores](docs/stores.md)**: For information on credential stores.
|
49
|
+
* **[Tools Framework](docs/tools_framework.md)**: For details on the tool management system.
|
50
|
+
* **[Contributing Guidelines](CONTRIBUTING.md)**: For information on how to contribute to the project.
|
51
|
+
|
52
|
+
## License
|
53
|
+
|
54
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
@@ -0,0 +1,53 @@
|
|
1
|
+
universal_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
universal_mcp/analytics.py,sha256=8AjqAnqacos-1R9D6gf_eMbKFlBBIFSM9yv12AAnxlE,3961
|
3
|
+
universal_mcp/cli.py,sha256=aVTUGImHpEklW0OpLBLCYyvjv3M2Prf1ntkwmlG-Jxg,2238
|
4
|
+
universal_mcp/config.py,sha256=3CGLbwyhr4zq1kQ7vHIO4f6PyfmANFa9RVZEMVgSJ8U,10651
|
5
|
+
universal_mcp/exceptions.py,sha256=bf45HkNY-RVYzv8l_nPaxS5P2UCFww_oZmq508TMKgY,2070
|
6
|
+
universal_mcp/logger.py,sha256=VmH_83efpErLEDTJqz55Dp0dioTXfGvMBLZUx5smOLc,2116
|
7
|
+
universal_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
universal_mcp/applications/__init__.py,sha256=l19_sMs5766VFWU_7O2niamvvvfQOteysqylbqvjjGQ,3500
|
9
|
+
universal_mcp/applications/application.py,sha256=di4vuvAiOgVophzlvLiyVILdR8hPuSLS46YLQDEVq-c,23823
|
10
|
+
universal_mcp/applications/sample_tool_app.py,sha256=YfZGE6F-cqqJGLU3TxOk4fYlAuf-kCOdBw03S-5VcpE,2760
|
11
|
+
universal_mcp/client/cli.py,sha256=dZ_Uwp9grRN2UWOuE2PQ9eUAyGelNGI4GQkkliD_6Vs,6242
|
12
|
+
universal_mcp/client/oauth.py,sha256=O00zOUfQxINaruFU2zt-64DIR1_mAqrY8ykLQo-teJU,8679
|
13
|
+
universal_mcp/client/token_store.py,sha256=6VAzjzJG49wYvmEDqksFvb-fVqdjHIKWv7yYyh_AuF8,3912
|
14
|
+
universal_mcp/client/transport.py,sha256=xgAKBJ1-yCcTtl9cxzJgRn6to5Y9EvCwLc_WpDck3Dg,11838
|
15
|
+
universal_mcp/client/agents/__init__.py,sha256=ZeoMWi6C6ZaP28EzPhjTFlreZUP-FGo__VPgnKnU4uw,121
|
16
|
+
universal_mcp/client/agents/base.py,sha256=i8oAILtVoW4kHAx95fd8IaioqYrD1aqoWSRjUl05TaY,953
|
17
|
+
universal_mcp/client/agents/llm.py,sha256=O1cVPlXPhXb-x7GFIZ4dYFdB_Wd1eWHTTEV9FoBl_OE,5062
|
18
|
+
universal_mcp/client/agents/react.py,sha256=lI654OT-3gXwrTjbt0DTbB-tuim4ahqZ7vAFta_A6NY,2719
|
19
|
+
universal_mcp/integrations/__init__.py,sha256=UHno85kYa9nCjep31WpJlLu6ObNQxHzp4T57Q5eNILE,770
|
20
|
+
universal_mcp/integrations/integration.py,sha256=E-pC_VioPoJwyw5d_RquE7k2ygvXrAnphNzNt4NrOS0,19823
|
21
|
+
universal_mcp/servers/__init__.py,sha256=BbtZxl69EQcs9PpxBCkwa-vJKcfESgBfXQ5UYlkRQTo,542
|
22
|
+
universal_mcp/servers/server.py,sha256=CNLlVxNosqBipk1_WD0zQJz-MZDiK5k7d_tZMH3NpAQ,7542
|
23
|
+
universal_mcp/stores/__init__.py,sha256=quvuwhZnpiSLuojf0NfmBx2xpaCulv3fbKtKaSCEmuM,603
|
24
|
+
universal_mcp/stores/store.py,sha256=yWbEGZb53z3fpVyqGWbes63z1CtIzC_IuM49OXy__UY,10137
|
25
|
+
universal_mcp/tools/__init__.py,sha256=Fatza_R0qYWmNF1WQSfUZZKQFu5qf-16JhZzdmyx3KY,333
|
26
|
+
universal_mcp/tools/adapters.py,sha256=rnicV_WBgNe0WqVG60ms0o92BoRTRqd_C9jMMndx47c,3461
|
27
|
+
universal_mcp/tools/docstring_parser.py,sha256=efEOE-ME7G5Jbbzpn7pN2xNuyu2M5zfZ1Tqu1lRB0Gk,8392
|
28
|
+
universal_mcp/tools/func_metadata.py,sha256=F4jd--hoZWKPBbZihVtluYKUsIdXdq4a0VWRgMl5k-Q,10838
|
29
|
+
universal_mcp/tools/manager.py,sha256=Zpwr95rj4CvCRMkdX3_q3kZ9fYm8SkuLa-UkURG3WZQ,11740
|
30
|
+
universal_mcp/tools/tools.py,sha256=pHehD4dqaTSnMBNhsj0Gpb4_L8OIy1rlZOITIDt7cnU,3730
|
31
|
+
universal_mcp/utils/__init__.py,sha256=8wi4PGWu-SrFjNJ8U7fr2iFJ1ktqlDmSKj1xYd7KSDc,41
|
32
|
+
universal_mcp/utils/agentr.py,sha256=8G9ZGQEA_Od2O9C6p439UclbzBgjvWB09Xej71NoAVk,3727
|
33
|
+
universal_mcp/utils/common.py,sha256=HEZC2Mhilb8DrGXQG2tboAIw1r4veGilGWjfnPF1lyA,888
|
34
|
+
universal_mcp/utils/installation.py,sha256=PU_GfHPqzkumKk-xG4L9CkBzSmABxmchwblZkx-zY-I,7204
|
35
|
+
universal_mcp/utils/prompts.py,sha256=g6esB47Z5BNZxubQtZ21faJUcpH8-wRfS4xgk-2vECs,33284
|
36
|
+
universal_mcp/utils/singleton.py,sha256=RoOiKxBOAhp0TK1QaMDYi-8GjRcy2Vh-bAOuIAcYan0,775
|
37
|
+
universal_mcp/utils/testing.py,sha256=Crk1OqHjXSHIMfPquIuzL4NBq7x1RxL4roTpJobDoY4,1464
|
38
|
+
universal_mcp/utils/openapi/__inti__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
39
|
+
universal_mcp/utils/openapi/api_generator.py,sha256=bX4nAZCZLh4cOO5deLh7MqJ3p3ZWOzggQsCwhUaFMb4,5696
|
40
|
+
universal_mcp/utils/openapi/api_splitter.py,sha256=io7fV-E8hUIR4NxFlakqydbgrQF6aBAnZHPMlpxw-wc,20967
|
41
|
+
universal_mcp/utils/openapi/cli.py,sha256=oQe8KzVa7OEe-ruJRaDlmKmhppEMb15qHyqbDc0QAAM,8715
|
42
|
+
universal_mcp/utils/openapi/docgen.py,sha256=DNmwlhg_-TRrHa74epyErMTRjV2nutfCQ7seb_Rq5hE,21366
|
43
|
+
universal_mcp/utils/openapi/filters.py,sha256=96FajO5nLbvjNPy2A1HvSS9jqpzMDHd4q_QTP-DIsPI,3842
|
44
|
+
universal_mcp/utils/openapi/openapi.py,sha256=xAzr7V1PHBPbRhGrjNoBxT1clvTL7y_9BghvYgEvBqw,52406
|
45
|
+
universal_mcp/utils/openapi/preprocessor.py,sha256=OYlJX9BOn-lBFmBEOii3S2_Vdp3EGXVu3Qc3vLXtGRI,63087
|
46
|
+
universal_mcp/utils/openapi/readme.py,sha256=R2Jp7DUXYNsXPDV6eFTkLiy7MXbSULUj1vHh4O_nB4c,2974
|
47
|
+
universal_mcp/utils/templates/README.md.j2,sha256=Mrm181YX-o_-WEfKs01Bi2RJy43rBiq2j6fTtbWgbTA,401
|
48
|
+
universal_mcp/utils/templates/api_client.py.j2,sha256=972Im7LNUAq3yZTfwDcgivnb-b8u6_JLKWXwoIwXXXQ,908
|
49
|
+
universal_mcp-0.1.24rc2.dist-info/METADATA,sha256=YiW1lPdirDqFJDTvpi5Ah-INW9p0_btzqiSKE2kQrxA,2546
|
50
|
+
universal_mcp-0.1.24rc2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
51
|
+
universal_mcp-0.1.24rc2.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
|
52
|
+
universal_mcp-0.1.24rc2.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
|
53
|
+
universal_mcp-0.1.24rc2.dist-info/RECORD,,
|
@@ -1,122 +0,0 @@
|
|
1
|
-
# Universal MCP Applications Module
|
2
|
-
|
3
|
-
This module provides the core functionality for managing and integrating applications within the Universal MCP system. It offers a flexible framework for creating, managing, and interacting with various types of applications through a unified interface.
|
4
|
-
|
5
|
-
## Overview
|
6
|
-
|
7
|
-
The applications module provides three main base classes for building application integrations:
|
8
|
-
|
9
|
-
1. `BaseApplication`: The abstract base class that defines the common interface for all applications
|
10
|
-
2. `APIApplication`: A concrete implementation for applications that communicate via HTTP APIs
|
11
|
-
3. `GraphQLApplication`: A specialized implementation for applications that use GraphQL APIs
|
12
|
-
|
13
|
-
## Key Features
|
14
|
-
|
15
|
-
- **Dynamic Application Loading**: Applications can be loaded dynamically from external packages
|
16
|
-
- **Unified Credential Management**: Centralized handling of application credentials
|
17
|
-
- **HTTP API Support**: Built-in support for RESTful API interactions
|
18
|
-
- **GraphQL Support**: Specialized support for GraphQL-based applications
|
19
|
-
- **Automatic Package Installation**: Automatic installation of application packages from GitHub
|
20
|
-
|
21
|
-
## Base Classes
|
22
|
-
|
23
|
-
### BaseApplication
|
24
|
-
|
25
|
-
The foundation class for all applications, providing:
|
26
|
-
- Basic initialization
|
27
|
-
- Credential management
|
28
|
-
- Tool listing interface
|
29
|
-
|
30
|
-
### APIApplication
|
31
|
-
|
32
|
-
Extends BaseApplication to provide:
|
33
|
-
- HTTP client management
|
34
|
-
- Authentication handling
|
35
|
-
- Common HTTP methods (GET, POST, PUT, DELETE, PATCH)
|
36
|
-
- Request/response handling
|
37
|
-
|
38
|
-
### GraphQLApplication
|
39
|
-
|
40
|
-
Specialized for GraphQL-based applications, offering:
|
41
|
-
- GraphQL client management
|
42
|
-
- Query and mutation execution
|
43
|
-
- Authentication handling
|
44
|
-
|
45
|
-
## Usage
|
46
|
-
|
47
|
-
### Creating a New Application
|
48
|
-
|
49
|
-
1. Create a new package following the naming convention: `universal_mcp_<app_name>`
|
50
|
-
2. Implement your application class inheriting from one of the base classes
|
51
|
-
3. Name your class following the convention: `<AppName>App`
|
52
|
-
|
53
|
-
Example:
|
54
|
-
```python
|
55
|
-
from universal_mcp.applications import APIApplication
|
56
|
-
|
57
|
-
class MyApp(APIApplication):
|
58
|
-
def __init__(self, name: str, integration=None, **kwargs):
|
59
|
-
super().__init__(name, integration, **kwargs)
|
60
|
-
self.base_url = "https://api.example.com"
|
61
|
-
|
62
|
-
def list_tools(self):
|
63
|
-
return [self.my_tool]
|
64
|
-
|
65
|
-
def my_tool(self):
|
66
|
-
# Implementation here
|
67
|
-
pass
|
68
|
-
```
|
69
|
-
|
70
|
-
### Loading an Application
|
71
|
-
|
72
|
-
```python
|
73
|
-
from universal_mcp.applications import app_from_slug
|
74
|
-
|
75
|
-
# The system will automatically install the package if needed
|
76
|
-
MyApp = app_from_slug("my-app")
|
77
|
-
app = MyApp("my-app-instance")
|
78
|
-
```
|
79
|
-
|
80
|
-
## Authentication
|
81
|
-
|
82
|
-
The module supports various authentication methods:
|
83
|
-
- API Keys
|
84
|
-
- Access Tokens
|
85
|
-
- Custom Headers
|
86
|
-
- Bearer Tokens
|
87
|
-
|
88
|
-
Credentials are managed through the integration system and can be accessed via the `credentials` property.
|
89
|
-
|
90
|
-
## Error Handling
|
91
|
-
|
92
|
-
The module includes comprehensive error handling for:
|
93
|
-
- Package installation failures
|
94
|
-
- Import errors
|
95
|
-
- API request failures
|
96
|
-
- Authentication issues
|
97
|
-
|
98
|
-
## Logging
|
99
|
-
|
100
|
-
All operations are logged using the `loguru` logger, providing detailed information about:
|
101
|
-
- Application initialization
|
102
|
-
- API requests
|
103
|
-
- Authentication attempts
|
104
|
-
- Package installation
|
105
|
-
- Error conditions
|
106
|
-
|
107
|
-
## Requirements
|
108
|
-
|
109
|
-
- Python 3.8+
|
110
|
-
- httpx
|
111
|
-
- gql
|
112
|
-
- loguru
|
113
|
-
- uv (for package installation)
|
114
|
-
|
115
|
-
## Contributing
|
116
|
-
|
117
|
-
To contribute a new application:
|
118
|
-
1. Create a new package following the naming conventions
|
119
|
-
2. Implement the application class
|
120
|
-
3. Add proper error handling and logging
|
121
|
-
4. Include comprehensive documentation
|
122
|
-
5. Submit a pull request to the Universal MCP repository
|
universal_mcp/client/__main__.py
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
import os
|
3
|
-
import sys
|
4
|
-
|
5
|
-
from loguru import logger
|
6
|
-
from pydantic import ValidationError
|
7
|
-
|
8
|
-
from universal_mcp.client.agent import ChatSession
|
9
|
-
from universal_mcp.client.client import MultiClientServer
|
10
|
-
from universal_mcp.config import ClientConfig
|
11
|
-
|
12
|
-
|
13
|
-
async def main() -> None:
|
14
|
-
"""Initialize and run the chat session."""
|
15
|
-
# Load settings and config using Pydantic BaseSettings
|
16
|
-
|
17
|
-
config_path = os.getenv("MCP_CONFIG_PATH", "servers.json")
|
18
|
-
try:
|
19
|
-
app_config = ClientConfig.load_json_config(config_path)
|
20
|
-
except (FileNotFoundError, ValidationError) as e:
|
21
|
-
logger.error(f"Error loading config: {e}")
|
22
|
-
sys.exit(1)
|
23
|
-
|
24
|
-
async with MultiClientServer(app_config.mcpServers) as mcp_server:
|
25
|
-
chat_session = ChatSession(mcp_server, app_config.llm)
|
26
|
-
await chat_session.interactive_loop()
|
27
|
-
|
28
|
-
|
29
|
-
if __name__ == "__main__":
|
30
|
-
asyncio.run(main())
|
universal_mcp/client/agent.py
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
|
3
|
-
from loguru import logger
|
4
|
-
from mcp.server import Server as MCPServer
|
5
|
-
from openai import AsyncOpenAI
|
6
|
-
|
7
|
-
from universal_mcp.config import LLMConfig
|
8
|
-
|
9
|
-
|
10
|
-
class ChatSession:
|
11
|
-
"""Orchestrates the interaction between user, LLM, and tools."""
|
12
|
-
|
13
|
-
def __init__(self, mcp_server: MCPServer, llm: LLMConfig | None) -> None:
|
14
|
-
self.mcp_server: MCPServer = mcp_server
|
15
|
-
self.llm: AsyncOpenAI | None = AsyncOpenAI(api_key=llm.api_key, base_url=llm.base_url) if llm else None
|
16
|
-
self.model = llm.model if llm else None
|
17
|
-
|
18
|
-
async def run(self, messages, tools) -> None:
|
19
|
-
"""Run the chat session."""
|
20
|
-
llm_response = await self.llm.chat.completions.create(
|
21
|
-
model=self.model,
|
22
|
-
messages=messages,
|
23
|
-
tools=tools,
|
24
|
-
tool_choice="auto",
|
25
|
-
)
|
26
|
-
|
27
|
-
tool_calls = llm_response.choices[0].message.tool_calls
|
28
|
-
if tool_calls:
|
29
|
-
for tool_call in tool_calls:
|
30
|
-
result = await self.mcp_server.call_tool(
|
31
|
-
tool_name=tool_call.function.name,
|
32
|
-
arguments=json.loads(tool_call.function.arguments) if tool_call.function.arguments else {},
|
33
|
-
)
|
34
|
-
result_content = [rc.text for rc in result.content] if result.content else "No result"
|
35
|
-
messages.append(
|
36
|
-
{
|
37
|
-
"tool_call_id": tool_call.id,
|
38
|
-
"role": "tool",
|
39
|
-
"name": tool_call.function.name,
|
40
|
-
"content": result_content,
|
41
|
-
}
|
42
|
-
)
|
43
|
-
else:
|
44
|
-
messages.append(llm_response.choices[0].message)
|
45
|
-
return messages
|
46
|
-
|
47
|
-
async def interactive_loop(self) -> None:
|
48
|
-
"""Main chat session handler."""
|
49
|
-
all_openai_tools = await self.mcp_server.list_tools(format="openai")
|
50
|
-
system_message = "You are a helpful assistant"
|
51
|
-
messages = [{"role": "system", "content": system_message}]
|
52
|
-
|
53
|
-
print("\n🎯 Interactive MCP Client")
|
54
|
-
print("Commands:")
|
55
|
-
print(" list - List available tools")
|
56
|
-
print(" call <tool_name> [args] - Call a tool")
|
57
|
-
print(" quit - Exit the client")
|
58
|
-
print()
|
59
|
-
while True:
|
60
|
-
try:
|
61
|
-
user_input = input("You: ").strip()
|
62
|
-
if user_input.lower() in {"quit", "exit"}:
|
63
|
-
logger.info("\nExiting...")
|
64
|
-
break
|
65
|
-
elif user_input.lower() == "list":
|
66
|
-
tools = await self.mcp_server.list_tools()
|
67
|
-
print("\nAvailable tools:")
|
68
|
-
for tool in tools:
|
69
|
-
print(f" {tool.name}")
|
70
|
-
continue
|
71
|
-
elif user_input.startswith("call "):
|
72
|
-
parts = user_input.split(maxsplit=2)
|
73
|
-
tool_name = parts[1] if len(parts) > 1 else ""
|
74
|
-
|
75
|
-
if not tool_name:
|
76
|
-
print("❌ Please specify a tool name")
|
77
|
-
continue
|
78
|
-
|
79
|
-
# Parse arguments (simple JSON-like format)
|
80
|
-
arguments = {}
|
81
|
-
if len(parts) > 2:
|
82
|
-
try:
|
83
|
-
arguments = json.loads(parts[2])
|
84
|
-
except json.JSONDecodeError:
|
85
|
-
print("❌ Invalid arguments format (expected JSON)")
|
86
|
-
continue
|
87
|
-
await self.mcp_server.call_tool(tool_name, arguments)
|
88
|
-
|
89
|
-
messages.append({"role": "user", "content": user_input})
|
90
|
-
|
91
|
-
messages = await self.run(messages, all_openai_tools)
|
92
|
-
print("\nAssistant: ", messages[-1]["content"])
|
93
|
-
|
94
|
-
except KeyboardInterrupt:
|
95
|
-
print("\nExiting...")
|
96
|
-
break
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# Integrations
|
2
|
-
|
3
|
-
This package provides integration classes for handling authentication and authorization with external services.
|
4
|
-
|
5
|
-
## Overview
|
6
|
-
|
7
|
-
An Integration defines how an application authenticates and authorizes with a service provider. The base `Integration` class provides an interface that all integrations must implement.
|
8
|
-
|
9
|
-
## Supported Integrations
|
10
|
-
|
11
|
-
### AgentR Integration
|
12
|
-
The `AgentRIntegration` class handles OAuth-based authentication flow with the AgentR API. It requires an API key which can be obtained from [agentr.dev](https://agentr.dev).
|
13
|
-
|
14
|
-
### API Key Integration
|
15
|
-
The `ApiKeyIntegration` class provides a simple API key based authentication mechanism. API keys are configured via environment variables.
|
16
|
-
|
17
|
-
## Usage
|
18
|
-
|
19
|
-
Each integration implements three key methods:
|
20
|
-
|
21
|
-
- `authorize()` - Initiates the authorization flow
|
22
|
-
- `get_credentials()` - Retrieves stored credentials
|
23
|
-
- `set_credentials()` - Stores new credentials
|
24
|
-
|
25
|
-
See the individual integration classes for specific usage details.
|
universal_mcp/servers/README.md
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
# Servers
|
2
|
-
|
3
|
-
This package provides server implementations for hosting and managing MCP (Model Control Protocol) applications.
|
4
|
-
|
5
|
-
## Overview
|
6
|
-
|
7
|
-
The server implementations provide different ways to host and expose MCP applications and their tools. The base `BaseServer` class provides common functionality that all server implementations inherit.
|
8
|
-
|
9
|
-
## Supported Server Types
|
10
|
-
|
11
|
-
### Local Server
|
12
|
-
The `LocalServer` class provides a local development server implementation that:
|
13
|
-
- Loads applications from local configuration
|
14
|
-
- Manages a local store for data persistence
|
15
|
-
- Supports integration with external services
|
16
|
-
- Exposes application tools through the MCP protocol
|
17
|
-
|
18
|
-
### AgentR Server
|
19
|
-
The `AgentRServer` class provides a server implementation that:
|
20
|
-
- Connects to the AgentR API
|
21
|
-
- Dynamically fetches and loads available applications
|
22
|
-
- Manages AgentR-specific integrations
|
23
|
-
- Requires an API key for authentication
|
24
|
-
|
25
|
-
### Single MCP Server
|
26
|
-
The `SingleMCPServer` class provides a minimal server implementation that:
|
27
|
-
- Hosts a single application instance
|
28
|
-
- Ideal for development and testing
|
29
|
-
- Does not manage integrations or stores internally
|
30
|
-
- Exposes only the tools from the provided application
|
31
|
-
|
32
|
-
## Core Features
|
33
|
-
|
34
|
-
All server implementations provide:
|
35
|
-
|
36
|
-
- Tool management and registration
|
37
|
-
- Application loading and configuration
|
38
|
-
- Error handling and logging
|
39
|
-
- MCP protocol compliance
|
40
|
-
- Integration support
|
41
|
-
|
42
|
-
## Usage
|
43
|
-
|
44
|
-
Each server implementation can be initialized with a `ServerConfig` object that specifies:
|
45
|
-
- Server name and description
|
46
|
-
- Port configuration
|
47
|
-
- Application configurations
|
48
|
-
- Store configuration (where applicable)
|
49
|
-
|
50
|
-
Example:
|
51
|
-
```python
|
52
|
-
from universal_mcp.servers import LocalServer
|
53
|
-
from universal_mcp.config import ServerConfig
|
54
|
-
|
55
|
-
config = ServerConfig(
|
56
|
-
name="My Local Server",
|
57
|
-
description="Development server for testing applications",
|
58
|
-
port=8000,
|
59
|
-
# ... additional configuration
|
60
|
-
)
|
61
|
-
|
62
|
-
server = LocalServer(config)
|
63
|
-
```
|
64
|
-
|
65
|
-
## Tool Management
|
66
|
-
|
67
|
-
Servers provide methods for:
|
68
|
-
- Adding individual tools
|
69
|
-
- Listing available tools
|
70
|
-
- Calling tools with proper error handling
|
71
|
-
- Formatting tool results
|
72
|
-
|
73
|
-
## Error Handling
|
74
|
-
|
75
|
-
All servers implement comprehensive error handling for:
|
76
|
-
- Tool execution failures
|
77
|
-
- Application loading errors
|
78
|
-
- Integration setup issues
|
79
|
-
- API communication problems
|
universal_mcp/stores/README.md
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
# Universal MCP Stores
|
2
|
-
|
3
|
-
The stores module provides a flexible and secure way to manage credentials and sensitive data across different storage backends. It implements a common interface for storing, retrieving, and deleting sensitive information.
|
4
|
-
|
5
|
-
## Features
|
6
|
-
|
7
|
-
- Abstract base class defining a consistent interface for credential stores
|
8
|
-
- Multiple storage backend implementations:
|
9
|
-
- In-memory store (temporary storage)
|
10
|
-
- Environment variable store
|
11
|
-
- System keyring store (secure credential storage)
|
12
|
-
- Exception handling for common error cases
|
13
|
-
- Type hints and comprehensive documentation
|
14
|
-
|
15
|
-
## Available Store Implementations
|
16
|
-
|
17
|
-
### MemoryStore
|
18
|
-
A simple in-memory store that persists data only for the duration of program execution. Useful for testing or temporary storage.
|
19
|
-
|
20
|
-
```python
|
21
|
-
from universal_mcp.stores import MemoryStore
|
22
|
-
|
23
|
-
store = MemoryStore()
|
24
|
-
store.set("api_key", "secret123")
|
25
|
-
value = store.get("api_key") # Returns "secret123"
|
26
|
-
```
|
27
|
-
|
28
|
-
### EnvironmentStore
|
29
|
-
Uses environment variables to store and retrieve credentials. Useful for containerized environments or CI/CD pipelines.
|
30
|
-
|
31
|
-
```python
|
32
|
-
from universal_mcp.stores import EnvironmentStore
|
33
|
-
|
34
|
-
store = EnvironmentStore()
|
35
|
-
store.set("API_KEY", "secret123")
|
36
|
-
value = store.get("API_KEY") # Returns "secret123"
|
37
|
-
```
|
38
|
-
|
39
|
-
### KeyringStore
|
40
|
-
Leverages the system's secure credential storage facility. Provides the most secure option for storing sensitive data.
|
41
|
-
|
42
|
-
```python
|
43
|
-
from universal_mcp.stores import KeyringStore
|
44
|
-
|
45
|
-
store = KeyringStore(app_name="my_app")
|
46
|
-
store.set("api_key", "secret123")
|
47
|
-
value = store.get("api_key") # Returns "secret123"
|
48
|
-
```
|
49
|
-
|
50
|
-
## Error Handling
|
51
|
-
|
52
|
-
The module provides specific exception types for handling errors:
|
53
|
-
|
54
|
-
- `StoreError`: Base exception for all store-related errors
|
55
|
-
- `KeyNotFoundError`: Raised when a requested key is not found in the store
|
56
|
-
|
57
|
-
## Best Practices
|
58
|
-
|
59
|
-
1. Use `KeyringStore` for production environments where security is a priority
|
60
|
-
2. Use `EnvironmentStore` for containerized or cloud environments
|
61
|
-
3. Use `MemoryStore` for testing or temporary storage only
|
62
|
-
4. Always handle `StoreError` and `KeyNotFoundError` exceptions appropriately
|
63
|
-
|
64
|
-
## Dependencies
|
65
|
-
|
66
|
-
- `keyring`: Required for the KeyringStore implementation
|
67
|
-
- `loguru`: Used for logging operations in the KeyringStore
|
68
|
-
|
69
|
-
## Contributing
|
70
|
-
|
71
|
-
New store implementations should inherit from `BaseStore` and implement all required abstract methods:
|
72
|
-
- `get(key: str) -> Any`
|
73
|
-
- `set(key: str, value: str) -> None`
|
74
|
-
- `delete(key: str) -> None`
|
universal_mcp/tools/README.md
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
# Universal MCP Tools
|
2
|
-
|
3
|
-
This directory contains the core tooling infrastructure for Universal MCP, providing a flexible and extensible framework for defining, managing, and converting tools across different formats.
|
4
|
-
|
5
|
-
## Components
|
6
|
-
|
7
|
-
### `tools.py`
|
8
|
-
The main module containing the core tool management functionality:
|
9
|
-
|
10
|
-
- `Tool` class: Represents a tool with metadata, validation, and execution capabilities
|
11
|
-
- `ToolManager` class: Manages tool registration, lookup, and execution
|
12
|
-
- Conversion utilities for different tool formats (OpenAI, LangChain, MCP)
|
13
|
-
|
14
|
-
### `adapters.py`
|
15
|
-
Contains adapters for converting tools between different formats:
|
16
|
-
- `convert_tool_to_mcp_tool`: Converts a tool to MCP format
|
17
|
-
- `convert_tool_to_langchain_tool`: Converts a tool to LangChain format
|
18
|
-
|
19
|
-
### `func_metadata.py`
|
20
|
-
Provides function metadata and argument validation:
|
21
|
-
- `FuncMetadata` class: Handles function signature analysis and argument validation
|
22
|
-
- `ArgModelBase` class: Base model for function arguments
|
23
|
-
- Utilities for parsing and validating function signatures
|
24
|
-
|
25
|
-
## Usage
|
26
|
-
|
27
|
-
### Creating a Tool
|
28
|
-
|
29
|
-
```python
|
30
|
-
from universal_mcp.tools import Tool
|
31
|
-
|
32
|
-
def my_tool(param1: str, param2: int) -> str:
|
33
|
-
"""A simple tool that does something.
|
34
|
-
|
35
|
-
Args:
|
36
|
-
param1: Description of param1
|
37
|
-
param2: Description of param2
|
38
|
-
|
39
|
-
Returns:
|
40
|
-
Description of return value
|
41
|
-
"""
|
42
|
-
return f"Result: {param1} {param2}"
|
43
|
-
|
44
|
-
tool = Tool.from_function(my_tool)
|
45
|
-
```
|
46
|
-
|
47
|
-
### Managing Tools
|
48
|
-
|
49
|
-
```python
|
50
|
-
from universal_mcp.tools import ToolManager
|
51
|
-
|
52
|
-
manager = ToolManager()
|
53
|
-
manager.add_tool(my_tool)
|
54
|
-
|
55
|
-
# Get a tool by name
|
56
|
-
tool = manager.get_tool("my_tool")
|
57
|
-
|
58
|
-
# List all tools in a specific format
|
59
|
-
tools = manager.list_tools(format="openai") # or "langchain" or "mcp"
|
60
|
-
```
|
61
|
-
|
62
|
-
### Converting Tools
|
63
|
-
|
64
|
-
```python
|
65
|
-
from universal_mcp.tools import convert_tool_to_langchain_tool
|
66
|
-
|
67
|
-
langchain_tool = convert_tool_to_langchain_tool(tool)
|
68
|
-
```
|
69
|
-
|
70
|
-
## Features
|
71
|
-
|
72
|
-
- Automatic docstring parsing for tool metadata
|
73
|
-
- Type validation using Pydantic
|
74
|
-
- Support for both sync and async tools
|
75
|
-
- JSON schema generation for tool parameters
|
76
|
-
- Error handling and analytics tracking
|
77
|
-
- Tag-based tool organization
|
78
|
-
- Multiple format support (OpenAI, LangChain, MCP)
|
79
|
-
|
80
|
-
## Best Practices
|
81
|
-
|
82
|
-
1. Always provide clear docstrings for your tools
|
83
|
-
2. Use type hints for better validation
|
84
|
-
3. Handle errors appropriately in your tool implementations
|
85
|
-
4. Use tags to organize related tools
|
86
|
-
5. Consider async implementations for I/O-bound operations
|