universal-mcp 0.1.23rc2__py3-none-any.whl → 0.1.24rc3__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.
Files changed (69) hide show
  1. universal_mcp/agentr/__init__.py +6 -0
  2. universal_mcp/agentr/agentr.py +30 -0
  3. universal_mcp/{utils/agentr.py → agentr/client.py} +22 -7
  4. universal_mcp/agentr/integration.py +104 -0
  5. universal_mcp/agentr/registry.py +91 -0
  6. universal_mcp/agentr/server.py +51 -0
  7. universal_mcp/agents/__init__.py +6 -0
  8. universal_mcp/agents/auto.py +576 -0
  9. universal_mcp/agents/base.py +88 -0
  10. universal_mcp/agents/cli.py +27 -0
  11. universal_mcp/agents/codeact/__init__.py +243 -0
  12. universal_mcp/agents/codeact/sandbox.py +27 -0
  13. universal_mcp/agents/codeact/test.py +15 -0
  14. universal_mcp/agents/codeact/utils.py +61 -0
  15. universal_mcp/agents/hil.py +104 -0
  16. universal_mcp/agents/llm.py +10 -0
  17. universal_mcp/agents/react.py +58 -0
  18. universal_mcp/agents/simple.py +40 -0
  19. universal_mcp/agents/utils.py +111 -0
  20. universal_mcp/analytics.py +44 -14
  21. universal_mcp/applications/__init__.py +42 -75
  22. universal_mcp/applications/application.py +187 -133
  23. universal_mcp/applications/sample/app.py +245 -0
  24. universal_mcp/cli.py +14 -231
  25. universal_mcp/client/oauth.py +122 -18
  26. universal_mcp/client/token_store.py +62 -3
  27. universal_mcp/client/{client.py → transport.py} +127 -48
  28. universal_mcp/config.py +189 -49
  29. universal_mcp/exceptions.py +54 -6
  30. universal_mcp/integrations/__init__.py +0 -18
  31. universal_mcp/integrations/integration.py +185 -168
  32. universal_mcp/servers/__init__.py +2 -14
  33. universal_mcp/servers/server.py +84 -258
  34. universal_mcp/stores/store.py +126 -93
  35. universal_mcp/tools/__init__.py +3 -0
  36. universal_mcp/tools/adapters.py +20 -11
  37. universal_mcp/tools/func_metadata.py +1 -1
  38. universal_mcp/tools/manager.py +38 -53
  39. universal_mcp/tools/registry.py +41 -0
  40. universal_mcp/tools/tools.py +24 -3
  41. universal_mcp/types.py +10 -0
  42. universal_mcp/utils/common.py +245 -0
  43. universal_mcp/utils/installation.py +3 -4
  44. universal_mcp/utils/openapi/api_generator.py +71 -17
  45. universal_mcp/utils/openapi/api_splitter.py +0 -1
  46. universal_mcp/utils/openapi/cli.py +669 -0
  47. universal_mcp/utils/openapi/filters.py +114 -0
  48. universal_mcp/utils/openapi/openapi.py +315 -23
  49. universal_mcp/utils/openapi/postprocessor.py +275 -0
  50. universal_mcp/utils/openapi/preprocessor.py +63 -8
  51. universal_mcp/utils/openapi/test_generator.py +287 -0
  52. universal_mcp/utils/prompts.py +634 -0
  53. universal_mcp/utils/singleton.py +4 -1
  54. universal_mcp/utils/testing.py +196 -8
  55. universal_mcp-0.1.24rc3.dist-info/METADATA +68 -0
  56. universal_mcp-0.1.24rc3.dist-info/RECORD +70 -0
  57. universal_mcp/applications/README.md +0 -122
  58. universal_mcp/client/__main__.py +0 -30
  59. universal_mcp/client/agent.py +0 -96
  60. universal_mcp/integrations/README.md +0 -25
  61. universal_mcp/servers/README.md +0 -79
  62. universal_mcp/stores/README.md +0 -74
  63. universal_mcp/tools/README.md +0 -86
  64. universal_mcp-0.1.23rc2.dist-info/METADATA +0 -283
  65. universal_mcp-0.1.23rc2.dist-info/RECORD +0 -51
  66. /universal_mcp/{utils → tools}/docstring_parser.py +0 -0
  67. {universal_mcp-0.1.23rc2.dist-info → universal_mcp-0.1.24rc3.dist-info}/WHEEL +0 -0
  68. {universal_mcp-0.1.23rc2.dist-info → universal_mcp-0.1.24rc3.dist-info}/entry_points.txt +0 -0
  69. {universal_mcp-0.1.23rc2.dist-info → universal_mcp-0.1.24rc3.dist-info}/licenses/LICENSE +0 -0
@@ -1,13 +1,48 @@
1
+ import os
2
+ from dataclasses import dataclass
3
+
4
+ from langchain_core.messages import AIMessage, HumanMessage
5
+ from langgraph.prebuilt import create_react_agent
1
6
  from loguru import logger
7
+ from pydantic import BaseModel, SecretStr
8
+
9
+ from universal_mcp.agentr import AgentrIntegration
10
+ from universal_mcp.agentr.client import AgentrClient
11
+ from universal_mcp.applications import APIApplication, BaseApplication
12
+ from universal_mcp.tools import Tool, ToolManager
13
+ from universal_mcp.types import ToolFormat
14
+
15
+
16
+ class ValidateResult(BaseModel):
17
+ success: bool
18
+ reasoning: str
19
+
20
+
21
+ def check_application_instance(app_instance: BaseApplication, app_name: str):
22
+ """
23
+ Performs a series of assertions to validate an application instance and its tools.
2
24
 
3
- from universal_mcp.tools.tools import Tool
25
+ This function checks for the following:
26
+ - The application instance is not None.
27
+ - The application instance's name matches the expected application name.
28
+ - The application has at least one tool.
29
+ - Each tool has a non-None name with a valid length (1-47 characters).
30
+ - Each tool has a non-None description.
31
+ - All tool names are unique within the application.
32
+ - The application has at least one tool tagged as "important".
4
33
 
34
+ Args:
35
+ app_instance: The application instance to check. Must be an instance of BaseApplication.
36
+ app_name: The expected name of the application.
37
+
38
+ Raises:
39
+ AssertionError: If any of the validation checks fail.
40
+ """
5
41
 
6
- def check_application_instance(app_instance, app_name):
7
42
  assert app_instance is not None, f"Application object is None for {app_name}"
8
- assert (
9
- app_instance.name == app_name
10
- ), f"Application instance name '{app_instance.name}' does not match expected name '{app_name}'"
43
+ assert app_instance.name == app_name, (
44
+ f"Application instance name '{app_instance.name}' does not match expected name '{app_name}'"
45
+ )
11
46
 
12
47
  tools = app_instance.list_tools()
13
48
  logger.info(f"Tools for {app_name}: {len(tools)}")
@@ -19,9 +54,9 @@ def check_application_instance(app_instance, app_name):
19
54
 
20
55
  for tool in tools:
21
56
  assert tool.name is not None, f"Tool name is None for a tool in {app_name}"
22
- assert (
23
- 0 < len(tool.name) <= 48
24
- ), f"Tool name '{tool.name}' for {app_name} has invalid length (must be between 1 and 47 characters)"
57
+ assert 0 < len(tool.name) <= 48, (
58
+ f"Tool name '{tool.name}' for {app_name} has invalid length (must be between 1 and 47 characters)"
59
+ )
25
60
  assert tool.description is not None, f"Tool description is None for tool '{tool.name}' in {app_name}"
26
61
  # 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
62
  assert tool.name not in seen_names, f"Duplicate tool name: '{tool.name}' found for {app_name}"
@@ -29,3 +64,156 @@ def check_application_instance(app_instance, app_name):
29
64
  if "important" in tool.tags:
30
65
  important_tools.append(tool.name)
31
66
  assert len(important_tools) > 0, f"No important tools found for {app_name}"
67
+
68
+
69
+ @dataclass
70
+ class AutomationTestCase:
71
+ """Generic test case for automation testing."""
72
+
73
+ app: str
74
+ app_instance: APIApplication | None = None
75
+ tools: list[str] | None = None
76
+ tasks: list[str] | None = None
77
+ validate_query: str | None = None
78
+
79
+
80
+ def create_agentr_client(app_name: str) -> AgentrClient:
81
+ """
82
+ Create an AgentrClient with appropriate API key and base URL.
83
+
84
+ Args:
85
+ app_name: Name of the application (used for app-specific environment variables)
86
+
87
+ Returns:
88
+ AgentrClient instance
89
+ """
90
+ api_key = os.environ.get(f"{app_name.upper()}_API_KEY") or os.environ.get("AGENTR_API_KEY")
91
+ base_url = os.environ.get(f"{app_name.upper()}_BASE_URL") or os.environ.get(
92
+ "AGENTR_BASE_URL", "https://api.agentr.dev"
93
+ )
94
+ return AgentrClient(api_key=api_key, base_url=base_url)
95
+
96
+
97
+ def create_integration(app_name: str) -> AgentrIntegration:
98
+ """
99
+ Create an AgentRIntegration instance with appropriate client.
100
+
101
+ Args:
102
+ app_name: Name of the application
103
+
104
+ Returns:
105
+ AgentRIntegration instance
106
+ """
107
+ client = create_agentr_client(app_name)
108
+ return AgentrIntegration(name=app_name, client=client)
109
+
110
+
111
+ def create_app_with_integration(app_name: str, app_class: type[APIApplication]) -> APIApplication:
112
+ """
113
+ Create an application instance with integration.
114
+
115
+ Args:
116
+ app_name: Name of the application
117
+ app_class: Class of the application to instantiate
118
+
119
+ Returns:
120
+ Application instance with integration
121
+ """
122
+ integration = create_integration(app_name)
123
+ return app_class(integration=integration)
124
+
125
+
126
+ def load_app_with_integration(app_name: str, app_class: type[APIApplication]) -> APIApplication:
127
+ """
128
+ Load application instance with real integration.
129
+
130
+ Args:
131
+ app_name: Name of the application
132
+ app_class: Class of the application to instantiate
133
+
134
+ Returns:
135
+ Instantiated application with integration
136
+ """
137
+ integration = create_integration(app_name)
138
+ return app_class(integration=integration)
139
+
140
+
141
+ async def execute_automation_test(test_case: AutomationTestCase, app_instance: APIApplication | None = None) -> None:
142
+ """
143
+ Execute an automation test case using LangGraph ReAct agent.
144
+
145
+ Args:
146
+ test_case: Test case to execute
147
+ app_instance: The application instance to test (optional if provided in test_case)
148
+ """
149
+ tool_manager = ToolManager()
150
+
151
+ if app_instance is None:
152
+ app_instance = test_case.app_instance
153
+ if app_instance is None:
154
+ raise ValueError("No app_instance provided in test_case or as parameter")
155
+
156
+ all_tools = app_instance.list_tools()
157
+ logger.info(f"Available tools from app: {[getattr(t, '__name__', str(t)) for t in all_tools]}")
158
+
159
+ tool_manager.register_tools_from_app(app_instance)
160
+
161
+ all_registered = tool_manager.get_tools_by_app(app_name=app_instance.name)
162
+ logger.info(f"All registered tools: {[t.name for t in all_registered]}")
163
+
164
+ if test_case.tools:
165
+ tools = tool_manager.list_tools(
166
+ format=ToolFormat.LANGCHAIN, app_name=app_instance.name, tool_names=test_case.tools
167
+ )
168
+ else:
169
+ tools = tool_manager.list_tools(format=ToolFormat.LANGCHAIN, app_name=app_instance.name)
170
+
171
+ logger.info(f"Tools for test: {[tool.name for tool in tools]}")
172
+
173
+ azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT")
174
+ azure_api_key = os.environ.get("AZURE_OPENAI_API_KEY")
175
+ azure_deployment = os.environ.get("AZURE_OPENAI_DEPLOYMENT", "o4-mini")
176
+ api_version = os.environ.get("AZURE_OPENAI_API_VERSION", "2025-03-01-preview")
177
+
178
+ if not azure_endpoint or not azure_api_key:
179
+ raise ValueError(
180
+ "Azure OpenAI credentials not found. Please set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_API_KEY environment variables."
181
+ )
182
+
183
+ from langchain_openai import AzureChatOpenAI
184
+
185
+ llm = AzureChatOpenAI(
186
+ azure_endpoint=azure_endpoint,
187
+ azure_deployment=azure_deployment,
188
+ api_key=SecretStr(azure_api_key) if azure_api_key else None,
189
+ api_version=api_version,
190
+ )
191
+ logger.info(f"Using Azure OpenAI with deployment: {azure_deployment}")
192
+
193
+ agent = create_react_agent(
194
+ model=llm,
195
+ tools=tools,
196
+ )
197
+
198
+ messages = []
199
+ for task in test_case.tasks or []:
200
+ try:
201
+ messages.append(HumanMessage(content=task))
202
+ response = await agent.ainvoke({"messages": messages})
203
+ messages.append(AIMessage(content=response["messages"][-1].content))
204
+ logger.info(f"Task: {task}")
205
+ logger.info(f"Response: {response['messages'][-1].content}")
206
+ logger.info("---")
207
+ except Exception as e:
208
+ logger.error(f"Error: {e}")
209
+ import traceback
210
+
211
+ traceback.print_exc()
212
+ raise AssertionError(f"Task execution failed: {e}") from e
213
+
214
+ if test_case.validate_query:
215
+ messages.append(HumanMessage(content=test_case.validate_query))
216
+ structured_llm = llm.with_structured_output(ValidateResult)
217
+ result = await structured_llm.ainvoke(messages)
218
+ logger.info(f"Validation result: {result}")
219
+ assert result.success, f"Validation failed: {result.reasoning}"
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: universal-mcp
3
+ Version: 0.1.24rc3
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: langchain-mcp-adapters>=0.1.9
16
+ Requires-Dist: langchain-openai>=0.3.27
17
+ Requires-Dist: langgraph-cli[inmem]>=0.3.4
18
+ Requires-Dist: langgraph>=0.5.2
19
+ Requires-Dist: langsmith>=0.4.5
20
+ Requires-Dist: loguru>=0.7.3
21
+ Requires-Dist: mcp>=1.10.0
22
+ Requires-Dist: mkdocs-material>=9.6.15
23
+ Requires-Dist: mkdocs>=1.6.1
24
+ Requires-Dist: posthog>=3.24.0
25
+ Requires-Dist: pydantic-settings>=2.8.1
26
+ Requires-Dist: pydantic>=2.11.1
27
+ Requires-Dist: pyyaml>=6.0.2
28
+ Requires-Dist: rich>=14.0.0
29
+ Requires-Dist: streamlit>=1.46.1
30
+ Requires-Dist: ty>=0.0.1a17
31
+ Requires-Dist: typer>=0.15.2
32
+ Provides-Extra: dev
33
+ Requires-Dist: litellm>=1.30.7; extra == 'dev'
34
+ Requires-Dist: mypy>=1.16.0; extra == 'dev'
35
+ Requires-Dist: pre-commit>=4.2.0; extra == 'dev'
36
+ Requires-Dist: pyright>=1.1.398; extra == 'dev'
37
+ Requires-Dist: pytest-asyncio>=0.26.0; extra == 'dev'
38
+ Requires-Dist: pytest>=8.3.5; extra == 'dev'
39
+ Requires-Dist: ruff>=0.11.4; extra == 'dev'
40
+ Provides-Extra: docs
41
+ Requires-Dist: mkdocs-glightbox>=0.4.0; extra == 'docs'
42
+ Requires-Dist: mkdocs-material[imaging]>=9.5.45; extra == 'docs'
43
+ Requires-Dist: mkdocs>=1.6.1; extra == 'docs'
44
+ Requires-Dist: mkdocstrings-python>=1.12.2; extra == 'docs'
45
+ Description-Content-Type: text/markdown
46
+
47
+ # Universal MCP
48
+
49
+ 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.
50
+
51
+ ## Documentation
52
+
53
+ The primary documentation for Universal MCP is available in `/docs` folder in this repository.
54
+
55
+ Please refer to the following for more detailed information:
56
+
57
+ * **[Main Documentation](docs/index.md)**: For an overview of the project, features, quick start, and installation.
58
+ * **[Playground Usage](docs/playground.md)**: For instructions on using the interactive playground.
59
+ * **[Applications Framework](docs/applications.md)**: For details on the applications module.
60
+ * **[Integrations & Authentication](docs/integrations.md)**: For information on integration types.
61
+ * **[Server Implementations](docs/servers.md)**: For details on server types.
62
+ * **[Credential Stores](docs/stores.md)**: For information on credential stores.
63
+ * **[Tools Framework](docs/tools_framework.md)**: For details on the tool management system.
64
+ * **[Contributing Guidelines](CONTRIBUTING.md)**: For information on how to contribute to the project.
65
+
66
+ ## License
67
+
68
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,70 @@
1
+ universal_mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ universal_mcp/analytics.py,sha256=RzS88HSvJRGMjdJeLHnOgWzfKSb1jVnvOcD7NHqfERw,3733
3
+ universal_mcp/cli.py,sha256=pPnIWLhSrLV9ukI8YAg2znehCR3VovhEkmh8XkRT3MU,2505
4
+ universal_mcp/config.py,sha256=pkKs0gST65umzmNEvjHiOAtmiBaaICi45WG4Z0My0ak,11983
5
+ universal_mcp/exceptions.py,sha256=Uen8UFgLHGlSwXgRUyF-nhqTwdiBuL3okgBVRV2AgtA,2150
6
+ universal_mcp/logger.py,sha256=VmH_83efpErLEDTJqz55Dp0dioTXfGvMBLZUx5smOLc,2116
7
+ universal_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ universal_mcp/types.py,sha256=dVK7uSMuhvx5Xk6L7GGdjeaAIKiEwQskTmaVFwIS8LQ,176
9
+ universal_mcp/agentr/__init__.py,sha256=ogOhH_OJwkoUZu_2nQJc7-vEGmYQxEjOE511-6ubrX0,217
10
+ universal_mcp/agentr/agentr.py,sha256=JfawuREfXAyeNUE7o58DzTPhmQXuwsB_Da7c1Gf3Qxw,1059
11
+ universal_mcp/agentr/client.py,sha256=oyF6VKq56UMVf5L1WnFTMSZ85W8Qcy-5HZ5XOGiIELM,4139
12
+ universal_mcp/agentr/integration.py,sha256=V5GjqocqS02tRoI8MeV9PL6m-BzejwBzgJhOHo4MxAE,4212
13
+ universal_mcp/agentr/registry.py,sha256=b9sr5JyT3HLj3e7GFpdXpT7ofGwLQc--y8k2DqF5dE0,3542
14
+ universal_mcp/agentr/server.py,sha256=bIPmHMiKKwnUYnxmfZVRh1thcn7Rytm_-bNiXTfANzc,2098
15
+ universal_mcp/agents/__init__.py,sha256=vgixOLTCcCmSweENV7GSAuOPyHXlE4XAbvOXyr4MrRA,185
16
+ universal_mcp/agents/auto.py,sha256=o__71BCOHSfaj7Xt0PhsamVXdeP4o7irhtmu1q6-3Fo,25336
17
+ universal_mcp/agents/base.py,sha256=U5JtpOopmUi73qcxtY9T2qJpYD7e6c62iVlIr3m5Chc,3430
18
+ universal_mcp/agents/cli.py,sha256=7GdRBpu9rhZPiC2vaNQXWI7K-0yCnvdlmE0IFpvy2Gk,539
19
+ universal_mcp/agents/hil.py,sha256=CTgX7CoFEyTFIaNaL-id2WALOPd0VBb79pHkQK8quM8,3671
20
+ universal_mcp/agents/llm.py,sha256=YNxN43bVhGfdYs09yPkdkGCKJkj-2UNqkB1EFmtnUS4,309
21
+ universal_mcp/agents/react.py,sha256=6L--LcuU5Ityi2UiZSYJWgp-lXGkxvpsx8mjvpoNRBQ,2021
22
+ universal_mcp/agents/simple.py,sha256=UfmQIIff--_Y0DQ6oivRciHqSZvRqy_qwQn_UYVzYy8,1146
23
+ universal_mcp/agents/utils.py,sha256=7kwFpD0Rv6JqHG-LlNCVwSu_xRX-N119mUmiBroHJL4,4109
24
+ universal_mcp/agents/codeact/__init__.py,sha256=5D_I3lI_3tWjZERRoFav_bPe9UDaJ53pDzZYtyixg3E,10097
25
+ universal_mcp/agents/codeact/sandbox.py,sha256=lGRzhuXTHCB1qauuOI3bH1-fPTsyL6Lf9EmMIz4C2xQ,1039
26
+ universal_mcp/agents/codeact/test.py,sha256=bva-KkBNbGZn2f9nmmo9SNPQnY24Ni5gLHhJ5I0cm0k,481
27
+ universal_mcp/agents/codeact/utils.py,sha256=VuMvLTxBBh3pgaJk8RWj5AK8XZFF-1gnZJ6jFLeM_CI,1690
28
+ universal_mcp/applications/__init__.py,sha256=HrCnGdAT7w4puw2_VulBfjOLku9D5DuMaOwAuQzu6nI,2067
29
+ universal_mcp/applications/application.py,sha256=pGF9Rb2D6qzlaSwlcfZ-dNqPtsLkQTqL3jpsRuJ6-qE,23835
30
+ universal_mcp/applications/sample/app.py,sha256=E0JwaWD7qytwawb_iWc1pBnJ-Te7MMtab4MxOOebLdc,8972
31
+ universal_mcp/client/oauth.py,sha256=O00zOUfQxINaruFU2zt-64DIR1_mAqrY8ykLQo-teJU,8679
32
+ universal_mcp/client/token_store.py,sha256=6VAzjzJG49wYvmEDqksFvb-fVqdjHIKWv7yYyh_AuF8,3912
33
+ universal_mcp/client/transport.py,sha256=xgAKBJ1-yCcTtl9cxzJgRn6to5Y9EvCwLc_WpDck3Dg,11838
34
+ universal_mcp/integrations/__init__.py,sha256=tfzLyPEPly5tfIcT8K6-oKCr_MEFGxOROHy_NeVy0KM,200
35
+ universal_mcp/integrations/integration.py,sha256=H-hOoDHqk78A4Fi_TGN7OOFS7PDfqXK_nedH8iSz-6A,16459
36
+ universal_mcp/servers/__init__.py,sha256=speBb_E94UJa4A6Fv8RHFeoJ7cR-q2bCMtKV7R21P5w,142
37
+ universal_mcp/servers/server.py,sha256=qHeHm4UFVUr8TAailbEkWGq7EdlOASkOevY_0lyrWWs,5882
38
+ universal_mcp/stores/__init__.py,sha256=quvuwhZnpiSLuojf0NfmBx2xpaCulv3fbKtKaSCEmuM,603
39
+ universal_mcp/stores/store.py,sha256=yWbEGZb53z3fpVyqGWbes63z1CtIzC_IuM49OXy__UY,10137
40
+ universal_mcp/tools/__init__.py,sha256=jC8hsqfTdtn32yU57AVFUXiU3ZmUOCfCERSCaNEIH7E,395
41
+ universal_mcp/tools/adapters.py,sha256=YJ2oqgc8JgmtsdRRtvO-PO0Q0bKqTJ4Y3J6yxlESoTo,3947
42
+ universal_mcp/tools/docstring_parser.py,sha256=efEOE-ME7G5Jbbzpn7pN2xNuyu2M5zfZ1Tqu1lRB0Gk,8392
43
+ universal_mcp/tools/func_metadata.py,sha256=F4jd--hoZWKPBbZihVtluYKUsIdXdq4a0VWRgMl5k-Q,10838
44
+ universal_mcp/tools/manager.py,sha256=MajVskIptgXv1uZzwnSRycj1TSi7nhn4ebNSRkSSEDs,10455
45
+ universal_mcp/tools/registry.py,sha256=XsmVZL1rY5XgIBPTmvKKBWFLAvB3d9LfYMb11b4wSPI,1169
46
+ universal_mcp/tools/tools.py,sha256=1Q8bKiqj1E_-swvjmNHv16Orpd4p_HQtMKGxfqPmoPI,4570
47
+ universal_mcp/utils/__init__.py,sha256=8wi4PGWu-SrFjNJ8U7fr2iFJ1ktqlDmSKj1xYd7KSDc,41
48
+ universal_mcp/utils/common.py,sha256=3aJK3AnBkmYf-dbsFLaEu_dGuXQ0Qi2HuqYTueLVhXQ,10968
49
+ universal_mcp/utils/installation.py,sha256=PU_GfHPqzkumKk-xG4L9CkBzSmABxmchwblZkx-zY-I,7204
50
+ universal_mcp/utils/prompts.py,sha256=FJhqE0gPXDzYHS8gOjAVrdqVxc9X12ESnpd4C3jDSMI,27547
51
+ universal_mcp/utils/singleton.py,sha256=RoOiKxBOAhp0TK1QaMDYi-8GjRcy2Vh-bAOuIAcYan0,775
52
+ universal_mcp/utils/testing.py,sha256=J857Xt5K-hMxTc8UNJWlkzLbca1zObjwNhNXzYGxBHI,8009
53
+ universal_mcp/utils/openapi/__inti__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
+ universal_mcp/utils/openapi/api_generator.py,sha256=892AWoOCzzvFHVfSpEBg1m4LFRnWMmOSeY0DgLDW0fU,6960
55
+ universal_mcp/utils/openapi/api_splitter.py,sha256=io7fV-E8hUIR4NxFlakqydbgrQF6aBAnZHPMlpxw-wc,20967
56
+ universal_mcp/utils/openapi/cli.py,sha256=az5ObS74R-MmDCOZ1PHTJVKZJrHnsBOAweOUa7A-GqA,25918
57
+ universal_mcp/utils/openapi/docgen.py,sha256=DNmwlhg_-TRrHa74epyErMTRjV2nutfCQ7seb_Rq5hE,21366
58
+ universal_mcp/utils/openapi/filters.py,sha256=96FajO5nLbvjNPy2A1HvSS9jqpzMDHd4q_QTP-DIsPI,3842
59
+ universal_mcp/utils/openapi/openapi.py,sha256=0Pn_ugkEwL0eMtctjc0XDMPZdB3SBOqza_J6BK8i_SY,62165
60
+ universal_mcp/utils/openapi/postprocessor.py,sha256=NKvpXi73INRXxj1KOu8Ph3loWGICx2Uyy2Q8uOOqBoc,12177
61
+ universal_mcp/utils/openapi/preprocessor.py,sha256=r4n0WQI__OzPL8FTza7jxiM4EYeZwa-3tvEJaJYZC44,63081
62
+ universal_mcp/utils/openapi/readme.py,sha256=R2Jp7DUXYNsXPDV6eFTkLiy7MXbSULUj1vHh4O_nB4c,2974
63
+ universal_mcp/utils/openapi/test_generator.py,sha256=h44gQXEXmrw4pD3-XNHKB7T9c2lDomqrJxVO6oszCqM,12186
64
+ universal_mcp/utils/templates/README.md.j2,sha256=Mrm181YX-o_-WEfKs01Bi2RJy43rBiq2j6fTtbWgbTA,401
65
+ universal_mcp/utils/templates/api_client.py.j2,sha256=972Im7LNUAq3yZTfwDcgivnb-b8u6_JLKWXwoIwXXXQ,908
66
+ universal_mcp-0.1.24rc3.dist-info/METADATA,sha256=rJ2CEZw0gwZkc3O39e1u_6VMcCr1dAhNBviG0YZXwto,3116
67
+ universal_mcp-0.1.24rc3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
68
+ universal_mcp-0.1.24rc3.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
69
+ universal_mcp-0.1.24rc3.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
70
+ universal_mcp-0.1.24rc3.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
@@ -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())
@@ -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.