universal-mcp-applications 0.1.2__py3-none-any.whl → 0.1.3__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.
Files changed (80) hide show
  1. universal_mcp/applications/airtable/app.py +1 -0
  2. universal_mcp/applications/apollo/app.py +1 -0
  3. universal_mcp/applications/aws_s3/app.py +3 -4
  4. universal_mcp/applications/bill/app.py +3 -3
  5. universal_mcp/applications/box/app.py +2 -6
  6. universal_mcp/applications/braze/app.py +2 -6
  7. universal_mcp/applications/cal_com_v2/app.py +22 -64
  8. universal_mcp/applications/confluence/app.py +1 -0
  9. universal_mcp/applications/contentful/app.py +8 -19
  10. universal_mcp/applications/digitalocean/app.py +9 -27
  11. universal_mcp/applications/{domain-checker → domain_checker}/app.py +2 -1
  12. universal_mcp/applications/elevenlabs/app.py +98 -3188
  13. universal_mcp/applications/falai/app.py +1 -0
  14. universal_mcp/applications/file_system/__init__.py +1 -0
  15. universal_mcp/applications/file_system/app.py +96 -0
  16. universal_mcp/applications/fireflies/app.py +4 -3
  17. universal_mcp/applications/fpl/app.py +1 -0
  18. universal_mcp/applications/fpl/utils/fixtures.py +1 -1
  19. universal_mcp/applications/fpl/utils/helper.py +1 -1
  20. universal_mcp/applications/fpl/utils/position_utils.py +0 -1
  21. universal_mcp/applications/{ghost-content → ghost_content}/app.py +2 -1
  22. universal_mcp/applications/github/app.py +3 -1
  23. universal_mcp/applications/google_calendar/app.py +2 -1
  24. universal_mcp/applications/google_docs/app.py +1 -1
  25. universal_mcp/applications/google_drive/app.py +2 -1
  26. universal_mcp/applications/google_gemini/app.py +138 -618
  27. universal_mcp/applications/google_mail/app.py +2 -1
  28. universal_mcp/applications/{google-searchconsole → google_searchconsole}/app.py +1 -1
  29. universal_mcp/applications/google_sheet/app.py +2 -1
  30. universal_mcp/applications/google_sheet/helper.py +156 -116
  31. universal_mcp/applications/hashnode/app.py +1 -0
  32. universal_mcp/applications/{http-tools → http_tools}/app.py +2 -1
  33. universal_mcp/applications/hubspot/app.py +4 -1
  34. universal_mcp/applications/jira/app.py +7 -18
  35. universal_mcp/applications/markitdown/app.py +2 -3
  36. universal_mcp/applications/ms_teams/app.py +1 -1
  37. universal_mcp/applications/openai/app.py +2 -3
  38. universal_mcp/applications/outlook/app.py +1 -3
  39. universal_mcp/applications/pipedrive/app.py +2 -6
  40. universal_mcp/applications/reddit/app.py +1 -0
  41. universal_mcp/applications/replicate/app.py +3 -3
  42. universal_mcp/applications/resend/app.py +1 -2
  43. universal_mcp/applications/rocketlane/app.py +1 -0
  44. universal_mcp/applications/semrush/app.py +1 -1
  45. universal_mcp/applications/sentry/README.md +20 -20
  46. universal_mcp/applications/sentry/app.py +40 -40
  47. universal_mcp/applications/serpapi/app.py +2 -2
  48. universal_mcp/applications/sharepoint/app.py +1 -0
  49. universal_mcp/applications/shopify/app.py +1 -0
  50. universal_mcp/applications/slack/app.py +3 -3
  51. universal_mcp/applications/trello/app.py +9 -27
  52. universal_mcp/applications/twilio/__init__.py +1 -0
  53. universal_mcp/applications/{twillo → twilio}/app.py +2 -2
  54. universal_mcp/applications/twitter/README.md +1 -1
  55. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +2 -2
  56. universal_mcp/applications/twitter/api_segments/lists_api.py +1 -1
  57. universal_mcp/applications/unipile/app.py +5 -1
  58. universal_mcp/applications/whatsapp/app.py +18 -17
  59. universal_mcp/applications/whatsapp/audio.py +110 -0
  60. universal_mcp/applications/whatsapp/whatsapp.py +398 -0
  61. universal_mcp/applications/whatsapp_business/app.py +1 -1
  62. universal_mcp/applications/youtube/app.py +195 -191
  63. universal_mcp/applications/zenquotes/app.py +1 -1
  64. {universal_mcp_applications-0.1.2.dist-info → universal_mcp_applications-0.1.3.dist-info}/METADATA +4 -2
  65. {universal_mcp_applications-0.1.2.dist-info → universal_mcp_applications-0.1.3.dist-info}/RECORD +76 -75
  66. universal_mcp/applications/google-ads/__init__.py +0 -1
  67. universal_mcp/applications/google-ads/app.py +0 -23
  68. universal_mcp/applications/twillo/README.md +0 -0
  69. universal_mcp/applications/twillo/__init__.py +0 -1
  70. /universal_mcp/applications/{domain-checker → domain_checker}/README.md +0 -0
  71. /universal_mcp/applications/{domain-checker → domain_checker}/__init__.py +0 -0
  72. /universal_mcp/applications/{ghost-content → ghost_content}/README.md +0 -0
  73. /universal_mcp/applications/{ghost-content → ghost_content}/__init__.py +0 -0
  74. /universal_mcp/applications/{google-searchconsole → google_searchconsole}/README.md +0 -0
  75. /universal_mcp/applications/{google-searchconsole → google_searchconsole}/__init__.py +0 -0
  76. /universal_mcp/applications/{http-tools → http_tools}/README.md +0 -0
  77. /universal_mcp/applications/{http-tools → http_tools}/__init__.py +0 -0
  78. /universal_mcp/applications/{google-ads → twilio}/README.md +0 -0
  79. {universal_mcp_applications-0.1.2.dist-info → universal_mcp_applications-0.1.3.dist-info}/WHEEL +0 -0
  80. {universal_mcp_applications-0.1.2.dist-info → universal_mcp_applications-0.1.3.dist-info}/licenses/LICENSE +0 -0
@@ -209,9 +209,7 @@ class TrelloApp(APIApplication):
209
209
  except ValueError:
210
210
  return None
211
211
 
212
- def get_actions_id_card(
213
- self, id: str, fields: str | None = None
214
- ) -> dict[str, Any]:
212
+ def get_actions_id_card(self, id: str, fields: str | None = None) -> dict[str, Any]:
215
213
  """
216
214
  Get the Card for an Action
217
215
 
@@ -243,9 +241,7 @@ class TrelloApp(APIApplication):
243
241
  except ValueError:
244
242
  return None
245
243
 
246
- def get_actions_id_list(
247
- self, id: str, fields: str | None = None
248
- ) -> dict[str, Any]:
244
+ def get_actions_id_list(self, id: str, fields: str | None = None) -> dict[str, Any]:
249
245
  """
250
246
  Get the List for an Action
251
247
 
@@ -2158,9 +2154,7 @@ class TrelloApp(APIApplication):
2158
2154
  except ValueError:
2159
2155
  return None
2160
2156
 
2161
- def post_boards_id_boardplugins(
2162
- self, id: str, idPlugin: str | None = None
2163
- ) -> Any:
2157
+ def post_boards_id_boardplugins(self, id: str, idPlugin: str | None = None) -> Any:
2164
2158
  """
2165
2159
  Enable a Power-Up on a Board
2166
2160
 
@@ -2849,9 +2843,7 @@ class TrelloApp(APIApplication):
2849
2843
  except ValueError:
2850
2844
  return None
2851
2845
 
2852
- def get_cards_id_checkitemstates(
2853
- self, id: str, fields: str | None = None
2854
- ) -> Any:
2846
+ def get_cards_id_checkitemstates(self, id: str, fields: str | None = None) -> Any:
2855
2847
  """
2856
2848
  Get checkItems on a Card
2857
2849
 
@@ -3842,9 +3834,7 @@ class TrelloApp(APIApplication):
3842
3834
  except ValueError:
3843
3835
  return None
3844
3836
 
3845
- def post_cards_id_labels(
3846
- self, id: str, color: str, name: str | None = None
3847
- ) -> Any:
3837
+ def post_cards_id_labels(self, id: str, color: str, name: str | None = None) -> Any:
3848
3838
  """
3849
3839
  Create a new Label on a Card
3850
3840
 
@@ -5525,9 +5515,7 @@ class TrelloApp(APIApplication):
5525
5515
  except ValueError:
5526
5516
  return None
5527
5517
 
5528
- def post_enterprises_id_tokens(
5529
- self, id: str, expiration: str | None = None
5530
- ) -> Any:
5518
+ def post_enterprises_id_tokens(self, id: str, expiration: str | None = None) -> Any:
5531
5519
  """
5532
5520
  Create an auth Token for an Enterprise.
5533
5521
 
@@ -6340,9 +6328,7 @@ class TrelloApp(APIApplication):
6340
6328
  except ValueError:
6341
6329
  return None
6342
6330
 
6343
- def put_lists_id_field(
6344
- self, id: str, field: str, value: Any | None = None
6345
- ) -> Any:
6331
+ def put_lists_id_field(self, id: str, field: str, value: Any | None = None) -> Any:
6346
6332
  """
6347
6333
  Update a field on a List
6348
6334
 
@@ -6680,9 +6666,7 @@ class TrelloApp(APIApplication):
6680
6666
  except ValueError:
6681
6667
  return None
6682
6668
 
6683
- def get_members_id_actions(
6684
- self, id: str, filter: str | None = None
6685
- ) -> list[Any]:
6669
+ def get_members_id_actions(self, id: str, filter: str | None = None) -> list[Any]:
6686
6670
  """
6687
6671
  Get a Member's Actions
6688
6672
 
@@ -8007,9 +7991,7 @@ class TrelloApp(APIApplication):
8007
7991
  except ValueError:
8008
7992
  return None
8009
7993
 
8010
- def get_members_id_tokens(
8011
- self, id: str, webhooks: bool | None = None
8012
- ) -> list[Any]:
7994
+ def get_members_id_tokens(self, id: str, webhooks: bool | None = None) -> list[Any]:
8013
7995
  """
8014
7996
  Get Member's Tokens
8015
7997
 
@@ -0,0 +1 @@
1
+ from .app import TwilioApp
@@ -17,13 +17,13 @@ from universal_mcp.exceptions import NotAuthorizedError, ToolError
17
17
  from universal_mcp.integrations import Integration
18
18
 
19
19
 
20
- class TwillioApp(APIApplication):
20
+ class TwilioApp(APIApplication):
21
21
  """
22
22
  Application for interacting with the Twilio Messaging API using the official Python SDK.
23
23
  """
24
24
 
25
25
  def __init__(self, integration: Integration, **kwargs: Any) -> None:
26
- super().__init__(name="twillio", integration=integration, **kwargs)
26
+ super().__init__(name="twilio", integration=integration, **kwargs)
27
27
  self.base_url = "https://api.twilio.com/2010-04-01"
28
28
  self._twilio_client: Any | None = None
29
29
  self._account_sid: str | None = None
@@ -13,7 +13,7 @@ This is automatically generated from OpenAPI schema for the TwitterApp API.
13
13
  | `create_batch_compliance_job` | Creates a new compliance job using JSON data in the request body and authenticates the request using a Bearer token. |
14
14
  | `get_batch_compliance_job` | Retrieves information about a compliance job by its ID using the BearerToken for authentication. |
15
15
  | `dm_conversation_id_create` | Creates a new group Direct Message conversation and sends an initial message to the specified participants. |
16
- | `get_dm_conversations_with_participant_id_dm_events` | Retrieves a list of direct message events for a conversation with a specific participant, allowing for optional filtering by event types and pagination. |
16
+ | `get_dm_convo_with_patcpnts_id_dm_evnts` | Retrieves a list of direct message events for a conversation with a specific participant, allowing for optional filtering by event types and pagination. |
17
17
  | `get_dm_conversations_id_dm_events` | Retrieves a list of direct message events for a specified conversation ID, allowing for optional filtering by event types and pagination. |
18
18
  | `get_dm_events` | Retrieves a list of direct message events with optional filtering by event types, pagination, and field expansions for media, users, tweets, and DM event details. |
19
19
  | `dm_event_delete` | Deletes a DM event by its ID using the DELETE method, requiring authentication via OAuth2UserToken with "dm.read" and "dm.write" scopes or UserToken. |
@@ -49,7 +49,7 @@ class DmConversationsApi(APISegmentBase):
49
49
  response.raise_for_status()
50
50
  return response.json()
51
51
 
52
- def get_dm_conversations_with_participant_id_dm_events(
52
+ def get_dm_convo_with_patcpnts_id_dm_evnts(
53
53
  self,
54
54
  participant_id,
55
55
  max_results=None,
@@ -248,7 +248,7 @@ class DmConversationsApi(APISegmentBase):
248
248
  def list_tools(self):
249
249
  return [
250
250
  self.dm_conversation_id_create,
251
- self.get_dm_conversations_with_participant_id_dm_events,
251
+ self.get_dm_convo_with_patcpnts_id_dm_evnts,
252
252
  self.dm_conversation_with_user_event_id_create,
253
253
  self.dm_conversation_by_id_event_id_create,
254
254
  self.get_dm_conversations_id_dm_events,
@@ -27,7 +27,7 @@ class ListsApi(APISegmentBase):
27
27
  JSONDecodeError: Raised if the response body cannot be parsed as JSON.
28
28
 
29
29
  Tags:
30
- Lists
30
+ Lists, important
31
31
  """
32
32
  request_body_data = None
33
33
  request_body_data = {
@@ -3,6 +3,7 @@ from collections.abc import Callable
3
3
  from typing import Any, Literal
4
4
 
5
5
  from loguru import logger
6
+
6
7
  from universal_mcp.applications.application import APIApplication
7
8
  from universal_mcp.integrations import Integration
8
9
 
@@ -666,7 +667,10 @@ class UnipileApp(APIApplication):
666
667
  keywords: str | None = None,
667
668
  sort_by: Literal["relevance", "date"] | None = None,
668
669
  date_posted: Literal["past_day", "past_week", "past_month"] | None = None,
669
- content_type: Literal["videos", "images", "live_videos", "collaborative_articles", "documents"] | None = None,
670
+ content_type: Literal[
671
+ "videos", "images", "live_videos", "collaborative_articles", "documents"
672
+ ]
673
+ | None = None,
670
674
  posted_by: dict[str, Any] | None = None,
671
675
  mentioning: dict[str, Any] | None = None,
672
676
  author: dict[str, Any] | None = None,
@@ -1,56 +1,57 @@
1
1
  from typing import Any
2
2
 
3
3
  import requests
4
- from universal_mcp.applications import BaseApplication
5
- from universal_mcp.exceptions import NotAuthorizedError
6
- from universal_mcp.integrations import AgentRIntegration
7
- from universal_mcp_whatsapp.whatsapp import (
4
+ from .whatsapp import (
8
5
  WHATSAPP_API_BASE_URL,
9
6
  )
10
- from universal_mcp_whatsapp.whatsapp import (
7
+ from .whatsapp import (
11
8
  download_media as whatsapp_download_media,
12
9
  )
13
- from universal_mcp_whatsapp.whatsapp import (
10
+ from .whatsapp import (
14
11
  get_chat as whatsapp_get_chat,
15
12
  )
16
- from universal_mcp_whatsapp.whatsapp import (
13
+ from .whatsapp import (
17
14
  get_contact_chats as whatsapp_get_contact_chats,
18
15
  )
19
- from universal_mcp_whatsapp.whatsapp import (
16
+ from .whatsapp import (
20
17
  get_direct_chat_by_contact as whatsapp_get_direct_chat_by_contact,
21
18
  )
22
- from universal_mcp_whatsapp.whatsapp import (
19
+ from .whatsapp import (
23
20
  get_last_interaction as whatsapp_get_last_interaction,
24
21
  )
25
- from universal_mcp_whatsapp.whatsapp import (
22
+ from .whatsapp import (
26
23
  get_message_context as whatsapp_get_message_context,
27
24
  )
28
- from universal_mcp_whatsapp.whatsapp import (
25
+ from .whatsapp import (
29
26
  list_chats as whatsapp_list_chats,
30
27
  )
31
- from universal_mcp_whatsapp.whatsapp import (
28
+ from .whatsapp import (
32
29
  list_messages as whatsapp_list_messages,
33
30
  )
34
- from universal_mcp_whatsapp.whatsapp import (
31
+ from .whatsapp import (
35
32
  search_contacts as whatsapp_search_contacts,
36
33
  )
37
- from universal_mcp_whatsapp.whatsapp import (
34
+ from .whatsapp import (
38
35
  send_audio_message as whatsapp_audio_voice_message,
39
36
  )
40
- from universal_mcp_whatsapp.whatsapp import (
37
+ from .whatsapp import (
41
38
  send_file as whatsapp_send_file,
42
39
  )
43
- from universal_mcp_whatsapp.whatsapp import (
40
+ from .whatsapp import (
44
41
  send_message as whatsapp_send_message,
45
42
  )
46
43
 
44
+ from universal_mcp.applications.application import BaseApplication
45
+ from universal_mcp.exceptions import NotAuthorizedError
46
+ from universal_mcp.agentr.integration import AgentrIntegration
47
+
47
48
 
48
49
  class WhatsappApp(BaseApplication):
49
50
  """
50
51
  Base class for Universal MCP Applications.
51
52
  """
52
53
 
53
- def __init__(self, integration: AgentRIntegration | None = None, **kwargs) -> None:
54
+ def __init__(self, integration: AgentrIntegration | None = None, **kwargs) -> None:
54
55
  super().__init__(name="whatsapp", integration=integration, **kwargs)
55
56
  self.base_url = WHATSAPP_API_BASE_URL
56
57
  self._api_key: str = integration.client.api_key if integration else None
@@ -0,0 +1,110 @@
1
+ import os
2
+ import subprocess
3
+ import tempfile
4
+
5
+ def convert_to_opus_ogg(input_file, output_file=None, bitrate="32k", sample_rate=24000):
6
+ """
7
+ Convert an audio file to Opus format in an Ogg container.
8
+
9
+ Args:
10
+ input_file (str): Path to the input audio file
11
+ output_file (str, optional): Path to save the output file. If None, replaces the
12
+ extension of input_file with .ogg
13
+ bitrate (str, optional): Target bitrate for Opus encoding (default: "32k")
14
+ sample_rate (int, optional): Sample rate for output (default: 24000)
15
+
16
+ Returns:
17
+ str: Path to the converted file
18
+
19
+ Raises:
20
+ FileNotFoundError: If the input file doesn't exist
21
+ RuntimeError: If the ffmpeg conversion fails
22
+ """
23
+ if not os.path.isfile(input_file):
24
+ raise FileNotFoundError(f"Input file not found: {input_file}")
25
+
26
+ # If no output file is specified, replace the extension with .ogg
27
+ if output_file is None:
28
+ output_file = os.path.splitext(input_file)[0] + ".ogg"
29
+
30
+ # Ensure the output directory exists
31
+ output_dir = os.path.dirname(output_file)
32
+ if output_dir and not os.path.exists(output_dir):
33
+ os.makedirs(output_dir)
34
+
35
+ # Build the ffmpeg command
36
+ cmd = [
37
+ "ffmpeg",
38
+ "-i", input_file,
39
+ "-c:a", "libopus",
40
+ "-b:a", bitrate,
41
+ "-ar", str(sample_rate),
42
+ "-application", "voip", # Optimize for voice
43
+ "-vbr", "on", # Variable bitrate
44
+ "-compression_level", "10", # Maximum compression
45
+ "-frame_duration", "60", # 60ms frames (good for voice)
46
+ "-y", # Overwrite output file if it exists
47
+ output_file
48
+ ]
49
+
50
+ try:
51
+ # Run the ffmpeg command and capture output
52
+ process = subprocess.run(
53
+ cmd,
54
+ stdout=subprocess.PIPE,
55
+ stderr=subprocess.PIPE,
56
+ text=True,
57
+ check=True
58
+ )
59
+ return output_file
60
+ except subprocess.CalledProcessError as e:
61
+ raise RuntimeError(f"Failed to convert audio. You likely need to install ffmpeg {e.stderr}")
62
+
63
+
64
+ def convert_to_opus_ogg_temp(input_file, bitrate="32k", sample_rate=24000):
65
+ """
66
+ Convert an audio file to Opus format in an Ogg container and store in a temporary file.
67
+
68
+ Args:
69
+ input_file (str): Path to the input audio file
70
+ bitrate (str, optional): Target bitrate for Opus encoding (default: "32k")
71
+ sample_rate (int, optional): Sample rate for output (default: 24000)
72
+
73
+ Returns:
74
+ str: Path to the temporary file with the converted audio
75
+
76
+ Raises:
77
+ FileNotFoundError: If the input file doesn't exist
78
+ RuntimeError: If the ffmpeg conversion fails
79
+ """
80
+ # Create a temporary file with .ogg extension
81
+ temp_file = tempfile.NamedTemporaryFile(suffix=".ogg", delete=False)
82
+ temp_file.close()
83
+
84
+ try:
85
+ # Convert the audio
86
+ convert_to_opus_ogg(input_file, temp_file.name, bitrate, sample_rate)
87
+ return temp_file.name
88
+ except Exception as e:
89
+ # Clean up the temporary file if conversion fails
90
+ if os.path.exists(temp_file.name):
91
+ os.unlink(temp_file.name)
92
+ raise e
93
+
94
+
95
+ if __name__ == "__main__":
96
+ # Example usage
97
+ import sys
98
+
99
+ if len(sys.argv) < 2:
100
+ print("Usage: python audio.py input_file [output_file]")
101
+ sys.exit(1)
102
+
103
+ input_file = sys.argv[1]
104
+
105
+ try:
106
+ result = convert_to_opus_ogg_temp(input_file)
107
+ print(f"Successfully converted to: {result}")
108
+ except Exception as e:
109
+ print(f"Error: {e}")
110
+ sys.exit(1)