universal-mcp-applications 0.1.30__py3-none-any.whl → 0.1.36rc1__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.

Files changed (105) hide show
  1. universal_mcp/applications/ahrefs/app.py +52 -198
  2. universal_mcp/applications/airtable/app.py +23 -122
  3. universal_mcp/applications/apollo/app.py +111 -464
  4. universal_mcp/applications/asana/app.py +417 -1567
  5. universal_mcp/applications/aws_s3/app.py +33 -100
  6. universal_mcp/applications/bill/app.py +546 -1957
  7. universal_mcp/applications/box/app.py +1068 -3981
  8. universal_mcp/applications/braze/app.py +364 -1430
  9. universal_mcp/applications/browser_use/app.py +2 -8
  10. universal_mcp/applications/cal_com_v2/app.py +207 -625
  11. universal_mcp/applications/calendly/app.py +61 -200
  12. universal_mcp/applications/canva/app.py +45 -110
  13. universal_mcp/applications/clickup/app.py +207 -674
  14. universal_mcp/applications/coda/app.py +146 -426
  15. universal_mcp/applications/confluence/app.py +310 -1098
  16. universal_mcp/applications/contentful/app.py +36 -151
  17. universal_mcp/applications/crustdata/app.py +28 -107
  18. universal_mcp/applications/dialpad/app.py +283 -756
  19. universal_mcp/applications/digitalocean/app.py +1766 -5777
  20. universal_mcp/applications/domain_checker/app.py +3 -54
  21. universal_mcp/applications/e2b/app.py +14 -64
  22. universal_mcp/applications/elevenlabs/app.py +9 -47
  23. universal_mcp/applications/exa/app.py +6 -17
  24. universal_mcp/applications/falai/app.py +23 -100
  25. universal_mcp/applications/figma/app.py +53 -137
  26. universal_mcp/applications/file_system/app.py +2 -13
  27. universal_mcp/applications/firecrawl/app.py +51 -152
  28. universal_mcp/applications/fireflies/app.py +59 -281
  29. universal_mcp/applications/fpl/app.py +91 -528
  30. universal_mcp/applications/fpl/utils/fixtures.py +15 -49
  31. universal_mcp/applications/fpl/utils/helper.py +25 -89
  32. universal_mcp/applications/fpl/utils/league_utils.py +20 -64
  33. universal_mcp/applications/ghost_content/app.py +52 -161
  34. universal_mcp/applications/github/app.py +19 -56
  35. universal_mcp/applications/gong/app.py +88 -248
  36. universal_mcp/applications/google_calendar/app.py +16 -68
  37. universal_mcp/applications/google_docs/app.py +88 -188
  38. universal_mcp/applications/google_drive/app.py +140 -462
  39. universal_mcp/applications/google_gemini/app.py +12 -64
  40. universal_mcp/applications/google_mail/app.py +28 -157
  41. universal_mcp/applications/google_searchconsole/app.py +15 -48
  42. universal_mcp/applications/google_sheet/app.py +101 -578
  43. universal_mcp/applications/google_sheet/helper.py +10 -37
  44. universal_mcp/applications/hashnode/app.py +57 -269
  45. universal_mcp/applications/heygen/app.py +44 -122
  46. universal_mcp/applications/http_tools/app.py +10 -32
  47. universal_mcp/applications/hubspot/api_segments/crm_api.py +460 -1573
  48. universal_mcp/applications/hubspot/api_segments/marketing_api.py +74 -262
  49. universal_mcp/applications/hubspot/app.py +23 -87
  50. universal_mcp/applications/jira/app.py +2071 -7986
  51. universal_mcp/applications/klaviyo/app.py +494 -1376
  52. universal_mcp/applications/linkedin/README.md +9 -2
  53. universal_mcp/applications/linkedin/app.py +392 -212
  54. universal_mcp/applications/mailchimp/app.py +450 -1605
  55. universal_mcp/applications/markitdown/app.py +8 -20
  56. universal_mcp/applications/miro/app.py +217 -699
  57. universal_mcp/applications/ms_teams/app.py +64 -186
  58. universal_mcp/applications/neon/app.py +86 -192
  59. universal_mcp/applications/notion/app.py +21 -36
  60. universal_mcp/applications/onedrive/app.py +14 -36
  61. universal_mcp/applications/openai/app.py +42 -165
  62. universal_mcp/applications/outlook/app.py +16 -76
  63. universal_mcp/applications/perplexity/app.py +4 -19
  64. universal_mcp/applications/pipedrive/app.py +832 -3142
  65. universal_mcp/applications/posthog/app.py +163 -432
  66. universal_mcp/applications/reddit/app.py +40 -139
  67. universal_mcp/applications/resend/app.py +41 -107
  68. universal_mcp/applications/retell/app.py +14 -41
  69. universal_mcp/applications/rocketlane/app.py +221 -934
  70. universal_mcp/applications/scraper/README.md +7 -4
  71. universal_mcp/applications/scraper/app.py +216 -102
  72. universal_mcp/applications/semanticscholar/app.py +22 -64
  73. universal_mcp/applications/semrush/app.py +43 -77
  74. universal_mcp/applications/sendgrid/app.py +512 -1262
  75. universal_mcp/applications/sentry/app.py +271 -906
  76. universal_mcp/applications/serpapi/app.py +40 -143
  77. universal_mcp/applications/sharepoint/app.py +15 -37
  78. universal_mcp/applications/shopify/app.py +1551 -4287
  79. universal_mcp/applications/shortcut/app.py +155 -417
  80. universal_mcp/applications/slack/app.py +50 -101
  81. universal_mcp/applications/spotify/app.py +126 -325
  82. universal_mcp/applications/supabase/app.py +104 -213
  83. universal_mcp/applications/tavily/app.py +1 -1
  84. universal_mcp/applications/trello/app.py +693 -2656
  85. universal_mcp/applications/twilio/app.py +14 -50
  86. universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
  87. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
  88. universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
  89. universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
  90. universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
  91. universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
  92. universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
  93. universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
  94. universal_mcp/applications/whatsapp/app.py +35 -186
  95. universal_mcp/applications/whatsapp/audio.py +2 -6
  96. universal_mcp/applications/whatsapp/whatsapp.py +17 -51
  97. universal_mcp/applications/whatsapp_business/app.py +70 -283
  98. universal_mcp/applications/wrike/app.py +45 -118
  99. universal_mcp/applications/yahoo_finance/app.py +19 -65
  100. universal_mcp/applications/youtube/app.py +75 -261
  101. universal_mcp/applications/zenquotes/app.py +2 -2
  102. {universal_mcp_applications-0.1.30.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/METADATA +2 -2
  103. {universal_mcp_applications-0.1.30.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/RECORD +105 -105
  104. {universal_mcp_applications-0.1.30.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/WHEEL +0 -0
  105. {universal_mcp_applications-0.1.30.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,5 @@
1
1
  from typing import Any
2
2
  from urllib.parse import parse_qs, urlparse
3
-
4
3
  from universal_mcp.applications.application import APIApplication
5
4
  from universal_mcp.integrations import Integration
6
5
 
@@ -10,12 +9,8 @@ class OutlookApp(APIApplication):
10
9
  super().__init__(name="outlook", integration=integration, **kwargs)
11
10
  self.base_url = "https://graph.microsoft.com/v1.0"
12
11
 
13
- def reply_to_email(
14
- self,
15
- message_id: str,
16
- comment: str,
17
- user_id: str | None = None,
18
- attachments: list[dict[str, Any]] | None = None,
12
+ async def reply_to_email(
13
+ self, message_id: str, comment: str, user_id: str | None = None, attachments: list[dict[str, Any]] | None = None
19
14
  ) -> dict[str, Any]:
20
15
  """
21
16
  Replies to a specific email message.
@@ -53,22 +48,14 @@ class OutlookApp(APIApplication):
53
48
  raise ValueError("Could not retrieve user ID from get_my_profile response.")
54
49
  if not message_id:
55
50
  raise ValueError("Missing required parameter 'message_id'.")
56
-
57
51
  request_body_data = {"comment": comment}
58
52
  if attachments:
59
53
  request_body_data["message"] = {"attachments": attachments}
60
-
61
54
  url = f"{self.base_url}/users/{user_id}/messages/{message_id}/reply"
62
-
63
- response = self._post(
64
- url,
65
- data=request_body_data,
66
- params={},
67
- content_type="application/json",
68
- )
55
+ response = self._post(url, data=request_body_data, params={}, content_type="application/json")
69
56
  return self._handle_response(response)
70
57
 
71
- def send_email(
58
+ async def send_email(
72
59
  self,
73
60
  subject: str,
74
61
  body: str,
@@ -109,7 +96,6 @@ class OutlookApp(APIApplication):
109
96
  user_id = user_info.get("userPrincipalName")
110
97
  if not user_id:
111
98
  raise ValueError("Could not retrieve user ID from get_my_profile response.")
112
-
113
99
  message = {
114
100
  "subject": subject,
115
101
  "body": {"contentType": body_content_type, "content": body},
@@ -121,23 +107,12 @@ class OutlookApp(APIApplication):
121
107
  message["bccRecipients"] = [{"emailAddress": {"address": email}} for email in bcc_recipients]
122
108
  if attachments:
123
109
  message["attachments"] = attachments
124
-
125
- request_body_data = {
126
- "message": message,
127
- "saveToSentItems": save_to_sent_items,
128
- }
129
-
110
+ request_body_data = {"message": message, "saveToSentItems": save_to_sent_items}
130
111
  url = f"{self.base_url}/users/{user_id}/sendMail"
131
-
132
- response = self._post(
133
- url,
134
- data=request_body_data,
135
- params={},
136
- content_type="application/json",
137
- )
112
+ response = self._post(url, data=request_body_data, params={}, content_type="application/json")
138
113
  return self._handle_response(response)
139
114
 
140
- def get_email_folder(
115
+ async def get_email_folder(
141
116
  self,
142
117
  folder_id: str,
143
118
  user_id: str | None = None,
@@ -171,24 +146,16 @@ class OutlookApp(APIApplication):
171
146
  raise ValueError("Could not retrieve user ID from get_my_profile response.")
172
147
  if not folder_id:
173
148
  raise ValueError("Missing required parameter 'folder_id'.")
174
-
175
149
  url = f"{self.base_url}/users/{user_id}/mailFolders/{folder_id}"
176
150
  select_str = ",".join(select) if select else None
177
151
  expand_str = ",".join(expand) if expand else None
178
-
179
152
  query_params = {
180
- k: v
181
- for k, v in [
182
- ("includeHiddenFolders", include_hidden),
183
- ("$select", select_str),
184
- ("$expand", expand_str),
185
- ]
186
- if v is not None
153
+ k: v for k, v in [("includeHiddenFolders", include_hidden), ("$select", select_str), ("$expand", expand_str)] if v is not None
187
154
  }
188
155
  response = self._get(url, params=query_params)
189
156
  return self._handle_response(response)
190
157
 
191
- def list_emails(
158
+ async def list_emails(
192
159
  self,
193
160
  user_id: str | None = None,
194
161
  select: list[str] = ["bodyPreview"],
@@ -232,18 +199,15 @@ class OutlookApp(APIApplication):
232
199
  raise ValueError("The 'search' parameter cannot be used with 'orderby'.")
233
200
  if skip:
234
201
  raise ValueError("The 'search' parameter cannot be used with 'skip'. Use pagination via @odata.nextLink instead.")
235
-
236
202
  if user_id is None:
237
203
  user_info = self.get_my_profile()
238
204
  user_id = user_info.get("userPrincipalName")
239
205
  if not user_id:
240
206
  raise ValueError("Could not retrieve user ID from get_my_profile response.")
241
-
242
207
  url = f"{self.base_url}/users/{user_id}/messages"
243
208
  select_str = ",".join(select) if select else None
244
209
  orderby_str = ",".join(orderby) if orderby else None
245
210
  expand_str = ",".join(expand) if expand else None
246
-
247
211
  query_params = {
248
212
  k: v
249
213
  for k, v in [
@@ -259,11 +223,10 @@ class OutlookApp(APIApplication):
259
223
  ]
260
224
  if v is not None
261
225
  }
262
-
263
226
  response = self._get(url, params=query_params)
264
227
  return self._handle_response(response)
265
228
 
266
- def get_email(
229
+ async def get_email(
267
230
  self,
268
231
  message_id: str,
269
232
  user_id: str | None = None,
@@ -297,24 +260,16 @@ class OutlookApp(APIApplication):
297
260
  raise ValueError("Could not retrieve user ID from get_my_profile response.")
298
261
  if not message_id:
299
262
  raise ValueError("Missing required parameter 'message_id'.")
300
-
301
263
  url = f"{self.base_url}/users/{user_id}/messages/{message_id}"
302
264
  select_str = ",".join(select) if select else None
303
265
  expand_str = ",".join(expand) if expand else None
304
-
305
266
  query_params = {
306
- k: v
307
- for k, v in [
308
- ("includeHiddenMessages", include_hidden),
309
- ("$select", select_str),
310
- ("$expand", expand_str),
311
- ]
312
- if v is not None
267
+ k: v for k, v in [("includeHiddenMessages", include_hidden), ("$select", select_str), ("$expand", expand_str)] if v is not None
313
268
  }
314
269
  response = self._get(url, params=query_params)
315
270
  return self._handle_response(response)
316
271
 
317
- def delete_email(self, message_id: str, user_id: str | None = None) -> dict[str, Any]:
272
+ async def delete_email(self, message_id: str, user_id: str | None = None) -> dict[str, Any]:
318
273
  """
319
274
  Permanently deletes a specific email by its ID.
320
275
 
@@ -338,12 +293,11 @@ class OutlookApp(APIApplication):
338
293
  raise ValueError("Could not retrieve user ID from get_my_profile response.")
339
294
  if not message_id:
340
295
  raise ValueError("Missing required parameter 'message_id'.")
341
-
342
296
  url = f"{self.base_url}/users/{user_id}/messages/{message_id}"
343
297
  response = self._delete(url, params={})
344
298
  return self._handle_response(response)
345
299
 
346
- def list_email_attachments(
300
+ async def list_email_attachments(
347
301
  self,
348
302
  message_id: str,
349
303
  user_id: str | None = None,
@@ -387,7 +341,6 @@ class OutlookApp(APIApplication):
387
341
  raise ValueError("The 'search' parameter cannot be used with 'orderby'.")
388
342
  if skip:
389
343
  raise ValueError("The 'search' parameter cannot be used with 'skip'. Use pagination via @odata.nextLink instead.")
390
-
391
344
  if user_id is None:
392
345
  user_info = self.get_my_profile()
393
346
  user_id = user_info.get("userPrincipalName")
@@ -395,12 +348,10 @@ class OutlookApp(APIApplication):
395
348
  raise ValueError("Could not retrieve user ID from get_my_profile response.")
396
349
  if not message_id:
397
350
  raise ValueError("Missing required parameter 'message_id'.")
398
-
399
351
  url = f"{self.base_url}/users/{user_id}/messages/{message_id}/attachments"
400
352
  orderby_str = ",".join(orderby) if orderby else None
401
353
  select_str = ",".join(select) if select else None
402
354
  expand_str = ",".join(expand) if expand else None
403
-
404
355
  query_params = {
405
356
  k: v
406
357
  for k, v in [
@@ -418,12 +369,7 @@ class OutlookApp(APIApplication):
418
369
  response = self._get(url, params=query_params)
419
370
  return self._handle_response(response)
420
371
 
421
- def get_attachment(
422
- self,
423
- message_id: str,
424
- attachment_id: str,
425
- user_id: str | None = None,
426
- ) -> dict[str, Any]:
372
+ async def get_attachment(self, message_id: str, attachment_id: str, user_id: str | None = None) -> dict[str, Any]:
427
373
  """
428
374
  Retrieves a specific attachment from an email message and formats it as a dictionary.
429
375
 
@@ -448,17 +394,13 @@ class OutlookApp(APIApplication):
448
394
  raise ValueError("Could not retrieve user ID.")
449
395
  if not message_id or not attachment_id:
450
396
  raise ValueError("Missing required parameter 'message_id' or 'attachment_id'.")
451
-
452
397
  url = f"{self.base_url}/users/{user_id}/messages/{message_id}/attachments/{attachment_id}"
453
-
454
398
  response = self._get(url, params={})
455
399
  attachment_data = self._handle_response(response)
456
-
457
400
  content_type = attachment_data.get("contentType", "application/octet-stream")
458
401
  attachment_type = content_type.split("/")[0] if "/" in content_type else "file"
459
402
  if attachment_type not in ["image", "audio", "video", "text"]:
460
403
  attachment_type = "file"
461
-
462
404
  return {
463
405
  "type": attachment_type,
464
406
  "data": attachment_data.get("contentBytes"),
@@ -466,7 +408,7 @@ class OutlookApp(APIApplication):
466
408
  "file_name": attachment_data.get("name"),
467
409
  }
468
410
 
469
- def get_my_profile(self) -> dict[str, Any]:
411
+ async def get_my_profile(self) -> dict[str, Any]:
470
412
  """
471
413
  Fetches the userPrincipalName for the currently authenticated user.
472
414
 
@@ -481,7 +423,7 @@ class OutlookApp(APIApplication):
481
423
  response = self._get(url, params=query_params)
482
424
  return self._handle_response(response)
483
425
 
484
- def get_next_page_results(self, url: str) -> dict[str, Any]:
426
+ async def get_next_page_results(self, url: str) -> dict[str, Any]:
485
427
  """
486
428
  Retrieves the next page of results from a paginated API response.
487
429
 
@@ -500,12 +442,10 @@ class OutlookApp(APIApplication):
500
442
  raise ValueError("Missing required parameter 'url'.")
501
443
  if not url.startswith(self.base_url):
502
444
  raise ValueError(f"The provided URL must start with '{self.base_url}'.")
503
-
504
445
  relative_part = url[len(self.base_url) :]
505
446
  parsed_relative = urlparse(relative_part)
506
447
  path_only = parsed_relative.path
507
448
  params = {k: v[0] for k, v in parse_qs(parsed_relative.query).items()}
508
-
509
449
  response = self._get(path_only, params=params)
510
450
  return self._handle_response(response)
511
451
 
@@ -1,5 +1,4 @@
1
1
  from typing import Any, Literal
2
-
3
2
  from universal_mcp.applications.application import APIApplication
4
3
  from universal_mcp.integrations import Integration
5
4
 
@@ -9,17 +8,10 @@ class PerplexityApp(APIApplication):
9
8
  super().__init__(name="perplexity", integration=integration)
10
9
  self.base_url = "https://api.perplexity.ai"
11
10
 
12
- def answer_with_search(
11
+ async def answer_with_search(
13
12
  self,
14
13
  query: str,
15
- model: Literal[
16
- "r1-1776",
17
- "sonar",
18
- "sonar-pro",
19
- "sonar-reasoning",
20
- "sonar-reasoning-pro",
21
- "sonar-deep-research",
22
- ] = "sonar-pro",
14
+ model: Literal["r1-1776", "sonar", "sonar-pro", "sonar-reasoning", "sonar-reasoning-pro", "sonar-deep-research"] = "sonar-pro",
23
15
  temperature: float = 1,
24
16
  system_prompt: str = "You are a helpful AI assistant that answers questions using real-time information from the web.",
25
17
  ) -> dict[str, Any] | str:
@@ -47,12 +39,7 @@ class PerplexityApp(APIApplication):
47
39
  if system_prompt:
48
40
  messages.append({"role": "system", "content": system_prompt})
49
41
  messages.append({"role": "user", "content": query})
50
- payload = {
51
- "model": model,
52
- "messages": messages,
53
- "temperature": temperature,
54
- # "max_tokens": 512,
55
- }
42
+ payload = {"model": model, "messages": messages, "temperature": temperature}
56
43
  data = self._post(endpoint, data=payload)
57
44
  response = data.json()
58
45
  content = response["choices"][0]["message"]["content"]
@@ -60,6 +47,4 @@ class PerplexityApp(APIApplication):
60
47
  return {"content": content, "citations": citations}
61
48
 
62
49
  def list_tools(self):
63
- return [
64
- self.answer_with_search,
65
- ]
50
+ return [self.answer_with_search]