universal-mcp-applications 0.1.33__py3-none-any.whl → 0.1.39rc8__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.
Potentially problematic release.
This version of universal-mcp-applications might be problematic. Click here for more details.
- universal_mcp/applications/ahrefs/app.py +92 -238
- universal_mcp/applications/airtable/app.py +23 -122
- universal_mcp/applications/apollo/app.py +122 -475
- universal_mcp/applications/asana/app.py +605 -1755
- universal_mcp/applications/aws_s3/app.py +36 -103
- universal_mcp/applications/bill/app.py +644 -2055
- universal_mcp/applications/box/app.py +1246 -4159
- universal_mcp/applications/braze/app.py +410 -1476
- universal_mcp/applications/browser_use/README.md +15 -1
- universal_mcp/applications/browser_use/__init__.py +1 -0
- universal_mcp/applications/browser_use/app.py +86 -24
- universal_mcp/applications/cal_com_v2/app.py +207 -625
- universal_mcp/applications/calendly/app.py +103 -242
- universal_mcp/applications/canva/app.py +75 -140
- universal_mcp/applications/clickup/app.py +331 -798
- universal_mcp/applications/coda/app.py +240 -520
- universal_mcp/applications/confluence/app.py +497 -1285
- universal_mcp/applications/contentful/app.py +36 -151
- universal_mcp/applications/crustdata/app.py +42 -121
- universal_mcp/applications/dialpad/app.py +451 -924
- universal_mcp/applications/digitalocean/app.py +2071 -6082
- universal_mcp/applications/domain_checker/app.py +3 -54
- universal_mcp/applications/e2b/app.py +14 -64
- universal_mcp/applications/elevenlabs/app.py +9 -47
- universal_mcp/applications/exa/README.md +8 -4
- universal_mcp/applications/exa/app.py +408 -186
- universal_mcp/applications/falai/app.py +24 -101
- universal_mcp/applications/figma/app.py +91 -175
- universal_mcp/applications/file_system/app.py +2 -13
- universal_mcp/applications/firecrawl/app.py +186 -163
- universal_mcp/applications/fireflies/app.py +59 -281
- universal_mcp/applications/fpl/app.py +92 -529
- universal_mcp/applications/fpl/utils/fixtures.py +15 -49
- universal_mcp/applications/fpl/utils/helper.py +25 -89
- universal_mcp/applications/fpl/utils/league_utils.py +20 -64
- universal_mcp/applications/ghost_content/app.py +66 -175
- universal_mcp/applications/github/app.py +28 -65
- universal_mcp/applications/gong/app.py +140 -300
- universal_mcp/applications/google_calendar/app.py +26 -78
- universal_mcp/applications/google_docs/app.py +98 -202
- universal_mcp/applications/google_drive/app.py +194 -793
- universal_mcp/applications/google_gemini/app.py +27 -62
- universal_mcp/applications/google_mail/README.md +1 -0
- universal_mcp/applications/google_mail/app.py +93 -214
- universal_mcp/applications/google_searchconsole/app.py +25 -58
- universal_mcp/applications/google_sheet/app.py +171 -624
- universal_mcp/applications/google_sheet/helper.py +26 -53
- universal_mcp/applications/hashnode/app.py +57 -269
- universal_mcp/applications/heygen/app.py +77 -155
- universal_mcp/applications/http_tools/app.py +10 -32
- universal_mcp/applications/hubspot/README.md +1 -1
- universal_mcp/applications/hubspot/app.py +7508 -99
- universal_mcp/applications/jira/app.py +2419 -8334
- universal_mcp/applications/klaviyo/app.py +737 -1619
- universal_mcp/applications/linkedin/README.md +5 -0
- universal_mcp/applications/linkedin/app.py +332 -227
- universal_mcp/applications/mailchimp/app.py +696 -1851
- universal_mcp/applications/markitdown/app.py +8 -20
- universal_mcp/applications/miro/app.py +333 -815
- universal_mcp/applications/ms_teams/app.py +85 -207
- universal_mcp/applications/neon/app.py +144 -250
- universal_mcp/applications/notion/app.py +36 -51
- universal_mcp/applications/onedrive/app.py +26 -48
- universal_mcp/applications/openai/app.py +42 -165
- universal_mcp/applications/outlook/README.md +22 -9
- universal_mcp/applications/outlook/app.py +403 -141
- universal_mcp/applications/perplexity/README.md +2 -1
- universal_mcp/applications/perplexity/app.py +162 -20
- universal_mcp/applications/pipedrive/app.py +1021 -3331
- universal_mcp/applications/posthog/app.py +272 -541
- universal_mcp/applications/reddit/app.py +61 -160
- universal_mcp/applications/resend/app.py +41 -107
- universal_mcp/applications/retell/app.py +23 -50
- universal_mcp/applications/rocketlane/app.py +250 -963
- universal_mcp/applications/scraper/app.py +67 -125
- universal_mcp/applications/semanticscholar/app.py +36 -78
- universal_mcp/applications/semrush/app.py +43 -77
- universal_mcp/applications/sendgrid/app.py +826 -1576
- universal_mcp/applications/sentry/app.py +444 -1079
- universal_mcp/applications/serpapi/app.py +40 -143
- universal_mcp/applications/sharepoint/app.py +27 -49
- universal_mcp/applications/shopify/app.py +1743 -4479
- universal_mcp/applications/shortcut/app.py +272 -534
- universal_mcp/applications/slack/app.py +41 -123
- universal_mcp/applications/spotify/app.py +206 -405
- universal_mcp/applications/supabase/app.py +174 -283
- universal_mcp/applications/tavily/app.py +2 -2
- universal_mcp/applications/trello/app.py +853 -2816
- universal_mcp/applications/twilio/app.py +14 -50
- universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
- universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
- universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
- universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
- universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
- universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
- universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
- universal_mcp/applications/whatsapp/app.py +35 -186
- universal_mcp/applications/whatsapp/audio.py +2 -6
- universal_mcp/applications/whatsapp/whatsapp.py +17 -51
- universal_mcp/applications/whatsapp_business/app.py +86 -299
- universal_mcp/applications/wrike/app.py +80 -153
- universal_mcp/applications/yahoo_finance/app.py +19 -65
- universal_mcp/applications/youtube/app.py +120 -306
- universal_mcp/applications/zenquotes/app.py +3 -3
- {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/METADATA +4 -2
- {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/RECORD +109 -113
- {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/WHEEL +1 -1
- universal_mcp/applications/hubspot/api_segments/__init__.py +0 -0
- universal_mcp/applications/hubspot/api_segments/api_segment_base.py +0 -54
- universal_mcp/applications/hubspot/api_segments/crm_api.py +0 -7337
- universal_mcp/applications/hubspot/api_segments/marketing_api.py +0 -1467
- {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from typing import Any
|
|
2
|
-
|
|
3
2
|
from loguru import logger
|
|
4
3
|
from universal_mcp.applications.application import APIApplication
|
|
5
4
|
from universal_mcp.integrations import Integration
|
|
@@ -17,12 +16,9 @@ class GithubApp(APIApplication):
|
|
|
17
16
|
credentials = self.integration.get_credentials()
|
|
18
17
|
if "headers" in credentials:
|
|
19
18
|
return credentials["headers"]
|
|
20
|
-
return {
|
|
21
|
-
"Authorization": f"Bearer {credentials['access_token']}",
|
|
22
|
-
"Accept": "application/vnd.github.v3+json",
|
|
23
|
-
}
|
|
19
|
+
return {"Authorization": f"Bearer {credentials['access_token']}", "Accept": "application/vnd.github.v3+json"}
|
|
24
20
|
|
|
25
|
-
def star_repository(self, repo_full_name: str) -> str:
|
|
21
|
+
async def star_repository(self, repo_full_name: str) -> str:
|
|
26
22
|
"""
|
|
27
23
|
Stars a GitHub repository for the authenticated user. This user-centric action takes the full repository name ('owner/repo') and returns a simple string message confirming the outcome, unlike other functions that list or create repository content like issues or pull requests.
|
|
28
24
|
|
|
@@ -40,7 +36,7 @@ class GithubApp(APIApplication):
|
|
|
40
36
|
star, github, api, action, social, repository, important
|
|
41
37
|
"""
|
|
42
38
|
url = f"https://api.github.com/user/starred/{repo_full_name}"
|
|
43
|
-
response = self.
|
|
39
|
+
response = await self._aput(url, data={})
|
|
44
40
|
if response.status_code == 204:
|
|
45
41
|
return f"Successfully starred repository {repo_full_name}"
|
|
46
42
|
elif response.status_code == 404:
|
|
@@ -49,7 +45,7 @@ class GithubApp(APIApplication):
|
|
|
49
45
|
logger.error(response.text)
|
|
50
46
|
return f"Error starring repository: {response.text}"
|
|
51
47
|
|
|
52
|
-
def list_recent_commits(self, repo_full_name: str) -> str:
|
|
48
|
+
async def list_recent_commits(self, repo_full_name: str) -> str:
|
|
53
49
|
"""
|
|
54
50
|
Fetches and formats the 12 most recent commits from a repository. It returns a human-readable string summarizing each commit's hash, author, and message, providing a focused overview of recent code changes, unlike functions that list branches, issues, or pull requests.
|
|
55
51
|
|
|
@@ -68,21 +64,20 @@ class GithubApp(APIApplication):
|
|
|
68
64
|
"""
|
|
69
65
|
repo_full_name = repo_full_name.strip()
|
|
70
66
|
url = f"{self.base_api_url}/{repo_full_name}/commits"
|
|
71
|
-
response = self.
|
|
67
|
+
response = await self._aget(url)
|
|
72
68
|
response.raise_for_status()
|
|
73
69
|
commits = response.json()
|
|
74
70
|
if not commits:
|
|
75
71
|
return f"No commits found for repository {repo_full_name}"
|
|
76
72
|
result = f"Recent commits for {repo_full_name}:\n\n"
|
|
77
|
-
for commit in commits[:12]:
|
|
73
|
+
for commit in commits[:12]:
|
|
78
74
|
sha = commit.get("sha", "")[:7]
|
|
79
75
|
message = commit.get("commit", {}).get("message", "").split("\n")[0]
|
|
80
76
|
author = commit.get("commit", {}).get("author", {}).get("name", "Unknown")
|
|
81
|
-
|
|
82
77
|
result += f"- {sha}: {message} (by {author})\n"
|
|
83
78
|
return result
|
|
84
79
|
|
|
85
|
-
def list_branches(self, repo_full_name: str) -> str:
|
|
80
|
+
async def list_branches(self, repo_full_name: str) -> str:
|
|
86
81
|
"""
|
|
87
82
|
Fetches all branches for a specified GitHub repository and formats them into a human-readable string. This method is distinct from others like `search_issues`, as it returns a formatted list for display rather than raw JSON data for programmatic use.
|
|
88
83
|
|
|
@@ -101,7 +96,7 @@ class GithubApp(APIApplication):
|
|
|
101
96
|
"""
|
|
102
97
|
repo_full_name = repo_full_name.strip()
|
|
103
98
|
url = f"{self.base_api_url}/{repo_full_name}/branches"
|
|
104
|
-
response = self.
|
|
99
|
+
response = await self._aget(url)
|
|
105
100
|
response.raise_for_status()
|
|
106
101
|
branches = response.json()
|
|
107
102
|
if not branches:
|
|
@@ -112,7 +107,7 @@ class GithubApp(APIApplication):
|
|
|
112
107
|
result += f"- {branch_name}\n"
|
|
113
108
|
return result
|
|
114
109
|
|
|
115
|
-
def list_pull_requests(self, repo_full_name: str, state: str = "open") -> str:
|
|
110
|
+
async def list_pull_requests(self, repo_full_name: str, state: str = "open") -> str:
|
|
116
111
|
"""
|
|
117
112
|
Fetches pull requests for a repository, filtered by state (e.g., 'open'). It returns a formatted string summarizing each PR's details, distinguishing it from `get_pull_request` (single PR) and `search_issues` (raw issue data).
|
|
118
113
|
|
|
@@ -132,7 +127,7 @@ class GithubApp(APIApplication):
|
|
|
132
127
|
repo_full_name = repo_full_name.strip()
|
|
133
128
|
url = f"{self.base_api_url}/{repo_full_name}/pulls"
|
|
134
129
|
params = {"state": state}
|
|
135
|
-
response = self.
|
|
130
|
+
response = await self._aget(url, params=params)
|
|
136
131
|
response.raise_for_status()
|
|
137
132
|
pull_requests = response.json()
|
|
138
133
|
if not pull_requests:
|
|
@@ -143,20 +138,11 @@ class GithubApp(APIApplication):
|
|
|
143
138
|
pr_number = pr.get("number", "Unknown")
|
|
144
139
|
pr_state = pr.get("state", "Unknown")
|
|
145
140
|
pr_user = pr.get("user", {}).get("login", "Unknown")
|
|
146
|
-
|
|
147
|
-
result += (
|
|
148
|
-
f"- PR #{pr_number}: {pr_title} (by {pr_user}, Status: {pr_state})\n"
|
|
149
|
-
)
|
|
141
|
+
result += f"- PR #{pr_number}: {pr_title} (by {pr_user}, Status: {pr_state})\n"
|
|
150
142
|
return result
|
|
151
143
|
|
|
152
|
-
def search_issues(
|
|
153
|
-
self,
|
|
154
|
-
repo_full_name: str,
|
|
155
|
-
state: str = "open",
|
|
156
|
-
assignee: str = None,
|
|
157
|
-
labels: str = None,
|
|
158
|
-
per_page: int = 30,
|
|
159
|
-
page: int = 1,
|
|
144
|
+
async def search_issues(
|
|
145
|
+
self, repo_full_name: str, state: str = "open", assignee: str = None, labels: str = None, per_page: int = 30, page: int = 1
|
|
160
146
|
) -> list[dict[str, Any]]:
|
|
161
147
|
"""
|
|
162
148
|
Fetches issues from a GitHub repository using specified filters (state, assignee, labels) and pagination. It returns the raw API response as a list of dictionaries, providing detailed issue data for programmatic processing, distinct from other methods that return formatted strings.
|
|
@@ -186,11 +172,11 @@ class GithubApp(APIApplication):
|
|
|
186
172
|
params["assignee"] = assignee
|
|
187
173
|
if labels:
|
|
188
174
|
params["labels"] = labels
|
|
189
|
-
response = self.
|
|
175
|
+
response = await self._aget(url, params=params)
|
|
190
176
|
response.raise_for_status()
|
|
191
177
|
return response.json()
|
|
192
178
|
|
|
193
|
-
def get_pull_request(self, repo_full_name: str, pull_number: int) -> str:
|
|
179
|
+
async def get_pull_request(self, repo_full_name: str, pull_number: int) -> str:
|
|
194
180
|
"""
|
|
195
181
|
Fetches a specific pull request from a repository using its unique number. It returns a human-readable string summarizing the PR's title, creator, status, and description, unlike `list_pull_requests` which retrieves a list of multiple PRs.
|
|
196
182
|
|
|
@@ -210,7 +196,7 @@ class GithubApp(APIApplication):
|
|
|
210
196
|
"""
|
|
211
197
|
repo_full_name = repo_full_name.strip()
|
|
212
198
|
url = f"{self.base_api_url}/{repo_full_name}/pulls/{pull_number}"
|
|
213
|
-
response = self.
|
|
199
|
+
response = await self._aget(url)
|
|
214
200
|
response.raise_for_status()
|
|
215
201
|
pr = response.json()
|
|
216
202
|
pr_title = pr.get("title", "No Title")
|
|
@@ -218,15 +204,10 @@ class GithubApp(APIApplication):
|
|
|
218
204
|
pr_state = pr.get("state", "Unknown")
|
|
219
205
|
pr_user = pr.get("user", {}).get("login", "Unknown")
|
|
220
206
|
pr_body = pr.get("body", "No description provided.")
|
|
221
|
-
result =
|
|
222
|
-
f"Pull Request #{pr_number}: {pr_title}\n"
|
|
223
|
-
f"Created by: {pr_user}\n"
|
|
224
|
-
f"Status: {pr_state}\n"
|
|
225
|
-
f"Description: {pr_body}\n"
|
|
226
|
-
)
|
|
207
|
+
result = f"Pull Request #{pr_number}: {pr_title}\nCreated by: {pr_user}\nStatus: {pr_state}\nDescription: {pr_body}\n"
|
|
227
208
|
return result
|
|
228
209
|
|
|
229
|
-
def create_pull_request(
|
|
210
|
+
async def create_pull_request(
|
|
230
211
|
self,
|
|
231
212
|
repo_full_name: str,
|
|
232
213
|
head: str,
|
|
@@ -262,12 +243,7 @@ class GithubApp(APIApplication):
|
|
|
262
243
|
"""
|
|
263
244
|
repo_full_name = repo_full_name.strip()
|
|
264
245
|
url = f"{self.base_api_url}/{repo_full_name}/pulls"
|
|
265
|
-
pull_request_data = {
|
|
266
|
-
"head": head,
|
|
267
|
-
"base": base,
|
|
268
|
-
"maintainer_can_modify": maintainer_can_modify,
|
|
269
|
-
"draft": draft,
|
|
270
|
-
}
|
|
246
|
+
pull_request_data = {"head": head, "base": base, "maintainer_can_modify": maintainer_can_modify, "draft": draft}
|
|
271
247
|
if issue is not None:
|
|
272
248
|
pull_request_data["issue"] = issue
|
|
273
249
|
else:
|
|
@@ -276,13 +252,11 @@ class GithubApp(APIApplication):
|
|
|
276
252
|
pull_request_data["title"] = title
|
|
277
253
|
if body is not None:
|
|
278
254
|
pull_request_data["body"] = body
|
|
279
|
-
response = self.
|
|
255
|
+
response = await self._apost(url, pull_request_data)
|
|
280
256
|
response.raise_for_status()
|
|
281
257
|
return response.json()
|
|
282
258
|
|
|
283
|
-
def create_issue(
|
|
284
|
-
self, repo_full_name: str, title: str, body: str = "", labels=None
|
|
285
|
-
) -> str:
|
|
259
|
+
async def create_issue(self, repo_full_name: str, title: str, body: str = "", labels=None) -> str:
|
|
286
260
|
"""
|
|
287
261
|
Creates a new issue in a GitHub repository using a title, body, and optional labels. It returns a formatted confirmation string with the new issue's number and URL, differing from `update_issue` which modifies existing issues and `search_issues` which returns raw API data.
|
|
288
262
|
|
|
@@ -306,26 +280,18 @@ class GithubApp(APIApplication):
|
|
|
306
280
|
issue_data = {"title": title, "body": body}
|
|
307
281
|
if labels:
|
|
308
282
|
if isinstance(labels, str):
|
|
309
|
-
labels_list = [
|
|
310
|
-
label.strip() for label in labels.split(",") if label.strip()
|
|
311
|
-
]
|
|
283
|
+
labels_list = [label.strip() for label in labels.split(",") if label.strip()]
|
|
312
284
|
issue_data["labels"] = labels_list
|
|
313
285
|
else:
|
|
314
286
|
issue_data["labels"] = labels
|
|
315
|
-
response = self.
|
|
287
|
+
response = await self._apost(url, issue_data)
|
|
316
288
|
response.raise_for_status()
|
|
317
289
|
issue = response.json()
|
|
318
290
|
issue_number = issue.get("number", "Unknown")
|
|
319
291
|
issue_url = issue.get("html_url", "")
|
|
320
|
-
return
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
f"URL: {issue_url}"
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
def list_repo_activities(
|
|
327
|
-
self, repo_full_name: str, direction: str = "desc", per_page: int = 30
|
|
328
|
-
) -> str:
|
|
292
|
+
return f"Successfully created issue #{issue_number}:\nTitle: {title}\nURL: {issue_url}"
|
|
293
|
+
|
|
294
|
+
async def list_repo_activities(self, repo_full_name: str, direction: str = "desc", per_page: int = 30) -> str:
|
|
329
295
|
"""
|
|
330
296
|
Fetches recent events for a GitHub repository and formats them into a human-readable string. It summarizes activities with actors and timestamps, providing a general event feed, unlike other `list_*` functions which retrieve specific resources like commits or issues.
|
|
331
297
|
|
|
@@ -347,24 +313,21 @@ class GithubApp(APIApplication):
|
|
|
347
313
|
repo_full_name = repo_full_name.strip()
|
|
348
314
|
url = f"{self.base_api_url}/{repo_full_name}/activity"
|
|
349
315
|
params = {"direction": direction, "per_page": per_page}
|
|
350
|
-
response = self.
|
|
316
|
+
response = await self._aget(url, params=params)
|
|
351
317
|
response.raise_for_status()
|
|
352
318
|
activities = response.json()
|
|
353
319
|
if not activities:
|
|
354
320
|
return f"No activities found for repository {repo_full_name}"
|
|
355
321
|
result = f"Repository activities for {repo_full_name}:\n\n"
|
|
356
322
|
for activity in activities:
|
|
357
|
-
# Extract common fields
|
|
358
323
|
timestamp = activity.get("timestamp", "Unknown time")
|
|
359
324
|
actor_name = "Unknown user"
|
|
360
325
|
if "actor" in activity and activity["actor"]:
|
|
361
326
|
actor_name = activity["actor"].get("login", "Unknown user")
|
|
362
|
-
|
|
363
|
-
# Create a simple description of the activity
|
|
364
327
|
result += f"- {actor_name} performed an activity at {timestamp}\n"
|
|
365
328
|
return result
|
|
366
329
|
|
|
367
|
-
def update_issue(
|
|
330
|
+
async def update_issue(
|
|
368
331
|
self,
|
|
369
332
|
repo_full_name: str,
|
|
370
333
|
issue_number: int,
|