universal-mcp 0.1.8rc2__py3-none-any.whl → 0.1.8rc3__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/__init__.py +0 -2
- universal_mcp/analytics.py +75 -0
- universal_mcp/applications/application.py +27 -5
- universal_mcp/applications/calendly/app.py +413 -160
- universal_mcp/applications/coda/README.md +133 -0
- universal_mcp/applications/coda/__init__.py +0 -0
- universal_mcp/applications/coda/app.py +3704 -0
- universal_mcp/applications/e2b/app.py +6 -7
- universal_mcp/applications/firecrawl/app.py +1 -1
- universal_mcp/applications/github/app.py +41 -42
- universal_mcp/applications/google_calendar/app.py +20 -20
- universal_mcp/applications/google_docs/app.py +22 -29
- universal_mcp/applications/google_drive/app.py +53 -59
- universal_mcp/applications/google_mail/app.py +40 -40
- universal_mcp/applications/google_sheet/app.py +44 -51
- universal_mcp/applications/markitdown/app.py +4 -4
- universal_mcp/applications/notion/app.py +93 -83
- universal_mcp/applications/perplexity/app.py +5 -5
- universal_mcp/applications/reddit/app.py +32 -32
- universal_mcp/applications/resend/app.py +4 -4
- universal_mcp/applications/serpapi/app.py +4 -4
- universal_mcp/applications/tavily/app.py +4 -4
- universal_mcp/applications/wrike/app.py +566 -226
- universal_mcp/applications/youtube/app.py +626 -166
- universal_mcp/applications/zenquotes/app.py +3 -3
- universal_mcp/exceptions.py +1 -0
- universal_mcp/integrations/__init__.py +11 -2
- universal_mcp/integrations/integration.py +2 -2
- universal_mcp/logger.py +3 -56
- universal_mcp/servers/__init__.py +2 -1
- universal_mcp/servers/server.py +76 -77
- universal_mcp/stores/store.py +5 -3
- universal_mcp/tools/__init__.py +1 -1
- universal_mcp/tools/adapters.py +4 -1
- universal_mcp/tools/func_metadata.py +5 -6
- universal_mcp/tools/tools.py +108 -51
- universal_mcp/utils/docgen.py +121 -69
- universal_mcp/utils/docstring_parser.py +44 -21
- universal_mcp/utils/dump_app_tools.py +33 -23
- universal_mcp/utils/openapi.py +121 -47
- {universal_mcp-0.1.8rc2.dist-info → universal_mcp-0.1.8rc3.dist-info}/METADATA +2 -2
- universal_mcp-0.1.8rc3.dist-info/RECORD +75 -0
- universal_mcp-0.1.8rc2.dist-info/RECORD +0 -71
- {universal_mcp-0.1.8rc2.dist-info → universal_mcp-0.1.8rc3.dist-info}/WHEEL +0 -0
- {universal_mcp-0.1.8rc2.dist-info → universal_mcp-0.1.8rc3.dist-info}/entry_points.txt +0 -0
universal_mcp/__init__.py
CHANGED
@@ -0,0 +1,75 @@
|
|
1
|
+
import os
|
2
|
+
import uuid
|
3
|
+
from functools import lru_cache
|
4
|
+
from importlib.metadata import version
|
5
|
+
|
6
|
+
import posthog
|
7
|
+
from loguru import logger
|
8
|
+
|
9
|
+
|
10
|
+
class Analytics:
|
11
|
+
_instance = None
|
12
|
+
|
13
|
+
def __new__(cls):
|
14
|
+
if cls._instance is None:
|
15
|
+
cls._instance = super().__new__(cls)
|
16
|
+
cls._instance._initialize()
|
17
|
+
return cls._instance
|
18
|
+
|
19
|
+
def _initialize(self):
|
20
|
+
"""Initialize the Analytics singleton"""
|
21
|
+
posthog.host = "https://us.i.posthog.com"
|
22
|
+
posthog.api_key = "phc_6HXMDi8CjfIW0l04l34L7IDkpCDeOVz9cOz1KLAHXh8"
|
23
|
+
self.enabled = os.getenv("TELEMETRY_DISABLED", "false").lower() != "true"
|
24
|
+
self.user_id = str(uuid.uuid4())[:8]
|
25
|
+
|
26
|
+
@staticmethod
|
27
|
+
@lru_cache(maxsize=1)
|
28
|
+
def get_version():
|
29
|
+
"""
|
30
|
+
Get the version of the Universal MCP
|
31
|
+
"""
|
32
|
+
try:
|
33
|
+
return version("universal_mcp")
|
34
|
+
except ImportError:
|
35
|
+
return "unknown"
|
36
|
+
|
37
|
+
def track_app_loaded(self, app_name: str):
|
38
|
+
"""Track when the app is loaded"""
|
39
|
+
if not self.enabled:
|
40
|
+
return
|
41
|
+
try:
|
42
|
+
properties = {
|
43
|
+
"version": self.get_version(),
|
44
|
+
"app_name": app_name,
|
45
|
+
}
|
46
|
+
posthog.capture(self.user_id, "app_loaded", properties)
|
47
|
+
except Exception as e:
|
48
|
+
logger.error(f"Failed to track app_loaded event: {e}")
|
49
|
+
|
50
|
+
def track_tool_called(
|
51
|
+
self, tool_name: str, status: str, error: str = None, user_id=None
|
52
|
+
):
|
53
|
+
"""Track when a tool is called
|
54
|
+
|
55
|
+
Args:
|
56
|
+
tool_name: Name of the tool being called
|
57
|
+
status: Status of the tool call (success/error)
|
58
|
+
error: Error message if status is error
|
59
|
+
user_id: Optional user ID to track
|
60
|
+
"""
|
61
|
+
if not self.enabled:
|
62
|
+
return
|
63
|
+
try:
|
64
|
+
properties = {
|
65
|
+
"tool_name": tool_name,
|
66
|
+
"status": status,
|
67
|
+
"error": error,
|
68
|
+
"version": self.get_version(),
|
69
|
+
}
|
70
|
+
posthog.capture(self.user_id, "tool_called", properties)
|
71
|
+
except Exception as e:
|
72
|
+
logger.error(f"Failed to track tool_called event: {e}")
|
73
|
+
|
74
|
+
|
75
|
+
analytics = Analytics()
|
@@ -36,7 +36,9 @@ class APIApplication(Application):
|
|
36
36
|
def _get(self, url, params=None):
|
37
37
|
try:
|
38
38
|
headers = self._get_headers()
|
39
|
-
response = httpx.get(
|
39
|
+
response = httpx.get(
|
40
|
+
url, headers=headers, params=params, timeout=self.default_timeout
|
41
|
+
)
|
40
42
|
response.raise_for_status()
|
41
43
|
return response
|
42
44
|
except NotAuthorizedError as e:
|
@@ -49,7 +51,13 @@ class APIApplication(Application):
|
|
49
51
|
def _post(self, url, data, params=None):
|
50
52
|
try:
|
51
53
|
headers = self._get_headers()
|
52
|
-
response = httpx.post(
|
54
|
+
response = httpx.post(
|
55
|
+
url,
|
56
|
+
headers=headers,
|
57
|
+
json=data,
|
58
|
+
params=params,
|
59
|
+
timeout=self.default_timeout,
|
60
|
+
)
|
53
61
|
response.raise_for_status()
|
54
62
|
return response
|
55
63
|
except NotAuthorizedError as e:
|
@@ -67,7 +75,13 @@ class APIApplication(Application):
|
|
67
75
|
def _put(self, url, data, params=None):
|
68
76
|
try:
|
69
77
|
headers = self._get_headers()
|
70
|
-
response = httpx.put(
|
78
|
+
response = httpx.put(
|
79
|
+
url,
|
80
|
+
headers=headers,
|
81
|
+
json=data,
|
82
|
+
params=params,
|
83
|
+
timeout=self.default_timeout,
|
84
|
+
)
|
71
85
|
response.raise_for_status()
|
72
86
|
return response
|
73
87
|
except NotAuthorizedError as e:
|
@@ -80,7 +94,9 @@ class APIApplication(Application):
|
|
80
94
|
def _delete(self, url, params=None):
|
81
95
|
try:
|
82
96
|
headers = self._get_headers()
|
83
|
-
response = httpx.delete(
|
97
|
+
response = httpx.delete(
|
98
|
+
url, headers=headers, params=params, timeout=self.default_timeout
|
99
|
+
)
|
84
100
|
response.raise_for_status()
|
85
101
|
return response
|
86
102
|
except NotAuthorizedError as e:
|
@@ -93,7 +109,13 @@ class APIApplication(Application):
|
|
93
109
|
def _patch(self, url, data, params=None):
|
94
110
|
try:
|
95
111
|
headers = self._get_headers()
|
96
|
-
response = httpx.patch(
|
112
|
+
response = httpx.patch(
|
113
|
+
url,
|
114
|
+
headers=headers,
|
115
|
+
json=data,
|
116
|
+
params=params,
|
117
|
+
timeout=self.default_timeout,
|
118
|
+
)
|
97
119
|
response.raise_for_status()
|
98
120
|
return response
|
99
121
|
except NotAuthorizedError as e:
|