universal-mcp-applications 0.1.33__py3-none-any.whl → 0.1.39rc16__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 (119) hide show
  1. universal_mcp/applications/BEST_PRACTICES.md +1 -1
  2. universal_mcp/applications/ahrefs/app.py +92 -238
  3. universal_mcp/applications/airtable/app.py +36 -135
  4. universal_mcp/applications/apollo/app.py +124 -477
  5. universal_mcp/applications/asana/app.py +605 -1755
  6. universal_mcp/applications/aws_s3/app.py +63 -119
  7. universal_mcp/applications/bill/app.py +644 -2055
  8. universal_mcp/applications/box/app.py +1246 -4159
  9. universal_mcp/applications/braze/app.py +410 -1476
  10. universal_mcp/applications/browser_use/README.md +15 -1
  11. universal_mcp/applications/browser_use/__init__.py +1 -0
  12. universal_mcp/applications/browser_use/app.py +91 -26
  13. universal_mcp/applications/cal_com_v2/app.py +207 -625
  14. universal_mcp/applications/calendly/app.py +103 -242
  15. universal_mcp/applications/canva/app.py +75 -140
  16. universal_mcp/applications/clickup/app.py +331 -798
  17. universal_mcp/applications/coda/app.py +240 -520
  18. universal_mcp/applications/confluence/app.py +497 -1285
  19. universal_mcp/applications/contentful/app.py +40 -155
  20. universal_mcp/applications/crustdata/app.py +44 -123
  21. universal_mcp/applications/dialpad/app.py +451 -924
  22. universal_mcp/applications/digitalocean/app.py +2071 -6082
  23. universal_mcp/applications/domain_checker/app.py +3 -54
  24. universal_mcp/applications/e2b/app.py +17 -68
  25. universal_mcp/applications/elevenlabs/README.md +27 -3
  26. universal_mcp/applications/elevenlabs/app.py +741 -74
  27. universal_mcp/applications/exa/README.md +8 -4
  28. universal_mcp/applications/exa/app.py +415 -186
  29. universal_mcp/applications/falai/README.md +5 -7
  30. universal_mcp/applications/falai/app.py +156 -232
  31. universal_mcp/applications/figma/app.py +91 -175
  32. universal_mcp/applications/file_system/app.py +2 -13
  33. universal_mcp/applications/firecrawl/app.py +198 -176
  34. universal_mcp/applications/fireflies/app.py +59 -281
  35. universal_mcp/applications/fpl/app.py +92 -529
  36. universal_mcp/applications/fpl/utils/fixtures.py +15 -49
  37. universal_mcp/applications/fpl/utils/helper.py +25 -89
  38. universal_mcp/applications/fpl/utils/league_utils.py +20 -64
  39. universal_mcp/applications/ghost_content/app.py +70 -179
  40. universal_mcp/applications/github/app.py +30 -67
  41. universal_mcp/applications/gong/app.py +142 -302
  42. universal_mcp/applications/google_calendar/app.py +26 -78
  43. universal_mcp/applications/google_docs/README.md +15 -14
  44. universal_mcp/applications/google_docs/app.py +103 -206
  45. universal_mcp/applications/google_drive/app.py +194 -793
  46. universal_mcp/applications/google_gemini/app.py +68 -59
  47. universal_mcp/applications/google_mail/README.md +1 -0
  48. universal_mcp/applications/google_mail/app.py +93 -214
  49. universal_mcp/applications/google_searchconsole/app.py +25 -58
  50. universal_mcp/applications/google_sheet/README.md +2 -1
  51. universal_mcp/applications/google_sheet/app.py +226 -624
  52. universal_mcp/applications/google_sheet/helper.py +26 -53
  53. universal_mcp/applications/hashnode/app.py +57 -269
  54. universal_mcp/applications/heygen/README.md +10 -32
  55. universal_mcp/applications/heygen/app.py +339 -811
  56. universal_mcp/applications/http_tools/app.py +10 -32
  57. universal_mcp/applications/hubspot/README.md +1 -1
  58. universal_mcp/applications/hubspot/app.py +7508 -99
  59. universal_mcp/applications/jira/app.py +2419 -8334
  60. universal_mcp/applications/klaviyo/app.py +739 -1621
  61. universal_mcp/applications/linkedin/README.md +18 -1
  62. universal_mcp/applications/linkedin/app.py +729 -251
  63. universal_mcp/applications/mailchimp/app.py +696 -1851
  64. universal_mcp/applications/markitdown/app.py +8 -20
  65. universal_mcp/applications/miro/app.py +333 -815
  66. universal_mcp/applications/ms_teams/app.py +420 -1407
  67. universal_mcp/applications/neon/app.py +144 -250
  68. universal_mcp/applications/notion/app.py +38 -53
  69. universal_mcp/applications/onedrive/app.py +26 -48
  70. universal_mcp/applications/openai/app.py +43 -166
  71. universal_mcp/applications/outlook/README.md +22 -9
  72. universal_mcp/applications/outlook/app.py +403 -141
  73. universal_mcp/applications/perplexity/README.md +2 -1
  74. universal_mcp/applications/perplexity/app.py +161 -20
  75. universal_mcp/applications/pipedrive/app.py +1021 -3331
  76. universal_mcp/applications/posthog/app.py +272 -541
  77. universal_mcp/applications/reddit/app.py +65 -164
  78. universal_mcp/applications/resend/app.py +72 -139
  79. universal_mcp/applications/retell/app.py +23 -50
  80. universal_mcp/applications/rocketlane/app.py +252 -965
  81. universal_mcp/applications/scraper/app.py +114 -142
  82. universal_mcp/applications/semanticscholar/app.py +36 -78
  83. universal_mcp/applications/semrush/app.py +44 -78
  84. universal_mcp/applications/sendgrid/app.py +826 -1576
  85. universal_mcp/applications/sentry/app.py +444 -1079
  86. universal_mcp/applications/serpapi/app.py +44 -146
  87. universal_mcp/applications/sharepoint/app.py +27 -49
  88. universal_mcp/applications/shopify/app.py +1748 -4486
  89. universal_mcp/applications/shortcut/app.py +275 -536
  90. universal_mcp/applications/slack/app.py +43 -125
  91. universal_mcp/applications/spotify/app.py +206 -405
  92. universal_mcp/applications/supabase/app.py +174 -283
  93. universal_mcp/applications/tavily/app.py +2 -2
  94. universal_mcp/applications/trello/app.py +853 -2816
  95. universal_mcp/applications/twilio/app.py +27 -62
  96. universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
  97. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
  98. universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
  99. universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
  100. universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
  101. universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
  102. universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
  103. universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
  104. universal_mcp/applications/whatsapp/app.py +35 -186
  105. universal_mcp/applications/whatsapp/audio.py +2 -6
  106. universal_mcp/applications/whatsapp/whatsapp.py +17 -51
  107. universal_mcp/applications/whatsapp_business/app.py +86 -299
  108. universal_mcp/applications/wrike/app.py +80 -153
  109. universal_mcp/applications/yahoo_finance/app.py +19 -65
  110. universal_mcp/applications/youtube/app.py +120 -306
  111. universal_mcp/applications/zenquotes/app.py +3 -3
  112. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/METADATA +4 -2
  113. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/RECORD +115 -119
  114. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/WHEEL +1 -1
  115. universal_mcp/applications/hubspot/api_segments/__init__.py +0 -0
  116. universal_mcp/applications/hubspot/api_segments/api_segment_base.py +0 -54
  117. universal_mcp/applications/hubspot/api_segments/crm_api.py +0 -7337
  118. universal_mcp/applications/hubspot/api_segments/marketing_api.py +0 -1467
  119. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/licenses/LICENSE +0 -0
@@ -3,8 +3,7 @@ import io
3
3
  import os
4
4
  import uuid
5
5
  import wave
6
- from typing import Annotated
7
-
6
+ from typing import Annotated, Literal
8
7
  from google import genai
9
8
  from google.genai import types
10
9
  from PIL import Image
@@ -17,16 +16,11 @@ class GoogleGeminiApp(APIApplication):
17
16
  super().__init__(name="google_gemini", integration=integration, **kwargs)
18
17
  self._genai_client = None
19
18
 
20
- @property
21
- def genai_client(self) -> genai.Client:
19
+ async def get_genai_client(self) -> genai.Client:
22
20
  if self._genai_client is not None:
23
21
  return self._genai_client
24
- credentials = self.integration.get_credentials()
25
- api_key = (
26
- credentials.get("api_key")
27
- or credentials.get("API_KEY")
28
- or credentials.get("apiKey")
29
- )
22
+ credentials = await self.integration.get_credentials_async()
23
+ api_key = credentials.get("api_key") or credentials.get("API_KEY") or credentials.get("apiKey")
30
24
  if not api_key:
31
25
  raise ValueError("API key not found in integration credentials")
32
26
  self._genai_client = genai.Client(api_key=api_key)
@@ -35,7 +29,12 @@ class GoogleGeminiApp(APIApplication):
35
29
  async def generate_text(
36
30
  self,
37
31
  prompt: Annotated[str, "The prompt to generate text from"],
38
- model: str = "gemini-2.5-flash",
32
+ model: Literal[
33
+ "gemini-2.5-flash",
34
+ "gemini-2.5-pro",
35
+ "gemini-3-flash-preview",
36
+ "gemini-3-pro-preview",
37
+ ] = "gemini-2.5-flash",
39
38
  ) -> str:
40
39
  """Generates text using the Google Gemini model based on a given prompt.
41
40
  This tool is suitable for various natural language processing tasks such as content generation, summarization, translation, and question answering.
@@ -54,16 +53,15 @@ class GoogleGeminiApp(APIApplication):
54
53
  Tags:
55
54
  text, generate, llm, important
56
55
  """
57
- response = self.genai_client.models.generate_content(
58
- contents=prompt, model=model
59
- )
56
+ client = await self.get_genai_client()
57
+ response = client.models.generate_content(contents=prompt, model=model)
60
58
  return response.text
61
59
 
62
60
  async def generate_image(
63
61
  self,
64
62
  prompt: Annotated[str, "The prompt to generate image from"],
65
- images: Annotated[list[str], "The reference image URLs"] | None = None,
66
- model: str = "gemini-2.5-flash-image-preview",
63
+ images: Annotated[list[str], "The reference image URLs"] | None = None,
64
+ model: Literal["gemini-3-pro-image-preview", "gemini-2.5-flash-image"] = "gemini-2.5-flash-image",
67
65
  ) -> dict:
68
66
  """
69
67
  Generates an image based on a text prompt and an optional reference image using the Google Gemini model.
@@ -73,12 +71,12 @@ class GoogleGeminiApp(APIApplication):
73
71
  Args:
74
72
  prompt (str): The descriptive text prompt to guide the image generation. For example: "A futuristic city at sunset with flying cars."
75
73
  images (list[str], optional): An optional list of URLs to reference images. These images will be used as a basis for the generation.
76
- model (str, optional): The Gemini model to use for image generation. Defaults to "gemini-2.5-flash-image-preview".
74
+ model (str, optional): The Gemini model to use for image generation. Defaults to "gemini-2.5-flash-image".
77
75
 
78
76
  Returns:
79
77
  dict: A dictionary containing:
80
78
  - 'type' (str): Always "image".
81
- - 'data' (str): The base64 encoded image data.
79
+ - 'data' (str): The base64 encoded image data. Either upload or save this and then render the file path/link in markdown to the user. DO NOT use a data url.
82
80
  - 'mime_type' (str): The MIME type of the image (e.g., "image/png").
83
81
  - 'file_name' (str): A suggested file name for the generated image.
84
82
  - 'text' (str): Any accompanying text generated by the model.
@@ -91,7 +89,7 @@ class GoogleGeminiApp(APIApplication):
91
89
  Tags:
92
90
  image, generate, vision, important
93
91
  """
94
- # The Gemini API is synchronous, so run in a thread
92
+ client = await self.get_genai_client()
95
93
  contents = [prompt]
96
94
  if images:
97
95
  for image in images:
@@ -104,35 +102,22 @@ class GoogleGeminiApp(APIApplication):
104
102
  else:
105
103
  image = Image.open(image)
106
104
  contents.append(image)
107
- response = self.genai_client.models.generate_content(
108
- model=model,
109
- contents=contents,
110
- )
105
+ response = client.models.generate_content(model=model, contents=contents)
111
106
  candidate = response.candidates[0]
112
107
  text = ""
113
108
  for part in candidate.content.parts:
114
109
  if part.text is not None:
115
110
  text += part.text
116
111
  elif part.inline_data is not None:
117
- # Return the raw image bytes
118
112
  image_bytes = part.inline_data.data
119
-
120
113
  img_base64 = base64.b64encode(image_bytes).decode("utf-8")
121
-
122
114
  file_name = f"{uuid.uuid4()}.png"
123
-
124
- return {
125
- "type": "image",
126
- "data": img_base64,
127
- "mime_type": "image/png",
128
- "file_name": file_name,
129
- "text": text,
130
- }
115
+ return {"type": "image", "data": img_base64, "mime_type": "image/png", "file_name": file_name, "text": text}
131
116
 
132
117
  async def generate_audio(
133
118
  self,
134
119
  prompt: Annotated[str, "The prompt to generate audio from"],
135
- model: str = "gemini-2.5-flash-preview-tts",
120
+ model: Literal["gemini-2.5-flash-preview-tts", "gemini-2.5-pro-preview-tts"] = "gemini-2.5-flash-preview-tts",
136
121
  ) -> str:
137
122
  """Generates audio from a given text prompt using the Google Gemini model's Text-to-Speech (TTS) capabilities.
138
123
  This tool is useful for converting text into spoken audio, which can be used for voiceovers, accessibility features, or interactive applications.
@@ -155,8 +140,8 @@ class GoogleGeminiApp(APIApplication):
155
140
  Tags:
156
141
  audio, generate, tts, speech, important
157
142
  """
143
+ client = await self.get_genai_client()
158
144
 
159
- # Set up the wave file to save the output:
160
145
  def wave_file(filename, pcm, channels=1, rate=24000, sample_width=2):
161
146
  with wave.open(filename, "wb") as wf:
162
147
  wf.setnchannels(channels)
@@ -164,58 +149,82 @@ class GoogleGeminiApp(APIApplication):
164
149
  wf.setframerate(rate)
165
150
  wf.writeframes(pcm)
166
151
 
167
- response = self.genai_client.models.generate_content(
152
+ response = client.models.generate_content(
168
153
  model=model,
169
154
  contents=prompt,
170
155
  config=types.GenerateContentConfig(
171
156
  response_modalities=["AUDIO"],
172
157
  speech_config=types.SpeechConfig(
173
- voice_config=types.VoiceConfig(
174
- prebuilt_voice_config=types.PrebuiltVoiceConfig(
175
- voice_name="Kore",
176
- )
177
- )
158
+ voice_config=types.VoiceConfig(prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name="Kore"))
178
159
  ),
179
160
  ),
180
161
  )
181
-
182
162
  data = response.candidates[0].content.parts[0].inline_data.data
183
-
184
163
  file_name = f"{uuid.uuid4()}.wav"
185
164
  wave_file(file_name, data)
186
-
187
- # read the file
188
165
  with open(file_name, "rb") as f:
189
166
  data = f.read()
190
-
191
- # delete the file
192
167
  os.remove(file_name)
193
-
194
- # Convert to base64
195
168
  import base64
196
169
 
197
170
  audio_base64 = base64.b64encode(data).decode("utf-8")
171
+ return {"type": "audio", "data": audio_base64, "mime_type": "audio/wav", "file_name": file_name}
172
+
173
+ async def analyze_image(
174
+ self,
175
+ images: Annotated[list[str], "The reference image URLs"],
176
+ prompt: Annotated[str, "The prompt to describe or ask about the image"] = "Describe this image",
177
+ model: Literal["gemini-2.5-flash", "gemini-2.5-pro"] = "gemini-2.5-flash",
178
+ ) -> str:
179
+ """
180
+ Analyzes one or more images based on a text prompt using the Google Gemini model.
181
+ This tool is capable of describing images, answering questions about them, or performing visual reasoning.
182
+ It accepts image URLs and a text prompt, returning a natural language response.
198
183
 
199
- return {
200
- "type": "audio",
201
- "data": audio_base64,
202
- "mime_type": "audio/wav",
203
- "file_name": file_name,
204
- }
184
+ Args:
185
+ images (list[str]): A list of URLs for the images to be analyzed.
186
+ prompt (str, optional): The text prompt or question about the images. Defaults to "Describe this image".
187
+ model (str, optional): The Gemini model to use for analysis. Defaults to "gemini-2.5-flash".
188
+
189
+ Returns:
190
+ str: The generated text response containing the analysis or description of the images.
191
+
192
+ Raises:
193
+ requests.exceptions.RequestException: If there's an issue fetching a remote image.
194
+ FileNotFoundError: If a local image path is invalid.
195
+ Exception: If the underlying Gemini API call fails.
196
+
197
+ Tags:
198
+ image, analyze, vision, describe, question, important
199
+ """
200
+ client = await self.get_genai_client()
201
+ contents = [prompt]
202
+ if images:
203
+ for image in images:
204
+ if image.startswith(("http://", "https://")):
205
+ import requests
206
+
207
+ response = requests.get(image)
208
+ response.raise_for_status()
209
+ image = Image.open(io.BytesIO(response.content))
210
+ else:
211
+ image = Image.open(image)
212
+ contents.append(image)
213
+ response = client.models.generate_content(model=model, contents=contents)
214
+ return response.text
205
215
 
206
216
  def list_tools(self):
207
217
  return [
208
218
  self.generate_text,
209
219
  self.generate_image,
220
+ self.analyze_image,
210
221
  self.generate_audio,
211
222
  ]
212
223
 
213
224
 
214
225
  async def test_google_gemini():
215
226
  app = GoogleGeminiApp()
216
- await app.generate_image(
217
- "A beautiful women potrait with red green hair color"
218
- )
227
+ await app.generate_image("A beautiful women potrait with red green hair color")
219
228
 
220
229
 
221
230
  if __name__ == "__main__":
@@ -16,6 +16,7 @@ This is automatically generated from OpenAPI schema for the GoogleMailApp API.
16
16
  | `list_drafts` | Fetches a list of email drafts, allowing filtering by a search query and limiting results. It can optionally include drafts from spam and trash, returning a collection of draft objects. This is distinct from `get_draft`, which retrieves only a single, specific draft by its ID. |
17
17
  | `get_message_details` | Retrieves a specific email from Gmail by its ID. It parses the API response to extract and format key details—including sender, subject, body, and attachments—into a structured dictionary. This function provides detailed data for a single message, distinguishing it from `list_messages` which fetches multiple messages. |
18
18
  | `list_messages` | Fetches a paginated list of detailed email messages using optional search queries. It concurrently retrieves full content (sender, subject, body) for each message, returning the results and a pagination token. This differs from `get_message_details`, which fetches only a single message. |
19
+ | `get_email_thread` | Fetches a complete email conversation by its unique thread ID. Unlike `get_message_details`, which retrieves a single message, this returns all messages and metadata for the entire thread, providing the full context of the conversation. |
19
20
  | `list_labels` | Fetches a complete list of all available labels from the user's Gmail account via the API. It retrieves both system-defined (e.g., INBOX) and user-created labels, returning their names and IDs, complementing management functions like `create_label` and `update_label`. |
20
21
  | `create_label` | Creates a new Gmail label with a specified name, hardcoding its visibility to ensure it appears in both label and message lists. This function complements `update_label` and `delete_label` by adding new organizational tags to the user's account via the API. |
21
22
  | `get_profile` | Retrieves the authenticated user's Gmail profile from the API. The profile includes the user's email address, total message and thread counts, and the mailbox's history ID, offering a high-level summary of the account's state. |