universal-mcp-applications 0.1.22__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.

Files changed (120) hide show
  1. universal_mcp/applications/ahrefs/app.py +92 -238
  2. universal_mcp/applications/airtable/app.py +23 -122
  3. universal_mcp/applications/apollo/app.py +122 -475
  4. universal_mcp/applications/asana/app.py +605 -1755
  5. universal_mcp/applications/aws_s3/app.py +36 -103
  6. universal_mcp/applications/bill/app.py +644 -2055
  7. universal_mcp/applications/box/app.py +1246 -4159
  8. universal_mcp/applications/braze/app.py +410 -1476
  9. universal_mcp/applications/browser_use/README.md +15 -1
  10. universal_mcp/applications/browser_use/__init__.py +1 -0
  11. universal_mcp/applications/browser_use/app.py +94 -37
  12. universal_mcp/applications/cal_com_v2/app.py +207 -625
  13. universal_mcp/applications/calendly/app.py +103 -242
  14. universal_mcp/applications/canva/app.py +75 -140
  15. universal_mcp/applications/clickup/app.py +331 -798
  16. universal_mcp/applications/coda/app.py +240 -520
  17. universal_mcp/applications/confluence/app.py +497 -1285
  18. universal_mcp/applications/contentful/app.py +36 -151
  19. universal_mcp/applications/crustdata/app.py +42 -121
  20. universal_mcp/applications/dialpad/app.py +451 -924
  21. universal_mcp/applications/digitalocean/app.py +2071 -6082
  22. universal_mcp/applications/domain_checker/app.py +3 -54
  23. universal_mcp/applications/e2b/app.py +14 -64
  24. universal_mcp/applications/elevenlabs/app.py +9 -47
  25. universal_mcp/applications/exa/README.md +8 -4
  26. universal_mcp/applications/exa/app.py +408 -186
  27. universal_mcp/applications/falai/app.py +24 -101
  28. universal_mcp/applications/figma/app.py +91 -175
  29. universal_mcp/applications/file_system/app.py +2 -13
  30. universal_mcp/applications/firecrawl/app.py +186 -163
  31. universal_mcp/applications/fireflies/app.py +59 -281
  32. universal_mcp/applications/fpl/app.py +92 -529
  33. universal_mcp/applications/fpl/utils/fixtures.py +15 -49
  34. universal_mcp/applications/fpl/utils/helper.py +25 -89
  35. universal_mcp/applications/fpl/utils/league_utils.py +20 -64
  36. universal_mcp/applications/ghost_content/app.py +66 -175
  37. universal_mcp/applications/github/app.py +28 -65
  38. universal_mcp/applications/gong/app.py +140 -300
  39. universal_mcp/applications/google_calendar/app.py +26 -78
  40. universal_mcp/applications/google_docs/app.py +324 -354
  41. universal_mcp/applications/google_drive/app.py +194 -793
  42. universal_mcp/applications/google_gemini/app.py +29 -64
  43. universal_mcp/applications/google_mail/README.md +1 -0
  44. universal_mcp/applications/google_mail/app.py +93 -214
  45. universal_mcp/applications/google_searchconsole/app.py +25 -58
  46. universal_mcp/applications/google_sheet/app.py +174 -623
  47. universal_mcp/applications/google_sheet/helper.py +26 -53
  48. universal_mcp/applications/hashnode/app.py +57 -269
  49. universal_mcp/applications/heygen/app.py +77 -155
  50. universal_mcp/applications/http_tools/app.py +10 -32
  51. universal_mcp/applications/hubspot/README.md +1 -1
  52. universal_mcp/applications/hubspot/app.py +7508 -99
  53. universal_mcp/applications/jira/app.py +2419 -8334
  54. universal_mcp/applications/klaviyo/app.py +737 -1619
  55. universal_mcp/applications/linkedin/README.md +23 -4
  56. universal_mcp/applications/linkedin/app.py +861 -155
  57. universal_mcp/applications/mailchimp/app.py +696 -1851
  58. universal_mcp/applications/markitdown/app.py +8 -20
  59. universal_mcp/applications/miro/app.py +333 -815
  60. universal_mcp/applications/ms_teams/app.py +85 -207
  61. universal_mcp/applications/neon/app.py +144 -250
  62. universal_mcp/applications/notion/app.py +36 -51
  63. universal_mcp/applications/onedrive/README.md +24 -0
  64. universal_mcp/applications/onedrive/__init__.py +1 -0
  65. universal_mcp/applications/onedrive/app.py +316 -0
  66. universal_mcp/applications/openai/app.py +42 -165
  67. universal_mcp/applications/outlook/README.md +22 -9
  68. universal_mcp/applications/outlook/app.py +606 -262
  69. universal_mcp/applications/perplexity/README.md +2 -1
  70. universal_mcp/applications/perplexity/app.py +162 -20
  71. universal_mcp/applications/pipedrive/app.py +1021 -3331
  72. universal_mcp/applications/posthog/app.py +272 -541
  73. universal_mcp/applications/reddit/app.py +88 -204
  74. universal_mcp/applications/resend/app.py +41 -107
  75. universal_mcp/applications/retell/app.py +23 -50
  76. universal_mcp/applications/rocketlane/app.py +250 -963
  77. universal_mcp/applications/scraper/README.md +7 -4
  78. universal_mcp/applications/scraper/app.py +245 -283
  79. universal_mcp/applications/semanticscholar/app.py +36 -78
  80. universal_mcp/applications/semrush/app.py +43 -77
  81. universal_mcp/applications/sendgrid/app.py +826 -1576
  82. universal_mcp/applications/sentry/app.py +444 -1079
  83. universal_mcp/applications/serpapi/app.py +40 -143
  84. universal_mcp/applications/sharepoint/README.md +16 -14
  85. universal_mcp/applications/sharepoint/app.py +245 -154
  86. universal_mcp/applications/shopify/app.py +1743 -4479
  87. universal_mcp/applications/shortcut/app.py +272 -534
  88. universal_mcp/applications/slack/app.py +58 -109
  89. universal_mcp/applications/spotify/app.py +206 -405
  90. universal_mcp/applications/supabase/app.py +174 -283
  91. universal_mcp/applications/tavily/app.py +2 -2
  92. universal_mcp/applications/trello/app.py +853 -2816
  93. universal_mcp/applications/twilio/app.py +14 -50
  94. universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
  95. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
  96. universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
  97. universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
  98. universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
  99. universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
  100. universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
  101. universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
  102. universal_mcp/applications/whatsapp/app.py +35 -186
  103. universal_mcp/applications/whatsapp/audio.py +2 -6
  104. universal_mcp/applications/whatsapp/whatsapp.py +17 -51
  105. universal_mcp/applications/whatsapp_business/app.py +86 -299
  106. universal_mcp/applications/wrike/app.py +80 -153
  107. universal_mcp/applications/yahoo_finance/app.py +19 -65
  108. universal_mcp/applications/youtube/app.py +120 -306
  109. universal_mcp/applications/zenquotes/app.py +4 -4
  110. {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/METADATA +4 -2
  111. {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/RECORD +113 -117
  112. {universal_mcp_applications-0.1.22.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/WHEEL +1 -1
  113. universal_mcp/applications/hubspot/api_segments/__init__.py +0 -0
  114. universal_mcp/applications/hubspot/api_segments/api_segment_base.py +0 -54
  115. universal_mcp/applications/hubspot/api_segments/crm_api.py +0 -7337
  116. universal_mcp/applications/hubspot/api_segments/marketing_api.py +0 -1467
  117. universal_mcp/applications/unipile/README.md +0 -28
  118. universal_mcp/applications/unipile/__init__.py +0 -1
  119. universal_mcp/applications/unipile/app.py +0 -1077
  120. {universal_mcp_applications-0.1.22.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 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 = await self._apost(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 = await self._apost(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 = await self._apost(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,
@@ -231,10 +223,10 @@ class SlackApp(APIApplication):
231
223
  ]
232
224
  if v is not None
233
225
  }
234
- response = self._get(url, params=query_params)
226
+ response = await self._aget(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
- response = self._get(url, params=query_params)
262
+ response = await self._aget(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 = await self._apost(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,
@@ -355,10 +330,10 @@ class SlackApp(APIApplication):
355
330
  ]
356
331
  if v is not None
357
332
  }
358
- response = self._get(url, params=query_params)
333
+ response = await self._aget(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,
@@ -403,10 +378,10 @@ class SlackApp(APIApplication):
403
378
  ]
404
379
  if v is not None
405
380
  }
406
- response = self._get(url, params=query_params)
381
+ response = await self._aget(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,
@@ -451,10 +426,10 @@ class SlackApp(APIApplication):
451
426
  ]
452
427
  if v is not None
453
428
  }
454
- response = self._get(url, params=query_params)
429
+ response = await self._aget(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
- }
478
- response = self._get(url, params=query_params)
450
+ query_params = {k: v for k, v in [("token", token), ("team", team)] if v is not None}
451
+ response = await self._aget(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
- }
514
- response = self._get(url, params=query_params)
473
+ query_params = {k: v for k, v in [("token", token), ("include_locale", include_locale), ("user", user)] if v is not None}
474
+ response = await self._aget(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,16 +497,9 @@ 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
- response = self._get(url, params=query_params)
502
+ response = await self._aget(url, params=query_params)
554
503
  return self._handle_response(response)
555
504
 
556
505
  def list_tools(self):