universal-mcp-applications 0.1.30rc1__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 (106) 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 +23 -4
  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 +280 -93
  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.30rc1.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/METADATA +2 -2
  103. {universal_mcp_applications-0.1.30rc1.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/RECORD +105 -106
  104. universal_mcp/applications/scraper/scraper_testers.py +0 -17
  105. {universal_mcp_applications-0.1.30rc1.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/WHEEL +0 -0
  106. {universal_mcp_applications-0.1.30rc1.dist-info → universal_mcp_applications-0.1.36rc1.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,4 @@
1
1
  from typing import Any
2
-
3
2
  from universal_mcp.applications.application import APIApplication
4
3
  from universal_mcp.integrations import Integration
5
4
 
@@ -9,12 +8,30 @@ class SlackApp(APIApplication):
9
8
  super().__init__(name="slack", integration=integration, **kwargs)
10
9
  self.base_url = "https://slack.com/api"
11
10
 
12
- def chat_delete(
13
- self,
14
- as_user: bool | None = None,
15
- channel: str | None = None,
16
- ts: float | None = None,
17
- ) -> dict[str, Any]:
11
+ def _get_headers(self) -> dict[str, str]:
12
+ """
13
+ Get headers for Slack API requests.
14
+ Prioritizes user-scoped access token from raw.authed_user.access_token
15
+ over the bot token at the root level.
16
+ """
17
+ if not self.integration:
18
+ raise ValueError("Integration not configured for SlackApp")
19
+ credentials = self.integration.get_credentials()
20
+ if not credentials:
21
+ raise ValueError("No credentials found for Slack integration")
22
+ access_token = None
23
+ raw = credentials.get("raw", {})
24
+ if isinstance(raw, dict) and "authed_user" in raw:
25
+ authed_user = raw.get("authed_user", {})
26
+ if isinstance(authed_user, dict):
27
+ access_token = authed_user.get("access_token")
28
+ if not access_token:
29
+ access_token = credentials.get("access_token")
30
+ if not access_token:
31
+ raise ValueError("Access token not found in Slack credentials")
32
+ return {"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"}
33
+
34
+ async def chat_delete(self, as_user: bool | None = None, channel: str | None = None, ts: float | None = None) -> dict[str, Any]:
18
35
  """
19
36
  Deletes a specific message from a Slack channel. It identifies the message using its channel ID and timestamp (`ts`). This function is distinct from `chat_update` which modifies a message, and `chat_post_message` which sends a new one.
20
37
 
@@ -33,25 +50,14 @@ class SlackApp(APIApplication):
33
50
  chat
34
51
  """
35
52
  request_body_data = None
36
- request_body_data = {
37
- "as_user": as_user,
38
- "channel": channel,
39
- "ts": ts,
40
- }
41
- request_body_data = {
42
- k: v for k, v in request_body_data.items() if v is not None
43
- }
53
+ request_body_data = {"as_user": as_user, "channel": channel, "ts": ts}
54
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
44
55
  url = f"{self.base_url}/chat.delete"
45
56
  query_params = {}
46
- response = self._post(
47
- url,
48
- data=request_body_data,
49
- params=query_params,
50
- content_type="application/x-www-form-urlencoded",
51
- )
57
+ response = self._post(url, data=request_body_data, params=query_params, content_type="application/x-www-form-urlencoded")
52
58
  return self._handle_response(response)
53
59
 
54
- def chat_post_message(
60
+ async def chat_post_message(
55
61
  self,
56
62
  as_user: bool | None = None,
57
63
  attachments: str | None = None,
@@ -116,20 +122,13 @@ class SlackApp(APIApplication):
116
122
  "unfurl_media": unfurl_media,
117
123
  "username": username,
118
124
  }
119
- request_body_data = {
120
- k: v for k, v in request_body_data.items() if v is not None
121
- }
125
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
122
126
  url = f"{self.base_url}/chat.postMessage"
123
127
  query_params = {}
124
- response = self._post(
125
- url,
126
- data=request_body_data,
127
- params=query_params,
128
- content_type="application/x-www-form-urlencoded",
129
- )
128
+ response = self._post(url, data=request_body_data, params=query_params, content_type="application/x-www-form-urlencoded")
130
129
  return self._handle_response(response)
131
130
 
132
- def chat_update(
131
+ async def chat_update(
133
132
  self,
134
133
  as_user: str | None = None,
135
134
  attachments: str | None = None,
@@ -173,20 +172,13 @@ class SlackApp(APIApplication):
173
172
  "text": text,
174
173
  "ts": ts,
175
174
  }
176
- request_body_data = {
177
- k: v for k, v in request_body_data.items() if v is not None
178
- }
175
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
179
176
  url = f"{self.base_url}/chat.update"
180
177
  query_params = {}
181
- response = self._post(
182
- url,
183
- data=request_body_data,
184
- params=query_params,
185
- content_type="application/x-www-form-urlencoded",
186
- )
178
+ response = self._post(url, data=request_body_data, params=query_params, content_type="application/x-www-form-urlencoded")
187
179
  return self._handle_response(response)
188
180
 
189
- def conversations_history(
181
+ async def conversations_history(
190
182
  self,
191
183
  token: str | None = None,
192
184
  channel: str | None = None,
@@ -234,7 +226,7 @@ class SlackApp(APIApplication):
234
226
  response = self._get(url, params=query_params)
235
227
  return self._handle_response(response)
236
228
 
237
- def conversations_list(
229
+ async def conversations_list(
238
230
  self,
239
231
  token: str | None = None,
240
232
  exclude_archived: bool | None = None,
@@ -264,19 +256,13 @@ class SlackApp(APIApplication):
264
256
  url = f"{self.base_url}/conversations.list"
265
257
  query_params = {
266
258
  k: v
267
- for k, v in [
268
- ("token", token),
269
- ("exclude_archived", exclude_archived),
270
- ("types", types),
271
- ("limit", limit),
272
- ("cursor", cursor),
273
- ]
259
+ for k, v in [("token", token), ("exclude_archived", exclude_archived), ("types", types), ("limit", limit), ("cursor", cursor)]
274
260
  if v is not None
275
261
  }
276
262
  response = self._get(url, params=query_params)
277
263
  return self._handle_response(response)
278
264
 
279
- def reactions_add(self, channel: str, name: str, timestamp: str) -> dict[str, Any]:
265
+ async def reactions_add(self, channel: str, name: str, timestamp: str) -> dict[str, Any]:
280
266
  """
281
267
  Adds a specific emoji reaction to a message in a Slack channel, identifying the message by its channel ID and timestamp. This method creates a new reaction, unlike `reactions_get` or `reactions_list` which retrieve existing reaction data for items or users.
282
268
 
@@ -295,25 +281,14 @@ class SlackApp(APIApplication):
295
281
  reactions
296
282
  """
297
283
  request_body_data = None
298
- request_body_data = {
299
- "channel": channel,
300
- "name": name,
301
- "timestamp": timestamp,
302
- }
303
- request_body_data = {
304
- k: v for k, v in request_body_data.items() if v is not None
305
- }
284
+ request_body_data = {"channel": channel, "name": name, "timestamp": timestamp}
285
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
306
286
  url = f"{self.base_url}/reactions.add"
307
287
  query_params = {}
308
- response = self._post(
309
- url,
310
- data=request_body_data,
311
- params=query_params,
312
- content_type="application/x-www-form-urlencoded",
313
- )
288
+ response = self._post(url, data=request_body_data, params=query_params, content_type="application/x-www-form-urlencoded")
314
289
  return self._handle_response(response)
315
290
 
316
- def get_reactions_for_item(
291
+ async def get_reactions_for_item(
317
292
  self,
318
293
  token: str,
319
294
  channel: str | None = None,
@@ -358,7 +333,7 @@ class SlackApp(APIApplication):
358
333
  response = self._get(url, params=query_params)
359
334
  return self._handle_response(response)
360
335
 
361
- def get_user_reactions(
336
+ async def get_user_reactions(
362
337
  self,
363
338
  token: str,
364
339
  user: str | None = None,
@@ -406,7 +381,7 @@ class SlackApp(APIApplication):
406
381
  response = self._get(url, params=query_params)
407
382
  return self._handle_response(response)
408
383
 
409
- def search_messages(
384
+ async def search_messages(
410
385
  self,
411
386
  token: str,
412
387
  query: str,
@@ -454,7 +429,7 @@ class SlackApp(APIApplication):
454
429
  response = self._get(url, params=query_params)
455
430
  return self._handle_response(response)
456
431
 
457
- def team_info(self, token: str, team: str | None = None) -> dict[str, Any]:
432
+ async def team_info(self, token: str, team: str | None = None) -> dict[str, Any]:
458
433
  """
459
434
  Fetches details for a Slack team, such as name and domain, by calling the `team.info` API endpoint. This function requires an authentication token and can optionally target a specific team by its ID, distinguishing it from user or channel-specific functions.
460
435
 
@@ -472,18 +447,11 @@ class SlackApp(APIApplication):
472
447
  team
473
448
  """
474
449
  url = f"{self.base_url}/team.info"
475
- query_params = {
476
- k: v for k, v in [("token", token), ("team", team)] if v is not None
477
- }
450
+ query_params = {k: v for k, v in [("token", token), ("team", team)] if v is not None}
478
451
  response = self._get(url, params=query_params)
479
452
  return self._handle_response(response)
480
453
 
481
- def get_user_info(
482
- self,
483
- token: str,
484
- include_locale: bool | None = None,
485
- user: str | None = None,
486
- ) -> dict[str, Any]:
454
+ async def get_user_info(self, token: str, include_locale: bool | None = None, user: str | None = None) -> dict[str, Any]:
487
455
  """
488
456
  Fetches detailed profile information for a single Slack user, identified by their user ID. Unlike `users_list`, which retrieves all workspace members, this function targets an individual and can optionally include their locale information. It directly calls the `users.info` Slack API endpoint.
489
457
 
@@ -502,24 +470,12 @@ class SlackApp(APIApplication):
502
470
  users, important
503
471
  """
504
472
  url = f"{self.base_url}/users.info"
505
- query_params = {
506
- k: v
507
- for k, v in [
508
- ("token", token),
509
- ("include_locale", include_locale),
510
- ("user", user),
511
- ]
512
- if v is not None
513
- }
473
+ query_params = {k: v for k, v in [("token", token), ("include_locale", include_locale), ("user", user)] if v is not None}
514
474
  response = self._get(url, params=query_params)
515
475
  return self._handle_response(response)
516
476
 
517
- def users_list(
518
- self,
519
- token: str | None = None,
520
- limit: int | None = None,
521
- cursor: str | None = None,
522
- include_locale: bool | None = None,
477
+ async def users_list(
478
+ self, token: str | None = None, limit: int | None = None, cursor: str | None = None, include_locale: bool | None = None
523
479
  ) -> dict[str, Any]:
524
480
  """
525
481
  Fetches a paginated list of all users in a Slack workspace, including deactivated members. Unlike `users_info` which retrieves a single user's details, this function returns a collection and supports limiting results or including locale data through optional parameters.
@@ -541,14 +497,7 @@ class SlackApp(APIApplication):
541
497
  """
542
498
  url = f"{self.base_url}/users.list"
543
499
  query_params = {
544
- k: v
545
- for k, v in [
546
- ("token", token),
547
- ("limit", limit),
548
- ("cursor", cursor),
549
- ("include_locale", include_locale),
550
- ]
551
- if v is not None
500
+ k: v for k, v in [("token", token), ("limit", limit), ("cursor", cursor), ("include_locale", include_locale)] if v is not None
552
501
  }
553
502
  response = self._get(url, params=query_params)
554
503
  return self._handle_response(response)