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
@@ -1,9 +1,7 @@
1
1
  from typing import Any
2
-
3
2
  from universal_mcp.applications.application import APIApplication
4
3
  from universal_mcp.exceptions import NotAuthorizedError, ToolError
5
4
  from universal_mcp.integrations import Integration
6
-
7
5
  import resend
8
6
 
9
7
 
@@ -12,33 +10,22 @@ class ResendApp(APIApplication):
12
10
  super().__init__(name="resend", integration=integration, **kwargs)
13
11
  self._api_key = None
14
12
 
15
- @property
16
- def api_key(self) -> str:
13
+ async def get_api_key(self) -> str:
17
14
  """
18
15
  A property that lazily retrieves, validates, and caches the Resend API key from integration credentials. On first access, it configures the `resend` library, raising an error if authentication fails. This ensures the application is authenticated for all subsequent API calls within the class.
19
16
  """
20
17
  if self._api_key is None:
21
18
  if not self.integration:
22
19
  raise NotAuthorizedError("Resend integration not configured.")
23
- credentials = self.integration.get_credentials()
24
- api_key = (
25
- credentials.get("api_key")
26
- or credentials.get("API_KEY")
27
- or credentials.get("apiKey")
28
- )
20
+ credentials = await self.integration.get_credentials_async()
21
+ api_key = credentials.get("api_key") or credentials.get("API_KEY") or credentials.get("apiKey")
29
22
  if not api_key:
30
23
  raise NotAuthorizedError("Resend API key not found in credentials.")
31
24
  self._api_key = api_key
32
25
  resend.api_key = self._api_key
33
26
  return self._api_key
34
27
 
35
- def send_email(
36
- self,
37
- from_email: str,
38
- to_emails: list[str],
39
- subject: str,
40
- text: str,
41
- ) -> dict[str, Any]:
28
+ async def send_email(self, from_email: str, to_emails: list[str], subject: str, text: str) -> dict[str, Any]:
42
29
  """
43
30
  Sends a single email with a specified subject and text body to a list of recipients via the Resend API. Unlike `send_batch_emails`, which processes multiple distinct emails at once, this function is designed for dispatching one individual email composition per API call.
44
31
 
@@ -57,23 +44,15 @@ class ResendApp(APIApplication):
57
44
  Tags:
58
45
  send, email, api, communication, important
59
46
  """
60
- self.api_key
61
- params: resend.Emails.SendParams = {
62
- "from": from_email,
63
- "to": to_emails,
64
- "subject": subject,
65
- "text": text,
66
- }
47
+ api_key = await self.get_api_key()
48
+ params: resend.Emails.SendParams = {"from": from_email, "to": to_emails, "subject": subject, "text": text}
67
49
  try:
68
50
  email = resend.Emails.send(params)
69
51
  return email
70
52
  except Exception as e:
71
53
  raise ToolError(f"Failed to send email: {e}")
72
54
 
73
- def send_batch_emails(
74
- self,
75
- emails: list[dict[str, Any]],
76
- ) -> dict[str, Any]:
55
+ async def send_batch_emails(self, emails: list[dict[str, Any]]) -> dict[str, Any]:
77
56
  """
78
57
  Sends multiple emails (1-100) in a single API request. Unlike the `send_email` function which handles a single message, this accepts a list of email objects for efficient, high-volume delivery. It validates that the batch size is within the allowed limits before making the API call.
79
58
 
@@ -89,11 +68,9 @@ class ResendApp(APIApplication):
89
68
  Tags:
90
69
  batch, send, emails, resend-api
91
70
  """
92
- self.api_key
71
+ api_key = await self.get_api_key()
93
72
  if not 1 <= len(emails) <= 100:
94
- raise ToolError(
95
- "The number of emails in a batch must be between 1 and 100."
96
- )
73
+ raise ToolError("The number of emails in a batch must be between 1 and 100.")
97
74
  params: list[resend.Emails.SendParams] = emails
98
75
  try:
99
76
  sent_emails_response = resend.Batch.send(params)
@@ -101,7 +78,7 @@ class ResendApp(APIApplication):
101
78
  except Exception as e:
102
79
  raise ToolError(f"Failed to send batch emails: {e}")
103
80
 
104
- def retrieve_email_by_id(self, email_id: str) -> dict[str, Any]:
81
+ async def retrieve_email_by_id(self, email_id: str) -> dict[str, Any]:
105
82
  """
106
83
  Retrieves the details and status of a single email from the Resend API using its unique identifier. This function allows for looking up a specific email that has already been sent or scheduled, distinct from functions that initiate sending.
107
84
 
@@ -117,14 +94,14 @@ class ResendApp(APIApplication):
117
94
  Tags:
118
95
  retrieve, email, management
119
96
  """
120
- self.api_key
97
+ api_key = await self.get_api_key()
121
98
  try:
122
99
  email = resend.Emails.get(email_id=email_id)
123
100
  return email
124
101
  except Exception as e:
125
102
  raise ToolError(f"Failed to retrieve email: {e}")
126
103
 
127
- def reschedule_email(self, email_id: str, scheduled_at: str) -> dict[str, Any]:
104
+ async def reschedule_email(self, email_id: str, scheduled_at: str) -> dict[str, Any]:
128
105
  """
129
106
  Modifies the delivery time for a specific, previously scheduled email using its ID. It updates the `scheduled_at` attribute to a new ISO 8601 formatted time, effectively rescheduling its dispatch. This differs from `cancel_scheduled_email`, which permanently stops the send.
130
107
 
@@ -141,18 +118,15 @@ class ResendApp(APIApplication):
141
118
  Tags:
142
119
  update, email, async_job, management
143
120
  """
144
- self.api_key
145
- params: resend.Emails.UpdateParams = {
146
- "id": email_id,
147
- "scheduled_at": scheduled_at,
148
- }
121
+ api_key = await self.get_api_key()
122
+ params: resend.Emails.UpdateParams = {"id": email_id, "scheduled_at": scheduled_at}
149
123
  try:
150
124
  response = resend.Emails.update(params=params)
151
125
  return response
152
126
  except Exception as e:
153
127
  raise ToolError(f"Failed to update scheduled email: {e}")
154
128
 
155
- def cancel_scheduled_email(self, email_id: str) -> dict[str, Any]:
129
+ async def cancel_scheduled_email(self, email_id: str) -> dict[str, Any]:
156
130
  """
157
131
  Cancels a previously scheduled email using its unique ID, preventing it from being sent. This function calls the Resend API's cancellation endpoint, returning a confirmation response. It is distinct from `update_scheduled_email`, which reschedules the email instead of stopping its transmission.
158
132
 
@@ -168,14 +142,14 @@ class ResendApp(APIApplication):
168
142
  Tags:
169
143
  cancel, email, management
170
144
  """
171
- self.api_key
145
+ api_key = await self.get_api_key()
172
146
  try:
173
147
  response = resend.Emails.cancel(email_id=email_id)
174
148
  return response
175
149
  except Exception as e:
176
150
  raise ToolError(f"Failed to cancel scheduled email: {e}")
177
151
 
178
- def create_domain(self, name: str) -> dict[str, Any]:
152
+ async def create_domain(self, name: str) -> dict[str, Any]:
179
153
  """
180
154
  Registers a new sending domain with the Resend service using the provided name. This is a prerequisite for sending emails from your own domain and returns a dictionary containing details of the new domain object, which can then be verified and managed with other domain-related functions.
181
155
 
@@ -191,7 +165,7 @@ class ResendApp(APIApplication):
191
165
  Tags:
192
166
  create, domain, management, api, batch, important
193
167
  """
194
- self.api_key
168
+ api_key = await self.get_api_key()
195
169
  params: resend.Domains.CreateParams = {"name": name}
196
170
  try:
197
171
  domain = resend.Domains.create(params)
@@ -199,7 +173,7 @@ class ResendApp(APIApplication):
199
173
  except Exception as e:
200
174
  raise ToolError(f"Failed to create domain: {e}")
201
175
 
202
- def get_domain(self, domain_id: str) -> dict[str, Any]:
176
+ async def get_domain(self, domain_id: str) -> dict[str, Any]:
203
177
  """
204
178
  Retrieves the details of a specific domain from the Resend API using its unique ID. Unlike `list_domains`, which fetches all domains, this function targets a single record and returns a dictionary containing the domain's properties, like its verification status and tracking settings.
205
179
 
@@ -215,14 +189,14 @@ class ResendApp(APIApplication):
215
189
  Tags:
216
190
  retrieve, domain, management
217
191
  """
218
- self.api_key
192
+ api_key = await self.get_api_key()
219
193
  try:
220
194
  domain = resend.Domains.get(domain_id=domain_id)
221
195
  return domain
222
196
  except Exception as e:
223
197
  raise ToolError(f"Failed to retrieve domain: {e}")
224
198
 
225
- def verify_domain(self, domain_id: str) -> dict[str, Any]:
199
+ async def verify_domain(self, domain_id: str) -> dict[str, Any]:
226
200
  """
227
201
  Triggers the verification process for a registered domain using its unique ID. This action is crucial for authorizing the domain to send emails via Resend and returns an API response containing the verification status and necessary DNS records to complete the process.
228
202
 
@@ -238,19 +212,15 @@ class ResendApp(APIApplication):
238
212
  Tags:
239
213
  verify, domain
240
214
  """
241
- self.api_key
215
+ api_key = await self.get_api_key()
242
216
  try:
243
217
  response = resend.Domains.verify(domain_id=domain_id)
244
218
  return response
245
219
  except Exception as e:
246
220
  raise ToolError(f"Failed to verify domain: {e}")
247
221
 
248
- def update_domain_settings(
249
- self,
250
- domain_id: str,
251
- open_tracking: bool | None = None,
252
- click_tracking: bool | None = None,
253
- tls: str | None = None,
222
+ async def update_domain_settings(
223
+ self, domain_id: str, open_tracking: bool | None = None, click_tracking: bool | None = None, tls: str | None = None
254
224
  ) -> dict[str, Any]:
255
225
  """
256
226
  Updates settings for a specific domain identified by its ID. This function can modify configurations like open and click tracking, and TLS enforcement. It returns the updated domain object from the API, raising a ToolError if the update fails. Only the provided settings are modified.
@@ -270,7 +240,7 @@ class ResendApp(APIApplication):
270
240
  Tags:
271
241
  update, domain, management
272
242
  """
273
- self.api_key
243
+ api_key = await self.get_api_key()
274
244
  params: resend.Domains.UpdateParams = {"id": domain_id}
275
245
  if open_tracking is not None:
276
246
  params["open_tracking"] = open_tracking
@@ -284,7 +254,7 @@ class ResendApp(APIApplication):
284
254
  except Exception as e:
285
255
  raise ToolError(f"Failed to update domain: {e}")
286
256
 
287
- def list_domains(self) -> list[dict[str, Any]]:
257
+ async def list_domains(self) -> list[dict[str, Any]]:
288
258
  """
289
259
  Fetches a complete list of all domains registered with the Resend account. Unlike `get_domain`, which retrieves a single domain by ID, this provides a comprehensive overview of all configured domains for management and verification tasks.
290
260
 
@@ -297,14 +267,14 @@ class ResendApp(APIApplication):
297
267
  Tags:
298
268
  list, domains, important, management
299
269
  """
300
- self.api_key
270
+ api_key = await self.get_api_key()
301
271
  try:
302
272
  domains = resend.Domains.list()
303
273
  return domains
304
274
  except Exception as e:
305
275
  raise ToolError(f"Failed to list domains: {e}")
306
276
 
307
- def remove_domain(self, domain_id: str) -> dict[str, Any]:
277
+ async def remove_domain(self, domain_id: str) -> dict[str, Any]:
308
278
  """
309
279
  Permanently removes a specific domain from the Resend account using its unique ID. This function makes an authenticated API call to delete the domain, distinguishing it from retrieval (`get_domain`) or modification (`update_domain`) operations, and raises an error if the process fails.
310
280
 
@@ -320,14 +290,14 @@ class ResendApp(APIApplication):
320
290
  Tags:
321
291
  remove, management, api, domain
322
292
  """
323
- self.api_key
293
+ api_key = await self.get_api_key()
324
294
  try:
325
295
  response = resend.Domains.remove(domain_id=domain_id)
326
296
  return response
327
297
  except Exception as e:
328
298
  raise ToolError(f"Failed to remove domain: {e}")
329
299
 
330
- def create_api_key(self, name: str) -> dict[str, Any]:
300
+ async def create_api_key(self, name: str) -> dict[str, Any]:
331
301
  """
332
302
  Creates a new API key for authenticating with the Resend service, identified by a specified name. It returns a dictionary containing the new key object, including the generated token required for subsequent API requests.
333
303
 
@@ -343,7 +313,7 @@ class ResendApp(APIApplication):
343
313
  Tags:
344
314
  create, api-key, authentication
345
315
  """
346
- self.api_key
316
+ api_key = await self.get_api_key()
347
317
  params: resend.ApiKeys.CreateParams = {"name": name}
348
318
  try:
349
319
  api_key_obj = resend.ApiKeys.create(params)
@@ -351,7 +321,7 @@ class ResendApp(APIApplication):
351
321
  except Exception as e:
352
322
  raise ToolError(f"Failed to create API key: {e}")
353
323
 
354
- def list_api_keys(self) -> list[dict[str, Any]]:
324
+ async def list_api_keys(self) -> list[dict[str, Any]]:
355
325
  """
356
326
  Retrieves a list of all API keys for the authenticated Resend account. This read-only operation allows for auditing and viewing existing credentials, contrasting with `create_api_key` and `remove_api_key` which are used to add or delete keys.
357
327
 
@@ -367,14 +337,14 @@ class ResendApp(APIApplication):
367
337
  Tags:
368
338
  list, api, important
369
339
  """
370
- self.api_key
340
+ api_key = await self.get_api_key()
371
341
  try:
372
342
  keys = resend.ApiKeys.list()
373
343
  return keys
374
344
  except Exception as e:
375
345
  raise ToolError(f"Failed to list API keys: {e}")
376
346
 
377
- def remove_api_key(self, api_key_id: str) -> dict[str, Any]:
347
+ async def remove_api_key(self, api_key_id: str) -> dict[str, Any]:
378
348
  """
379
349
  Deletes a specific Resend API key identified by its unique ID. This function, part of the key management suite alongside `create_api_key` and `list_api_keys`, returns an API confirmation response or raises a `ToolError` if the operation fails.
380
350
 
@@ -390,20 +360,14 @@ class ResendApp(APIApplication):
390
360
  Tags:
391
361
  remove, api-key, management
392
362
  """
393
- self.api_key
363
+ api_key = await self.get_api_key()
394
364
  try:
395
365
  response = resend.ApiKeys.remove(api_key_id=api_key_id)
396
366
  return response
397
367
  except Exception as e:
398
368
  raise ToolError(f"Failed to remove API key: {e}")
399
369
 
400
- def register_broadcast(
401
- self,
402
- audience_id: str,
403
- from_email: str,
404
- subject: str,
405
- html: str,
406
- ) -> dict[str, Any]:
370
+ async def register_broadcast(self, audience_id: str, from_email: str, subject: str, html: str) -> dict[str, Any]:
407
371
  """
408
372
  Registers a new email broadcast campaign for a specific audience using the Resend API. This function creates the broadcast object but does not send it; use the `send_broadcast` function to dispatch the created campaign to the audience.
409
373
 
@@ -422,20 +386,15 @@ class ResendApp(APIApplication):
422
386
  Tags:
423
387
  broadcast, email, important
424
388
  """
425
- self.api_key
426
- params: resend.Broadcasts.CreateParams = {
427
- "audience_id": audience_id,
428
- "from": from_email,
429
- "subject": subject,
430
- "html": html,
431
- }
389
+ api_key = await self.get_api_key()
390
+ params: resend.Broadcasts.CreateParams = {"audience_id": audience_id, "from": from_email, "subject": subject, "html": html}
432
391
  try:
433
392
  broadcast = resend.Broadcasts.create(params)
434
393
  return broadcast
435
394
  except Exception as e:
436
395
  raise ToolError(f"Failed to create broadcast: {e}")
437
396
 
438
- def get_broadcast(self, broadcast_id: str) -> dict[str, Any]:
397
+ async def get_broadcast(self, broadcast_id: str) -> dict[str, Any]:
439
398
  """
440
399
  Retrieves a specific broadcast's complete details, including its status and content, by its unique ID. Unlike `list_broadcasts` which retrieves all broadcasts, this function targets a single entry for inspection.
441
400
 
@@ -451,19 +410,14 @@ class ResendApp(APIApplication):
451
410
  Tags:
452
411
  retrieve, broadcast
453
412
  """
454
- self.api_key
413
+ api_key = await self.get_api_key()
455
414
  try:
456
415
  broadcast = resend.Broadcasts.get(id=broadcast_id)
457
416
  return broadcast
458
417
  except Exception as e:
459
418
  raise ToolError(f"Failed to retrieve broadcast: {e}")
460
419
 
461
- def update_broadcast(
462
- self,
463
- broadcast_id: str,
464
- html: str | None = None,
465
- subject: str | None = None,
466
- ) -> dict[str, Any]:
420
+ async def update_broadcast(self, broadcast_id: str, html: str | None = None, subject: str | None = None) -> dict[str, Any]:
467
421
  """
468
422
  Updates the HTML content and/or subject of an existing broadcast, identified by its ID. Requires that at least one modifiable field (html or subject) is provided. This function alters a broadcast's content, differing from `send_broadcast` which triggers its delivery.
469
423
 
@@ -481,25 +435,21 @@ class ResendApp(APIApplication):
481
435
  Tags:
482
436
  update, management, broadcast, api
483
437
  """
484
- self.api_key
438
+ api_key = await self.get_api_key()
485
439
  params: resend.Broadcasts.UpdateParams = {"id": broadcast_id}
486
440
  if html is not None:
487
441
  params["html"] = html
488
442
  if subject is not None:
489
443
  params["subject"] = subject
490
444
  if len(params) == 1:
491
- raise ToolError(
492
- "At least one field (e.g., html, subject) must be provided for the update."
493
- )
445
+ raise ToolError("At least one field (e.g., html, subject) must be provided for the update.")
494
446
  try:
495
447
  updated_broadcast = resend.Broadcasts.update(params)
496
448
  return updated_broadcast
497
449
  except Exception as e:
498
450
  raise ToolError(f"Failed to update broadcast: {e}")
499
451
 
500
- def send_or_schedule_broadcast(
501
- self, broadcast_id: str, scheduled_at: str | None = None
502
- ) -> dict[str, Any]:
452
+ async def send_or_schedule_broadcast(self, broadcast_id: str, scheduled_at: str | None = None) -> dict[str, Any]:
503
453
  """
504
454
  Initiates the delivery of a pre-existing broadcast, identified by its ID, to its target audience. The broadcast can be sent immediately or scheduled for a future time via the optional `scheduled_at` parameter. It returns the API response upon execution.
505
455
 
@@ -516,7 +466,7 @@ class ResendApp(APIApplication):
516
466
  Tags:
517
467
  broadcast, send, api, management
518
468
  """
519
- self.api_key
469
+ api_key = await self.get_api_key()
520
470
  params: resend.Broadcasts.SendParams = {"broadcast_id": broadcast_id}
521
471
  if scheduled_at:
522
472
  params["scheduled_at"] = scheduled_at
@@ -526,7 +476,7 @@ class ResendApp(APIApplication):
526
476
  except Exception as e:
527
477
  raise ToolError(f"Failed to send broadcast: {e}")
528
478
 
529
- def remove_draft_broadcast(self, broadcast_id: str) -> dict[str, Any]:
479
+ async def remove_draft_broadcast(self, broadcast_id: str) -> dict[str, Any]:
530
480
  """
531
481
  Deletes a broadcast from the Resend service using its unique ID. This action is restricted to broadcasts that have a 'draft' status and have not been sent, returning the API's response upon successful removal or raising an error if the operation fails.
532
482
 
@@ -542,14 +492,14 @@ class ResendApp(APIApplication):
542
492
  Tags:
543
493
  remove, broadcast, api-management, draft-status
544
494
  """
545
- self.api_key
495
+ api_key = await self.get_api_key()
546
496
  try:
547
497
  response = resend.Broadcasts.remove(id=broadcast_id)
548
498
  return response
549
499
  except Exception as e:
550
500
  raise ToolError(f"Failed to remove broadcast: {e}")
551
501
 
552
- def list_broadcasts(self) -> list[dict[str, Any]]:
502
+ async def list_broadcasts(self) -> list[dict[str, Any]]:
553
503
  """
554
504
  Retrieves a list of all broadcasts associated with the authenticated account. Unlike `get_broadcast` which fetches a single item by ID, this function returns a list of dictionaries, each containing the attributes of a specific broadcast. Raises a `ToolError` on API failure.
555
505
 
@@ -562,14 +512,14 @@ class ResendApp(APIApplication):
562
512
  Tags:
563
513
  list, broadcast, api, management, important
564
514
  """
565
- self.api_key
515
+ api_key = await self.get_api_key()
566
516
  try:
567
517
  broadcasts = resend.Broadcasts.list()
568
518
  return broadcasts
569
519
  except Exception as e:
570
520
  raise ToolError(f"Failed to list broadcasts: {e}")
571
521
 
572
- def create_audience(self, name: str) -> dict[str, Any]:
522
+ async def create_audience(self, name: str) -> dict[str, Any]:
573
523
  """
574
524
  Creates a new audience, a named list for contacts, within the Resend service. This function requires a name for the audience and returns a dictionary representing the newly created object, enabling subsequent management of contacts within that specific list.
575
525
 
@@ -585,7 +535,7 @@ class ResendApp(APIApplication):
585
535
  Tags:
586
536
  create, audience, management, important
587
537
  """
588
- self.api_key
538
+ api_key = await self.get_api_key()
589
539
  params: resend.Audiences.CreateParams = {"name": name}
590
540
  try:
591
541
  audience = resend.Audiences.create(params)
@@ -593,7 +543,7 @@ class ResendApp(APIApplication):
593
543
  except Exception as e:
594
544
  raise ToolError(f"Failed to create audience: {e}")
595
545
 
596
- def get_audience(self, audience_id: str) -> dict[str, Any]:
546
+ async def get_audience(self, audience_id: str) -> dict[str, Any]:
597
547
  """
598
548
  Retrieves the details of a single audience using its unique ID. This provides a targeted lookup for one audience, distinct from `list_audiences` which fetches all available audiences in the account.
599
549
 
@@ -609,14 +559,14 @@ class ResendApp(APIApplication):
609
559
  Tags:
610
560
  fetch, audience, management, api
611
561
  """
612
- self.api_key
562
+ api_key = await self.get_api_key()
613
563
  try:
614
564
  audience = resend.Audiences.get(id=audience_id)
615
565
  return audience
616
566
  except Exception as e:
617
567
  raise ToolError(f"Failed to retrieve audience: {e}")
618
568
 
619
- def remove_audience(self, audience_id: str) -> dict[str, Any]:
569
+ async def remove_audience(self, audience_id: str) -> dict[str, Any]:
620
570
  """
621
571
  Deletes a specific audience from the Resend service using its unique identifier. This function wraps the Resend API's remove operation, returning the API's response. Unlike `remove_contact`, which targets individuals, this function removes the entire contact list defined by the audience ID.
622
572
 
@@ -632,14 +582,14 @@ class ResendApp(APIApplication):
632
582
  Tags:
633
583
  remove, audience, management, api
634
584
  """
635
- self.api_key
585
+ api_key = await self.get_api_key()
636
586
  try:
637
587
  response = resend.Audiences.remove(id=audience_id)
638
588
  return response
639
589
  except Exception as e:
640
590
  raise ToolError(f"Failed to remove audience: {e}")
641
591
 
642
- def list_audiences(self) -> list[dict[str, Any]]:
592
+ async def list_audiences(self) -> list[dict[str, Any]]:
643
593
  """
644
594
  Retrieves a complete list of all audiences from the Resend account. It returns a list of dictionaries, with each containing the details of a specific audience. This function is distinct from `get_audience`, which fetches a single audience by its ID.
645
595
 
@@ -652,20 +602,15 @@ class ResendApp(APIApplication):
652
602
  Tags:
653
603
  list, audiences, management, important
654
604
  """
655
- self.api_key
605
+ api_key = await self.get_api_key()
656
606
  try:
657
607
  audiences = resend.Audiences.list()
658
608
  return audiences
659
609
  except Exception as e:
660
610
  raise ToolError(f"Failed to list audiences: {e}")
661
611
 
662
- def create_contact(
663
- self,
664
- audience_id: str,
665
- email: str,
666
- first_name: str | None = None,
667
- last_name: str | None = None,
668
- unsubscribed: bool = False,
612
+ async def create_contact(
613
+ self, audience_id: str, email: str, first_name: str | None = None, last_name: str | None = None, unsubscribed: bool = False
669
614
  ) -> dict[str, Any]:
670
615
  """
671
616
  Creates a new contact with a given email, optional name, and subscription status, adding it to a specific audience. This function populates audience lists, differing from `update_contact` which modifies existing entries, and requires a valid `audience_id` to function.
@@ -686,12 +631,8 @@ class ResendApp(APIApplication):
686
631
  Tags:
687
632
  create, contact, management, important
688
633
  """
689
- self.api_key
690
- params: resend.Contacts.CreateParams = {
691
- "audience_id": audience_id,
692
- "email": email,
693
- "unsubscribed": unsubscribed,
694
- }
634
+ api_key = await self.get_api_key()
635
+ params: resend.Contacts.CreateParams = {"audience_id": audience_id, "email": email, "unsubscribed": unsubscribed}
695
636
  if first_name:
696
637
  params["first_name"] = first_name
697
638
  if last_name:
@@ -702,9 +643,7 @@ class ResendApp(APIApplication):
702
643
  except Exception as e:
703
644
  raise ToolError(f"Failed to create contact: {e}")
704
645
 
705
- def get_contact(
706
- self, audience_id: str, contact_id: str | None = None, email: str | None = None
707
- ) -> dict[str, Any]:
646
+ async def get_contact(self, audience_id: str, contact_id: str | None = None, email: str | None = None) -> dict[str, Any]:
708
647
  """
709
648
  Fetches a single contact's details from a specified audience by its unique ID or email address. The function requires exactly one identifier for the lookup, raising an error if the identifier is missing, ambiguous, or if the API call fails.
710
649
 
@@ -722,7 +661,7 @@ class ResendApp(APIApplication):
722
661
  Tags:
723
662
  retrieve, contact, audience, management, api
724
663
  """
725
- self.api_key
664
+ api_key = await self.get_api_key()
726
665
  if not (contact_id or email) or (contact_id and email):
727
666
  raise ToolError("You must provide exactly one of 'contact_id' or 'email'.")
728
667
  params = {"audience_id": audience_id}
@@ -736,7 +675,7 @@ class ResendApp(APIApplication):
736
675
  except Exception as e:
737
676
  raise ToolError(f"Failed to retrieve contact: {e}")
738
677
 
739
- def update_contact(
678
+ async def update_contact(
740
679
  self,
741
680
  audience_id: str,
742
681
  contact_id: str | None = None,
@@ -765,11 +704,9 @@ class ResendApp(APIApplication):
765
704
  Tags:
766
705
  update, contact, management
767
706
  """
768
- self.api_key
707
+ api_key = await self.get_api_key()
769
708
  if not (contact_id or email) or (contact_id and email):
770
- raise ToolError(
771
- "You must provide exactly one of 'contact_id' or 'email' to identify the contact."
772
- )
709
+ raise ToolError("You must provide exactly one of 'contact_id' or 'email' to identify the contact.")
773
710
  params: resend.Contacts.UpdateParams = {"audience_id": audience_id}
774
711
  if contact_id:
775
712
  params["id"] = contact_id
@@ -781,19 +718,15 @@ class ResendApp(APIApplication):
781
718
  params["last_name"] = last_name
782
719
  if unsubscribed is not None:
783
720
  params["unsubscribed"] = unsubscribed
784
- if len(params) <= 2: # Only audience_id and one identifier
785
- raise ToolError(
786
- "At least one field to update (e.g., first_name, unsubscribed) must be provided."
787
- )
721
+ if len(params) <= 2:
722
+ raise ToolError("At least one field to update (e.g., first_name, unsubscribed) must be provided.")
788
723
  try:
789
724
  response = resend.Contacts.update(params)
790
725
  return response
791
726
  except Exception as e:
792
727
  raise ToolError(f"Failed to update contact: {e}")
793
728
 
794
- def remove_contact(
795
- self, audience_id: str, contact_id: str | None = None, email: str | None = None
796
- ) -> dict[str, Any]:
729
+ async def remove_contact(self, audience_id: str, contact_id: str | None = None, email: str | None = None) -> dict[str, Any]:
797
730
  """
798
731
  Removes a contact from a specified audience. The contact must be identified by either its unique ID or email address, but not both. Raises an error if the identifier is missing, ambiguous, or if the API call to the Resend service fails.
799
732
 
@@ -811,7 +744,7 @@ class ResendApp(APIApplication):
811
744
  Tags:
812
745
  remove, contact-management, api-call
813
746
  """
814
- self.api_key
747
+ api_key = await self.get_api_key()
815
748
  if not (contact_id or email) or (contact_id and email):
816
749
  raise ToolError("You must provide exactly one of 'contact_id' or 'email'.")
817
750
  params = {"audience_id": audience_id}
@@ -825,7 +758,7 @@ class ResendApp(APIApplication):
825
758
  except Exception as e:
826
759
  raise ToolError(f"Failed to remove contact: {e}")
827
760
 
828
- def list_contacts(self, audience_id: str) -> list[dict[str, Any]]:
761
+ async def list_contacts(self, audience_id: str) -> list[dict[str, Any]]:
829
762
  """
830
763
  Retrieves a complete list of contacts belonging to a specific audience, identified by its unique ID. This function returns all contacts within the audience, unlike `get_contact` which retrieves only a single contact by its ID or email.
831
764
 
@@ -841,7 +774,7 @@ class ResendApp(APIApplication):
841
774
  Tags:
842
775
  list, contacts, management, important
843
776
  """
844
- self.api_key
777
+ api_key = await self.get_api_key()
845
778
  try:
846
779
  contacts = resend.Contacts.list(audience_id=audience_id)
847
780
  return contacts