universal-mcp 0.1.0__py3-none-any.whl → 0.1.1__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/cli.py +40 -68
- universal_mcp/servers/server.py +0 -1
- universal_mcp/utils/installation.py +89 -0
- {universal_mcp-0.1.0.dist-info → universal_mcp-0.1.1.dist-info}/METADATA +26 -1
- {universal_mcp-0.1.0.dist-info → universal_mcp-0.1.1.dist-info}/RECORD +7 -7
- universal_mcp/applications/agentr.py +0 -0
- {universal_mcp-0.1.0.dist-info → universal_mcp-0.1.1.dist-info}/WHEEL +0 -0
- {universal_mcp-0.1.0.dist-info → universal_mcp-0.1.1.dist-info}/entry_points.txt +0 -0
universal_mcp/cli.py
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
import typer
|
2
2
|
from pathlib import Path
|
3
|
-
|
3
|
+
|
4
|
+
from universal_mcp.utils.installation import (
|
5
|
+
get_supported_apps,
|
6
|
+
install_claude,
|
7
|
+
install_cursor,
|
8
|
+
)
|
4
9
|
|
5
10
|
app = typer.Typer()
|
6
11
|
|
12
|
+
|
7
13
|
@app.command()
|
8
14
|
def generate(schema_path: Path = typer.Option(..., "--schema", "-s")):
|
9
15
|
"""Generate API client from OpenAPI schema"""
|
@@ -20,19 +26,22 @@ def generate(schema_path: Path = typer.Option(..., "--schema", "-s")):
|
|
20
26
|
code = generate_api_client(schema)
|
21
27
|
print(code)
|
22
28
|
|
29
|
+
|
23
30
|
@app.command()
|
24
|
-
def run():
|
31
|
+
def run(transport: str = typer.Option("stdio", "--transport", "-t")):
|
25
32
|
"""Run the MCP server"""
|
26
33
|
from universal_mcp.servers.server import AgentRServer
|
27
|
-
|
28
|
-
mcp
|
34
|
+
|
35
|
+
mcp = AgentRServer(name="AgentR Server", description="AgentR Server", port=8005)
|
36
|
+
mcp.run(transport=transport)
|
37
|
+
|
29
38
|
|
30
39
|
@app.command()
|
31
40
|
def install(app_name: str = typer.Argument(..., help="Name of app to install")):
|
32
41
|
"""Install an app"""
|
33
42
|
# List of supported apps
|
34
|
-
supported_apps =
|
35
|
-
|
43
|
+
supported_apps = get_supported_apps()
|
44
|
+
|
36
45
|
if app_name not in supported_apps:
|
37
46
|
typer.echo("Available apps:")
|
38
47
|
for app in supported_apps:
|
@@ -40,72 +49,35 @@ def install(app_name: str = typer.Argument(..., help="Name of app to install")):
|
|
40
49
|
typer.echo(f"\nApp '{app_name}' not supported")
|
41
50
|
raise typer.Exit(1)
|
42
51
|
|
43
|
-
import json
|
44
|
-
|
45
52
|
# Print instructions before asking for API key
|
46
|
-
typer.echo(
|
47
|
-
|
48
|
-
|
49
|
-
|
53
|
+
typer.echo(
|
54
|
+
"╭─ Instruction ─────────────────────────────────────────────────────────────────╮"
|
55
|
+
)
|
56
|
+
typer.echo(
|
57
|
+
"│ API key is required. Visit https://agentr.dev to create an API key. │"
|
58
|
+
)
|
59
|
+
typer.echo(
|
60
|
+
"╰───────────────────────────────────────────────────────────────────────────────╯"
|
61
|
+
)
|
62
|
+
|
50
63
|
# Prompt for API key
|
51
64
|
api_key = typer.prompt("Enter your AgentR API key", hide_input=True)
|
65
|
+
try:
|
66
|
+
if app_name == "claude":
|
67
|
+
typer.echo(f"Installing mcp server for: {app_name}")
|
68
|
+
install_claude(api_key)
|
69
|
+
typer.echo("App installed successfully")
|
70
|
+
elif app_name == "cursor":
|
71
|
+
typer.echo(f"Installing mcp server for: {app_name}")
|
72
|
+
install_cursor(api_key)
|
73
|
+
typer.echo("App installed successfully")
|
74
|
+
except Exception as e:
|
75
|
+
typer.echo(f"Error installing app: {e}", err=True)
|
76
|
+
import traceback
|
77
|
+
|
78
|
+
traceback.print_exc()
|
79
|
+
raise typer.Exit(1)
|
52
80
|
|
53
|
-
if app_name == "claude":
|
54
|
-
typer.echo(f"Installing mcp server for: {app_name}")
|
55
|
-
|
56
|
-
# Determine platform-specific config path
|
57
|
-
if sys.platform == "darwin": # macOS
|
58
|
-
config_path = Path.home() / "Library/Application Support/Claude/claude_desktop_config.json"
|
59
|
-
elif sys.platform == "win32": # Windows
|
60
|
-
config_path = Path.home() / "AppData/Roaming/Claude/claude_desktop_config.json"
|
61
|
-
else:
|
62
|
-
typer.echo("Unsupported platform. Only macOS and Windows are currently supported.", err=True)
|
63
|
-
raise typer.Exit(1)
|
64
|
-
|
65
|
-
|
66
|
-
with open(config_path, 'r') as f:
|
67
|
-
config = json.load(f)
|
68
|
-
if 'mcpServers' not in config:
|
69
|
-
config['mcpServers'] = {}
|
70
|
-
config['mcpServers']['universal_mcp'] = {
|
71
|
-
"command": "uvx",
|
72
|
-
"args": ["universal_mcp@latest", "run"],
|
73
|
-
"env": {
|
74
|
-
"AGENTR_API_KEY": api_key
|
75
|
-
}
|
76
|
-
}
|
77
|
-
with open(config_path, 'w') as f:
|
78
|
-
json.dump(config, f, indent=4)
|
79
|
-
typer.echo("App installed successfully")
|
80
|
-
elif app_name == "cursor":
|
81
|
-
typer.echo(f"Installing mcp server for: {app_name}")
|
82
|
-
|
83
|
-
# Set up Cursor config path
|
84
|
-
config_path = Path.home() / ".cursor/mcp.json"
|
85
|
-
|
86
|
-
# Create config directory if it doesn't exist
|
87
|
-
config_path.parent.mkdir(parents=True, exist_ok=True)
|
88
|
-
|
89
|
-
# Create or load existing config
|
90
|
-
if config_path.exists():
|
91
|
-
with open(config_path, 'r') as f:
|
92
|
-
config = json.load(f)
|
93
|
-
else:
|
94
|
-
config = {}
|
95
|
-
|
96
|
-
if 'mcpServers' not in config:
|
97
|
-
config['mcpServers'] = {}
|
98
|
-
config['mcpServers']['universal_mcp'] = {
|
99
|
-
"command": "uvx",
|
100
|
-
"args": ["universal_mcp@latest", "run"],
|
101
|
-
"env": {
|
102
|
-
"AGENTR_API_KEY": api_key
|
103
|
-
}
|
104
|
-
}
|
105
|
-
|
106
|
-
with open(config_path, 'w') as f:
|
107
|
-
json.dump(config, f, indent=4)
|
108
|
-
typer.echo("App installed successfully")
|
109
81
|
|
110
82
|
if __name__ == "__main__":
|
111
83
|
app()
|
universal_mcp/servers/server.py
CHANGED
@@ -16,7 +16,6 @@ class Server(FastMCP, ABC):
|
|
16
16
|
"""
|
17
17
|
Server is responsible for managing the applications and the store
|
18
18
|
It also acts as a router for the applications, and exposed to the client
|
19
|
-
|
20
19
|
"""
|
21
20
|
def __init__(self, name: str, description: str, **kwargs):
|
22
21
|
super().__init__(name, description, **kwargs)
|
@@ -0,0 +1,89 @@
|
|
1
|
+
import json
|
2
|
+
import sys
|
3
|
+
from pathlib import Path
|
4
|
+
|
5
|
+
|
6
|
+
def create_file_if_not_exists(path: Path) -> None:
|
7
|
+
"""Create a file if it doesn't exist"""
|
8
|
+
if not path.exists():
|
9
|
+
with open(path, "w") as f:
|
10
|
+
json.dump({}, f)
|
11
|
+
|
12
|
+
|
13
|
+
def get_supported_apps() -> list[str]:
|
14
|
+
"""Get list of supported apps"""
|
15
|
+
return ["claude", "cursor", "windsurf"]
|
16
|
+
|
17
|
+
|
18
|
+
def install_claude(api_key: str) -> None:
|
19
|
+
"""Install Claude"""
|
20
|
+
# Determine platform-specific config path
|
21
|
+
if sys.platform == "darwin": # macOS
|
22
|
+
config_path = (
|
23
|
+
Path.home()
|
24
|
+
/ "Library/Application Support/Claude/claude_desktop_config.json"
|
25
|
+
)
|
26
|
+
elif sys.platform == "win32": # Windows
|
27
|
+
config_path = Path.home() / "AppData/Roaming/Claude/claude_desktop_config.json"
|
28
|
+
else:
|
29
|
+
raise ValueError(
|
30
|
+
"Unsupported platform. Only macOS and Windows are currently supported.",
|
31
|
+
)
|
32
|
+
|
33
|
+
# Create config directory if it doesn't exist
|
34
|
+
create_file_if_not_exists(config_path)
|
35
|
+
try:
|
36
|
+
config = json.loads(config_path.read_text())
|
37
|
+
except json.JSONDecodeError:
|
38
|
+
config = {}
|
39
|
+
if "mcpServers" not in config:
|
40
|
+
config["mcpServers"] = {}
|
41
|
+
config["mcpServers"]["universal_mcp"] = {
|
42
|
+
"command": "uvx",
|
43
|
+
"args": ["universal_mcp@latest", "run"],
|
44
|
+
"env": {"AGENTR_API_KEY": api_key},
|
45
|
+
}
|
46
|
+
with open(config_path, "w") as f:
|
47
|
+
json.dump(config, f, indent=4)
|
48
|
+
|
49
|
+
|
50
|
+
def install_cursor(api_key: str) -> None:
|
51
|
+
"""Install Cursor"""
|
52
|
+
# Set up Cursor config path
|
53
|
+
config_path = Path.home() / ".cursor/mcp.json"
|
54
|
+
|
55
|
+
# Create config directory if it doesn't exist
|
56
|
+
create_file_if_not_exists(config_path)
|
57
|
+
|
58
|
+
try:
|
59
|
+
config = json.loads(config_path.read_text())
|
60
|
+
except json.JSONDecodeError:
|
61
|
+
config = {}
|
62
|
+
|
63
|
+
if "mcpServers" not in config:
|
64
|
+
config["mcpServers"] = {}
|
65
|
+
config["mcpServers"]["universal_mcp"] = {
|
66
|
+
"command": "uvx",
|
67
|
+
"args": ["universal_mcp@latest", "run"],
|
68
|
+
"env": {"AGENTR_API_KEY": api_key},
|
69
|
+
}
|
70
|
+
|
71
|
+
with open(config_path, "w") as f:
|
72
|
+
json.dump(config, f, indent=4)
|
73
|
+
|
74
|
+
|
75
|
+
def install_windsurf() -> None:
|
76
|
+
"""Install Windsurf"""
|
77
|
+
pass
|
78
|
+
|
79
|
+
|
80
|
+
def install_app(app_name: str) -> None:
|
81
|
+
"""Install an app"""
|
82
|
+
if app_name == "claude":
|
83
|
+
install_claude()
|
84
|
+
elif app_name == "cursor":
|
85
|
+
install_cursor()
|
86
|
+
elif app_name == "windsurf":
|
87
|
+
install_windsurf()
|
88
|
+
else:
|
89
|
+
raise ValueError(f"App '{app_name}' not supported")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: universal-mcp
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.1
|
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
|
Requires-Python: >=3.11
|
@@ -10,6 +10,13 @@ Requires-Dist: pydantic-settings>=2.8.1
|
|
10
10
|
Requires-Dist: pydantic>=2.11.1
|
11
11
|
Requires-Dist: pyyaml>=6.0.2
|
12
12
|
Requires-Dist: typer>=0.15.2
|
13
|
+
Provides-Extra: playground
|
14
|
+
Requires-Dist: fastapi[standard]>=0.115.12; extra == 'playground'
|
15
|
+
Requires-Dist: langchain-anthropic>=0.3.10; extra == 'playground'
|
16
|
+
Requires-Dist: langchain-mcp-adapters>=0.0.3; extra == 'playground'
|
17
|
+
Requires-Dist: langgraph-checkpoint-sqlite>=2.0.6; extra == 'playground'
|
18
|
+
Requires-Dist: langgraph>=0.3.24; extra == 'playground'
|
19
|
+
Requires-Dist: streamlit>=1.44.1; extra == 'playground'
|
13
20
|
Provides-Extra: test
|
14
21
|
Requires-Dist: pytest-asyncio>=0.26.0; extra == 'test'
|
15
22
|
Requires-Dist: pytest>=8.3.5; extra == 'test'
|
@@ -87,6 +94,24 @@ if __name__ == "__main__":
|
|
87
94
|
server.run()
|
88
95
|
```
|
89
96
|
|
97
|
+
## Using Playground
|
98
|
+
|
99
|
+
Start MCP Server
|
100
|
+
```bash
|
101
|
+
universal_mcp run -t sse
|
102
|
+
```
|
103
|
+
|
104
|
+
Start FastAPI app
|
105
|
+
```bash
|
106
|
+
fastapi run src/playground
|
107
|
+
```
|
108
|
+
|
109
|
+
Start Frontend
|
110
|
+
```bash
|
111
|
+
streamlit run src/playground/streamlit.py
|
112
|
+
```
|
113
|
+
|
114
|
+
|
90
115
|
## 🧩 Available Applications
|
91
116
|
AgentR comes with several pre-built applications:
|
92
117
|
|
@@ -1,10 +1,9 @@
|
|
1
1
|
universal_mcp/__init__.py,sha256=2gdHpHaDDcsRjZjJ01FLN-1iidN_wbDAolNpxhGoFB4,59
|
2
|
-
universal_mcp/cli.py,sha256=
|
2
|
+
universal_mcp/cli.py,sha256=BmO-_huXXKvBsg0S3REPDNdu1YNmmSz5-fXlFceJyg4,2848
|
3
3
|
universal_mcp/config.py,sha256=YTygfFJPUuL-epRuILvt5tc5ACzByWIFFNhpFwHlDCE,387
|
4
4
|
universal_mcp/exceptions.py,sha256=cPpdoioDrtNXD6QvH_GKs7bcQ5XRfX8wTrklC4mLS2g,273
|
5
5
|
universal_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
6
|
universal_mcp/applications/__init__.py,sha256=8X1y7kzqBRYsx7vP5jKSagyi4wa5hkbj6d8f8XanKU4,1132
|
7
|
-
universal_mcp/applications/agentr.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
7
|
universal_mcp/applications/application.py,sha256=gHVR7jS0SusNiIm98yoy6RpR-uJsgnvYNa_6DanaPsY,3409
|
9
8
|
universal_mcp/applications/github/app.py,sha256=yXVukXPvAtTAuwNRjo6VU_bt52Sp91P3-K7GUpa3jt4,14020
|
10
9
|
universal_mcp/applications/google_calendar/app.py,sha256=tovWxCW6YM2DiXM7aEZyA7_u2w2IHlcGcvmj3NsQzyA,19897
|
@@ -18,12 +17,13 @@ universal_mcp/integrations/__init__.py,sha256=frBUL7zHnCeukXLuGL8g2P8Rx7D_1TryJQ
|
|
18
17
|
universal_mcp/integrations/agentr.py,sha256=wmac5vwMvftv8PWR54_42fYGlQloFejx76e-vxa597Q,3385
|
19
18
|
universal_mcp/integrations/integration.py,sha256=R4yATIL6JcuPmFZQknQgWv9mb5eGIcpoismOx2VkKPs,4647
|
20
19
|
universal_mcp/servers/__init__.py,sha256=IA9hGn0pebJx4hzTdcsRlH4rPD6BAeuw-7VG_WlRzFw,105
|
21
|
-
universal_mcp/servers/server.py,sha256=
|
20
|
+
universal_mcp/servers/server.py,sha256=vGnqdCd6AA1uh0G87GyfbCXuKqjR12gC2TDnGhFzFYU,5275
|
22
21
|
universal_mcp/stores/__init__.py,sha256=2_qV1Np4GIrFPdH5CIKLeXEXn2b_ImoOTXmaEuHLc6g,135
|
23
22
|
universal_mcp/stores/store.py,sha256=fB3uAaobnWf2ILcDBmg3ToDaqAIPYlLtmHBdpmkcGcI,1585
|
24
23
|
universal_mcp/utils/bridge.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
|
+
universal_mcp/utils/installation.py,sha256=DXcl6voNn1Ihx717KIo2LBzFi_67ffDUxvPu8j0bMyY,2498
|
25
25
|
universal_mcp/utils/openapi.py,sha256=YvDAUohGkcUf2j1-C9jXCF9DaM4ovnr2NlwejFRxGdI,9590
|
26
|
-
universal_mcp-0.1.
|
27
|
-
universal_mcp-0.1.
|
28
|
-
universal_mcp-0.1.
|
29
|
-
universal_mcp-0.1.
|
26
|
+
universal_mcp-0.1.1.dist-info/METADATA,sha256=KFEK1nblKHpSOiRxmJEpbPHAIFzcaYF1vXCCVTlhJAc,5123
|
27
|
+
universal_mcp-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
28
|
+
universal_mcp-0.1.1.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
|
29
|
+
universal_mcp-0.1.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|