universal-mcp 0.1.7rc1__py3-none-any.whl → 0.1.8__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/ahrefs/README.md +76 -0
- universal_mcp/applications/ahrefs/app.py +2291 -0
- universal_mcp/applications/application.py +95 -5
- universal_mcp/applications/calendly/README.md +78 -0
- universal_mcp/applications/calendly/__init__.py +0 -0
- universal_mcp/applications/calendly/app.py +1195 -0
- universal_mcp/applications/coda/README.md +133 -0
- universal_mcp/applications/coda/__init__.py +0 -0
- universal_mcp/applications/coda/app.py +3671 -0
- universal_mcp/applications/e2b/app.py +14 -28
- universal_mcp/applications/figma/README.md +74 -0
- universal_mcp/applications/figma/__init__.py +0 -0
- universal_mcp/applications/figma/app.py +1261 -0
- universal_mcp/applications/firecrawl/app.py +38 -35
- universal_mcp/applications/github/app.py +127 -85
- universal_mcp/applications/google_calendar/app.py +62 -138
- universal_mcp/applications/google_docs/app.py +47 -52
- universal_mcp/applications/google_drive/app.py +119 -113
- universal_mcp/applications/google_mail/app.py +124 -50
- universal_mcp/applications/google_sheet/app.py +89 -91
- universal_mcp/applications/markitdown/app.py +9 -8
- universal_mcp/applications/notion/app.py +254 -134
- universal_mcp/applications/perplexity/app.py +13 -41
- universal_mcp/applications/reddit/app.py +94 -85
- universal_mcp/applications/resend/app.py +12 -13
- universal_mcp/applications/{serp → serpapi}/app.py +14 -25
- universal_mcp/applications/tavily/app.py +11 -18
- universal_mcp/applications/wrike/README.md +71 -0
- universal_mcp/applications/wrike/__init__.py +0 -0
- universal_mcp/applications/wrike/app.py +1372 -0
- universal_mcp/applications/youtube/README.md +82 -0
- universal_mcp/applications/youtube/__init__.py +0 -0
- universal_mcp/applications/youtube/app.py +1428 -0
- universal_mcp/applications/zenquotes/app.py +12 -2
- universal_mcp/exceptions.py +9 -2
- universal_mcp/integrations/__init__.py +24 -1
- universal_mcp/integrations/agentr.py +27 -4
- universal_mcp/integrations/integration.py +146 -32
- universal_mcp/logger.py +3 -56
- universal_mcp/servers/__init__.py +6 -14
- universal_mcp/servers/server.py +201 -146
- universal_mcp/stores/__init__.py +7 -2
- universal_mcp/stores/store.py +103 -40
- universal_mcp/tools/__init__.py +3 -0
- universal_mcp/tools/adapters.py +43 -0
- universal_mcp/tools/func_metadata.py +213 -0
- universal_mcp/tools/tools.py +342 -0
- universal_mcp/utils/docgen.py +325 -119
- universal_mcp/utils/docstring_parser.py +179 -0
- universal_mcp/utils/dump_app_tools.py +33 -23
- universal_mcp/utils/installation.py +201 -10
- universal_mcp/utils/openapi.py +229 -46
- {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.8.dist-info}/METADATA +9 -5
- universal_mcp-0.1.8.dist-info/RECORD +81 -0
- universal_mcp-0.1.7rc1.dist-info/RECORD +0 -58
- /universal_mcp/{utils/bridge.py → applications/ahrefs/__init__.py} +0 -0
- /universal_mcp/applications/{serp → serpapi}/README.md +0 -0
- {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.8.dist-info}/WHEEL +0 -0
- {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.8.dist-info}/entry_points.txt +0 -0
@@ -3,6 +3,7 @@ from abc import ABC, abstractmethod
|
|
3
3
|
import httpx
|
4
4
|
from loguru import logger
|
5
5
|
|
6
|
+
from universal_mcp.analytics import analytics
|
6
7
|
from universal_mcp.exceptions import NotAuthorizedError
|
7
8
|
from universal_mcp.integrations import Integration
|
8
9
|
|
@@ -14,6 +15,8 @@ class Application(ABC):
|
|
14
15
|
|
15
16
|
def __init__(self, name: str, **kwargs):
|
16
17
|
self.name = name
|
18
|
+
logger.debug(f"Initializing Application '{name}' with kwargs: {kwargs}")
|
19
|
+
analytics.track_app_loaded(name) # Track app loading
|
17
20
|
|
18
21
|
@abstractmethod
|
19
22
|
def list_tools(self):
|
@@ -27,16 +30,60 @@ class APIApplication(Application):
|
|
27
30
|
|
28
31
|
def __init__(self, name: str, integration: Integration = None, **kwargs):
|
29
32
|
super().__init__(name, **kwargs)
|
33
|
+
self.default_timeout = 30
|
30
34
|
self.integration = integration
|
35
|
+
logger.debug(
|
36
|
+
f"Initializing APIApplication '{name}' with integration: {integration}"
|
37
|
+
)
|
31
38
|
|
32
39
|
def _get_headers(self):
|
40
|
+
if not self.integration:
|
41
|
+
logger.debug("No integration configured, returning empty headers")
|
42
|
+
return {}
|
43
|
+
credentials = self.integration.get_credentials()
|
44
|
+
logger.debug(f"Got credentials for integration: {credentials.keys()}")
|
45
|
+
|
46
|
+
# Check if direct headers are provided
|
47
|
+
headers = credentials.get("headers")
|
48
|
+
if headers:
|
49
|
+
logger.debug("Using direct headers from credentials")
|
50
|
+
return headers
|
51
|
+
|
52
|
+
# Check if api key is provided
|
53
|
+
api_key = (
|
54
|
+
credentials.get("api_key")
|
55
|
+
or credentials.get("API_KEY")
|
56
|
+
or credentials.get("apiKey")
|
57
|
+
)
|
58
|
+
if api_key:
|
59
|
+
logger.debug("Using API key from credentials")
|
60
|
+
return {
|
61
|
+
"Authorization": f"Bearer {api_key}",
|
62
|
+
"Content-Type": "application/json",
|
63
|
+
}
|
64
|
+
|
65
|
+
# Check if access token is provided
|
66
|
+
access_token = credentials.get("access_token")
|
67
|
+
if access_token:
|
68
|
+
logger.debug("Using access token from credentials")
|
69
|
+
return {
|
70
|
+
"Authorization": f"Bearer {access_token}",
|
71
|
+
"Content-Type": "application/json",
|
72
|
+
}
|
73
|
+
logger.debug("No authentication found in credentials, returning empty headers")
|
33
74
|
return {}
|
34
75
|
|
35
76
|
def _get(self, url, params=None):
|
36
77
|
try:
|
37
78
|
headers = self._get_headers()
|
38
|
-
|
79
|
+
logger.debug(f"Making GET request to {url} with params: {params}")
|
80
|
+
response = httpx.get(
|
81
|
+
url, headers=headers, params=params, timeout=self.default_timeout
|
82
|
+
)
|
39
83
|
response.raise_for_status()
|
84
|
+
logger.debug(
|
85
|
+
f"GET request successful with status code: {response.status_code}"
|
86
|
+
)
|
40
87
|
return response
|
41
88
|
except NotAuthorizedError as e:
|
42
89
|
logger.warning(f"Authorization needed: {e.message}")
|
@@ -48,14 +95,27 @@ class APIApplication(Application):
|
|
48
95
|
def _post(self, url, data, params=None):
|
49
96
|
try:
|
50
97
|
headers = self._get_headers()
|
51
|
-
|
98
|
+
logger.debug(
|
99
|
+
f"Making POST request to {url} with params: {params} and data: {data}"
|
100
|
+
)
|
101
|
+
response = httpx.post(
|
102
|
+
url,
|
103
|
+
headers=headers,
|
104
|
+
json=data,
|
105
|
+
params=params,
|
106
|
+
timeout=self.default_timeout,
|
107
|
+
)
|
52
108
|
response.raise_for_status()
|
109
|
+
logger.debug(
|
110
|
+
f"POST request successful with status code: {response.status_code}"
|
111
|
+
)
|
53
112
|
return response
|
54
113
|
except NotAuthorizedError as e:
|
55
114
|
logger.warning(f"Authorization needed: {e.message}")
|
56
115
|
raise e
|
57
116
|
except httpx.HTTPStatusError as e:
|
58
117
|
if e.response.status_code == 429:
|
118
|
+
logger.warning(f"Rate limit exceeded for {url}")
|
59
119
|
return e.response.text or "Rate limit exceeded. Please try again later."
|
60
120
|
else:
|
61
121
|
raise e
|
@@ -66,8 +126,20 @@ class APIApplication(Application):
|
|
66
126
|
def _put(self, url, data, params=None):
|
67
127
|
try:
|
68
128
|
headers = self._get_headers()
|
69
|
-
|
129
|
+
logger.debug(
|
130
|
+
f"Making PUT request to {url} with params: {params} and data: {data}"
|
131
|
+
)
|
132
|
+
response = httpx.put(
|
133
|
+
url,
|
134
|
+
headers=headers,
|
135
|
+
json=data,
|
136
|
+
params=params,
|
137
|
+
timeout=self.default_timeout,
|
138
|
+
)
|
70
139
|
response.raise_for_status()
|
140
|
+
logger.debug(
|
141
|
+
f"PUT request successful with status code: {response.status_code}"
|
142
|
+
)
|
71
143
|
return response
|
72
144
|
except NotAuthorizedError as e:
|
73
145
|
logger.warning(f"Authorization needed: {e.message}")
|
@@ -79,8 +151,14 @@ class APIApplication(Application):
|
|
79
151
|
def _delete(self, url, params=None):
|
80
152
|
try:
|
81
153
|
headers = self._get_headers()
|
82
|
-
|
154
|
+
logger.debug(f"Making DELETE request to {url} with params: {params}")
|
155
|
+
response = httpx.delete(
|
156
|
+
url, headers=headers, params=params, timeout=self.default_timeout
|
157
|
+
)
|
83
158
|
response.raise_for_status()
|
159
|
+
logger.debug(
|
160
|
+
f"DELETE request successful with status code: {response.status_code}"
|
161
|
+
)
|
84
162
|
return response
|
85
163
|
except NotAuthorizedError as e:
|
86
164
|
logger.warning(f"Authorization needed: {e.message}")
|
@@ -92,8 +170,20 @@ class APIApplication(Application):
|
|
92
170
|
def _patch(self, url, data, params=None):
|
93
171
|
try:
|
94
172
|
headers = self._get_headers()
|
95
|
-
|
173
|
+
logger.debug(
|
174
|
+
f"Making PATCH request to {url} with params: {params} and data: {data}"
|
175
|
+
)
|
176
|
+
response = httpx.patch(
|
177
|
+
url,
|
178
|
+
headers=headers,
|
179
|
+
json=data,
|
180
|
+
params=params,
|
181
|
+
timeout=self.default_timeout,
|
182
|
+
)
|
96
183
|
response.raise_for_status()
|
184
|
+
logger.debug(
|
185
|
+
f"PATCH request successful with status code: {response.status_code}"
|
186
|
+
)
|
97
187
|
return response
|
98
188
|
except NotAuthorizedError as e:
|
99
189
|
logger.warning(f"Authorization needed: {e.message}")
|
@@ -0,0 +1,78 @@
|
|
1
|
+
|
2
|
+
# Calendly MCP Server
|
3
|
+
|
4
|
+
An MCP Server for the Calendly API.
|
5
|
+
|
6
|
+
## Supported Integrations
|
7
|
+
|
8
|
+
- AgentR
|
9
|
+
- API Key (Coming Soon)
|
10
|
+
- OAuth (Coming Soon)
|
11
|
+
|
12
|
+
## Tools
|
13
|
+
|
14
|
+
This is automatically generated from OpenAPI schema for the Calendly API.
|
15
|
+
|
16
|
+
## Supported Integrations
|
17
|
+
|
18
|
+
This tool can be integrated with any service that supports HTTP requests.
|
19
|
+
|
20
|
+
## Tool List
|
21
|
+
|
22
|
+
| Tool | Description |
|
23
|
+
|------|-------------|
|
24
|
+
| list_event_invitees | Retrieves a list of invitees for a specific scheduled event, optionally filtered and paginated by status, email, sorting order, and paging parameters. |
|
25
|
+
| get_event | Retrieves the details of a scheduled event given its UUID. |
|
26
|
+
| get_event_invitee | Retrieves details about a specific invitee for a given scheduled event. |
|
27
|
+
| list_events | Retrieves a list of scheduled events filtered by optional user, organization, invitee email, status, date range, sorting, and pagination criteria. |
|
28
|
+
| get_event_type | Retrieves the event type details for the specified UUID from the API. |
|
29
|
+
| list_user_sevent_types | Retrieves a list of user event types with optional filtering, sorting, and pagination parameters. |
|
30
|
+
| get_user | Retrieves detailed user information for a given UUID from the remote API. |
|
31
|
+
| get_current_user | Retrieves information about the currently authenticated user from the API. |
|
32
|
+
| list_organization_invitations | Retrieves a paginated list of invitations for a specified organization, with optional filtering and sorting. |
|
33
|
+
| invite_user_to_organization | Sends an invitation to a specified email address to join an organization identified by its UUID. |
|
34
|
+
| get_organization_invitation | Retrieves a specific invitation for an organization using its unique identifiers. |
|
35
|
+
| revoke_user_sorganization_invitation | Revokes a user's invitation to an organization by deleting the specified invitation resource. |
|
36
|
+
| get_organization_membership | Retrieves the membership information for a specified organization membership UUID. |
|
37
|
+
| remove_user_from_organization | Removes a user from the organization by deleting their membership using the specified UUID. |
|
38
|
+
| list_organization_memberships | Retrieves a list of organization memberships, optionally filtered by pagination, email, organization, or user parameters. |
|
39
|
+
| get_webhook_subscription | Retrieves the details of a webhook subscription identified by its UUID. |
|
40
|
+
| delete_webhook_subscription | Deletes a webhook subscription identified by its UUID. |
|
41
|
+
| list_webhook_subscriptions | Retrieves a list of webhook subscriptions, optionally filtered and paginated based on input criteria. |
|
42
|
+
| create_webhook_subscription | Creates a new webhook subscription with the specified parameters and returns the subscription details as a dictionary. |
|
43
|
+
| create_single_use_scheduling_link | Creates a single-use scheduling link by sending a POST request with optional restrictions. |
|
44
|
+
| delete_invitee_data | Deletes invitee data for the specified email addresses by sending a POST request to the data compliance API. |
|
45
|
+
| delete_scheduled_event_data | Deletes scheduled event data within the specified time range by sending a deletion request to the data compliance service. |
|
46
|
+
| get_invitee_no_show | Retrieves details about an invitee who did not show up for a scheduled event, identified by a unique UUID. |
|
47
|
+
| delete_invitee_no_show | Deletes an invitee no-show record identified by the given UUID. |
|
48
|
+
| create_invitee_no_show | Creates an invitee no-show record by sending a POST request to the invitee_no_shows endpoint. |
|
49
|
+
| get_group | Retrieves information for a group identified by its UUID from the server. |
|
50
|
+
| list_groups | Retrieves a list of groups from the API, optionally filtered by organization and paginated using a page token and count. |
|
51
|
+
| get_group_relationship | Retrieves the relationship information for a group specified by UUID from the API. |
|
52
|
+
| list_group_relationships | Retrieves a list of group relationships from the server, optionally filtered by pagination and various group ownership parameters. |
|
53
|
+
| get_routing_form | Retrieves a routing form by its unique identifier from the server. |
|
54
|
+
| list_routing_forms | Retrieves a paginated list of routing forms from the API, optionally filtered and sorted by organization, count, page token, or sort order. |
|
55
|
+
| get_routing_form_submission | Retrieves a routing form submission by its unique identifier (UUID) from the configured API endpoint. |
|
56
|
+
| list_routing_form_submissions | Retrieves a list of routing form submissions, optionally filtered and paginated based on provided parameters. |
|
57
|
+
| list_event_type_available_times | Retrieves available times for a specified event type within an optional date and time range. |
|
58
|
+
| list_activity_log_entries | Retrieves a list of activity log entries with optional filtering, sorting, and pagination. |
|
59
|
+
| create_share | Creates a new share with the specified configuration parameters by making a POST request to the shares API endpoint. |
|
60
|
+
| list_user_busy_times | Retrieves a list of busy time intervals for a specified user within an optional date range. |
|
61
|
+
| get_user_availability_schedule | Retrieves the availability schedule for a user identified by the given UUID. |
|
62
|
+
| list_user_availability_schedules | Retrieves a list of user availability schedules from the API, optionally filtering by a specific user. |
|
63
|
+
| list_event_type_hosts | Retrieves a list of event type hosts based on provided filter, count, and pagination parameters. |
|
64
|
+
| create_one_off_event_type | Creates a one-off event type with specified parameters and returns the created event type details. |
|
65
|
+
| get_sample_webhook_data | Retrieves sample webhook data from the API using optional filtering parameters. |
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
## Usage
|
70
|
+
|
71
|
+
- Login to AgentR
|
72
|
+
- Follow the quickstart guide to setup MCP Server for your client
|
73
|
+
- Visit Apps Store and enable the Calendly app
|
74
|
+
- Restart the MCP Server
|
75
|
+
|
76
|
+
### Local Development
|
77
|
+
|
78
|
+
- Follow the README to test with the local MCP Server
|
File without changes
|