universal-mcp-applications 0.1.33__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 (113) 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 +86 -24
  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 +98 -202
  41. universal_mcp/applications/google_drive/app.py +194 -793
  42. universal_mcp/applications/google_gemini/app.py +27 -62
  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 +171 -624
  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 +5 -0
  56. universal_mcp/applications/linkedin/app.py +332 -227
  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/app.py +26 -48
  64. universal_mcp/applications/openai/app.py +42 -165
  65. universal_mcp/applications/outlook/README.md +22 -9
  66. universal_mcp/applications/outlook/app.py +403 -141
  67. universal_mcp/applications/perplexity/README.md +2 -1
  68. universal_mcp/applications/perplexity/app.py +162 -20
  69. universal_mcp/applications/pipedrive/app.py +1021 -3331
  70. universal_mcp/applications/posthog/app.py +272 -541
  71. universal_mcp/applications/reddit/app.py +61 -160
  72. universal_mcp/applications/resend/app.py +41 -107
  73. universal_mcp/applications/retell/app.py +23 -50
  74. universal_mcp/applications/rocketlane/app.py +250 -963
  75. universal_mcp/applications/scraper/app.py +67 -125
  76. universal_mcp/applications/semanticscholar/app.py +36 -78
  77. universal_mcp/applications/semrush/app.py +43 -77
  78. universal_mcp/applications/sendgrid/app.py +826 -1576
  79. universal_mcp/applications/sentry/app.py +444 -1079
  80. universal_mcp/applications/serpapi/app.py +40 -143
  81. universal_mcp/applications/sharepoint/app.py +27 -49
  82. universal_mcp/applications/shopify/app.py +1743 -4479
  83. universal_mcp/applications/shortcut/app.py +272 -534
  84. universal_mcp/applications/slack/app.py +41 -123
  85. universal_mcp/applications/spotify/app.py +206 -405
  86. universal_mcp/applications/supabase/app.py +174 -283
  87. universal_mcp/applications/tavily/app.py +2 -2
  88. universal_mcp/applications/trello/app.py +853 -2816
  89. universal_mcp/applications/twilio/app.py +14 -50
  90. universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
  91. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
  92. universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
  93. universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
  94. universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
  95. universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
  96. universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
  97. universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
  98. universal_mcp/applications/whatsapp/app.py +35 -186
  99. universal_mcp/applications/whatsapp/audio.py +2 -6
  100. universal_mcp/applications/whatsapp/whatsapp.py +17 -51
  101. universal_mcp/applications/whatsapp_business/app.py +86 -299
  102. universal_mcp/applications/wrike/app.py +80 -153
  103. universal_mcp/applications/yahoo_finance/app.py +19 -65
  104. universal_mcp/applications/youtube/app.py +120 -306
  105. universal_mcp/applications/zenquotes/app.py +3 -3
  106. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/METADATA +4 -2
  107. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/RECORD +109 -113
  108. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/WHEEL +1 -1
  109. universal_mcp/applications/hubspot/api_segments/__init__.py +0 -0
  110. universal_mcp/applications/hubspot/api_segments/api_segment_base.py +0 -54
  111. universal_mcp/applications/hubspot/api_segments/crm_api.py +0 -7337
  112. universal_mcp/applications/hubspot/api_segments/marketing_api.py +0 -1467
  113. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc8.dist-info}/licenses/LICENSE +0 -0
@@ -1,18 +1,9 @@
1
1
  from collections.abc import Iterable
2
2
  from typing import Any
3
-
4
- # Import necessary components from pyairtable
5
3
  from pyairtable import Api
6
4
  from pyairtable.api.base import Base
7
5
  from pyairtable.api.table import Table
8
- from pyairtable.api.types import (
9
- RecordDeletedDict,
10
- RecordDict,
11
- RecordId,
12
- UpdateRecordDict,
13
- UpsertResultDict,
14
- WritableFields,
15
- )
6
+ from pyairtable.api.types import RecordDeletedDict, RecordDict, RecordId, UpdateRecordDict, UpsertResultDict, WritableFields
16
7
  from pyairtable.formulas import Formula, to_formula_str
17
8
  from universal_mcp.applications.application import APIApplication
18
9
  from universal_mcp.integrations import Integration
@@ -32,18 +23,12 @@ class AirtableApp(APIApplication):
32
23
  if not self.integration:
33
24
  raise ValueError("Integration is not set for AirtableApp.")
34
25
  credentials = self.integration.get_credentials()
35
- api_key = (
36
- credentials.get("api_key")
37
- or credentials.get("apiKey")
38
- or credentials.get("API_KEY")
39
- )
26
+ api_key = credentials.get("api_key") or credentials.get("apiKey") or credentials.get("API_KEY")
40
27
  if not api_key:
41
28
  raise ValueError("Airtable API key is not configured in the integration.")
42
29
  return Api(api_key)
43
30
 
44
- def _prepare_pyairtable_params(
45
- self, collected_options: dict[str, Any]
46
- ) -> dict[str, Any]:
31
+ def _prepare_pyairtable_params(self, collected_options: dict[str, Any]) -> dict[str, Any]:
47
32
  """
48
33
  Extracts the actual parameters for pyairtable from the collected options.
49
34
  If `collected_options` contains a key "options" whose value is a dictionary
@@ -53,10 +38,9 @@ class AirtableApp(APIApplication):
53
38
  nested_options = collected_options.get("options")
54
39
  if isinstance(nested_options, dict):
55
40
  return nested_options
56
-
57
41
  return collected_options
58
42
 
59
- def list_bases(self) -> list[Base] | str:
43
+ async def list_bases(self) -> list[Base] | str:
60
44
  """
61
45
  Lists all bases accessible with the current API key.
62
46
 
@@ -73,7 +57,7 @@ class AirtableApp(APIApplication):
73
57
  except Exception as e:
74
58
  return f"Error listing bases: {type(e).__name__} - {e}"
75
59
 
76
- def list_tables(self, base_id: str) -> list[Table] | str:
60
+ async def list_tables(self, base_id: str) -> list[Table] | str:
77
61
  """
78
62
  Lists all tables within a specified base.
79
63
 
@@ -92,13 +76,9 @@ class AirtableApp(APIApplication):
92
76
  base = client.base(base_id)
93
77
  return base.tables()
94
78
  except Exception as e:
95
- return (
96
- f"Error listing tables for base '{base_id}': {type(e).__name__} - {e}"
97
- )
79
+ return f"Error listing tables for base '{base_id}': {type(e).__name__} - {e}"
98
80
 
99
- def get_record(
100
- self, base_id: str, table_id_or_name: str, record_id: RecordId, **options: Any
101
- ) -> RecordDict | str:
81
+ async def get_record(self, base_id: str, table_id_or_name: str, record_id: RecordId, **options: Any) -> RecordDict | str:
102
82
  """
103
83
  Retrieves a single record by its ID from a specified table within a base.
104
84
 
@@ -125,9 +105,7 @@ class AirtableApp(APIApplication):
125
105
  except Exception as e:
126
106
  return f"Error getting record '{record_id}' from '{table_id_or_name}' in '{base_id}': {type(e).__name__} - {e}"
127
107
 
128
- def list_records(
129
- self, base_id: str, table_id_or_name: str, **options: Any
130
- ) -> list[RecordDict] | str:
108
+ async def list_records(self, base_id: str, table_id_or_name: str, **options: Any) -> list[RecordDict] | str:
131
109
  """
132
110
  Lists records from a specified table within a base.
133
111
 
@@ -150,26 +128,13 @@ class AirtableApp(APIApplication):
150
128
  client = self._get_client()
151
129
  table = client.table(base_id, table_id_or_name)
152
130
  pyairtable_params = self._prepare_pyairtable_params(options)
153
-
154
- # Convert Formula object to string if provided, after preparing params
155
- if "formula" in pyairtable_params and isinstance(
156
- pyairtable_params["formula"], Formula
157
- ):
158
- pyairtable_params["formula"] = to_formula_str(
159
- pyairtable_params["formula"]
160
- )
161
-
131
+ if "formula" in pyairtable_params and isinstance(pyairtable_params["formula"], Formula):
132
+ pyairtable_params["formula"] = to_formula_str(pyairtable_params["formula"])
162
133
  return table.all(**pyairtable_params)
163
134
  except Exception as e:
164
135
  return f"Error listing records from '{table_id_or_name}' in '{base_id}': {type(e).__name__} - {e}"
165
136
 
166
- def create_record(
167
- self,
168
- base_id: str,
169
- table_id_or_name: str,
170
- fields: WritableFields,
171
- **options: Any, # Captures typecast, use_field_ids etc.
172
- ) -> RecordDict | str:
137
+ async def create_record(self, base_id: str, table_id_or_name: str, fields: WritableFields, **options: Any) -> RecordDict | str:
173
138
  """
174
139
  Creates a new record in a specified table within a base.
175
140
 
@@ -191,44 +156,20 @@ class AirtableApp(APIApplication):
191
156
  try:
192
157
  client = self._get_client()
193
158
  table = client.table(base_id, table_id_or_name)
194
- # pyairtable's Table.create() takes typecast and use_field_ids as named args,
195
- # not as **kwargs. We need to extract them or use defaults.
196
-
197
159
  prepared_options = self._prepare_pyairtable_params(options)
198
160
  prepared_options.get("typecast", False)
199
- prepared_options.get(
200
- "use_field_ids"
201
- ) # Let pyairtable handle default if None
202
-
203
- # Ensure only valid kwargs for pyairtable's `create` are passed if it doesn't use **kwargs for these
204
- # For pyairtable.Table.create, it only takes `typecast` and `use_field_ids` as specific keyword args.
205
- # The `**options` in `AirtableApp` could collect other things if the tool call sends them.
206
- # The `pyairtable.Table.create` signature is:
207
- # create(self, fields: WritableFields, typecast: bool = False, use_field_ids: Optional[bool] = None)
208
- # It does NOT take a general **kwargs.
209
-
210
- # So, we must call it with the specific parameters.
211
- # `_prepare_pyairtable_params` helps if "options" is nested, but we still need to map.
212
-
161
+ prepared_options.get("use_field_ids")
213
162
  call_kwargs = {}
214
163
  if "typecast" in prepared_options:
215
164
  call_kwargs["typecast"] = prepared_options["typecast"]
216
- if (
217
- "use_field_ids" in prepared_options
218
- ): # Pass it only if explicitly provided
165
+ if "use_field_ids" in prepared_options:
219
166
  call_kwargs["use_field_ids"] = prepared_options["use_field_ids"]
220
-
221
167
  return table.create(fields=fields, **call_kwargs)
222
168
  except Exception as e:
223
169
  return f"Error creating record in '{table_id_or_name}' in '{base_id}': {type(e).__name__} - {e}"
224
170
 
225
- def update_record(
226
- self,
227
- base_id: str,
228
- table_id_or_name: str,
229
- record_id: RecordId,
230
- fields: WritableFields,
231
- **options: Any, # Captures replace, typecast, use_field_ids etc.
171
+ async def update_record(
172
+ self, base_id: str, table_id_or_name: str, record_id: RecordId, fields: WritableFields, **options: Any
232
173
  ) -> RecordDict | str:
233
174
  """
234
175
  Updates an existing record in a specified table within a base.
@@ -252,11 +193,6 @@ class AirtableApp(APIApplication):
252
193
  try:
253
194
  client = self._get_client()
254
195
  table = client.table(base_id, table_id_or_name)
255
- # pyairtable.Table.update() signature:
256
- # update(self, record_id: RecordId, fields: WritableFields, replace: bool = False,
257
- # typecast: bool = False, use_field_ids: Optional[bool] = None)
258
- # It does NOT take a general **kwargs.
259
-
260
196
  prepared_options = self._prepare_pyairtable_params(options)
261
197
  call_kwargs = {}
262
198
  if "replace" in prepared_options:
@@ -265,14 +201,11 @@ class AirtableApp(APIApplication):
265
201
  call_kwargs["typecast"] = prepared_options["typecast"]
266
202
  if "use_field_ids" in prepared_options:
267
203
  call_kwargs["use_field_ids"] = prepared_options["use_field_ids"]
268
-
269
204
  return table.update(record_id, fields=fields, **call_kwargs)
270
205
  except Exception as e:
271
206
  return f"Error updating record '{record_id}' in '{table_id_or_name}' in '{base_id}': {type(e).__name__} - {e}"
272
207
 
273
- def delete_record(
274
- self, base_id: str, table_id_or_name: str, record_id: RecordId
275
- ) -> RecordDeletedDict | str:
208
+ async def delete_record(self, base_id: str, table_id_or_name: str, record_id: RecordId) -> RecordDeletedDict | str:
276
209
  """
277
210
  Deletes a record from a specified table within a base.
278
211
 
@@ -295,12 +228,8 @@ class AirtableApp(APIApplication):
295
228
  except Exception as e:
296
229
  return f"Error deleting record '{record_id}' from '{table_id_or_name}' in '{base_id}': {type(e).__name__} - {e}"
297
230
 
298
- def batch_create_records(
299
- self,
300
- base_id: str,
301
- table_id_or_name: str,
302
- records: Iterable[WritableFields],
303
- **options: Any, # Captures typecast, use_field_ids etc.
231
+ async def batch_create_records(
232
+ self, base_id: str, table_id_or_name: str, records: Iterable[WritableFields], **options: Any
304
233
  ) -> list[RecordDict] | str:
305
234
  """
306
235
  Creates multiple records in batches in a specified table.
@@ -323,27 +252,18 @@ class AirtableApp(APIApplication):
323
252
  try:
324
253
  client = self._get_client()
325
254
  table = client.table(base_id, table_id_or_name)
326
- # pyairtable.Table.batch_create() signature:
327
- # batch_create(self, records: Iterable[WritableFields], typecast: bool = False, use_field_ids: Optional[bool] = None)
328
- # It does NOT take a general **kwargs.
329
-
330
255
  prepared_options = self._prepare_pyairtable_params(options)
331
256
  call_kwargs = {}
332
257
  if "typecast" in prepared_options:
333
258
  call_kwargs["typecast"] = prepared_options["typecast"]
334
259
  if "use_field_ids" in prepared_options:
335
260
  call_kwargs["use_field_ids"] = prepared_options["use_field_ids"]
336
-
337
261
  return table.batch_create(records, **call_kwargs)
338
262
  except Exception as e:
339
263
  return f"Error batch creating records in '{table_id_or_name}' in '{base_id}': {type(e).__name__} - {e}"
340
264
 
341
- def batch_update_records(
342
- self,
343
- base_id: str,
344
- table_id_or_name: str,
345
- records: Iterable[UpdateRecordDict],
346
- **options: Any, # Captures replace, typecast, use_field_ids etc.
265
+ async def batch_update_records(
266
+ self, base_id: str, table_id_or_name: str, records: Iterable[UpdateRecordDict], **options: Any
347
267
  ) -> list[RecordDict] | str:
348
268
  """
349
269
  Updates multiple records in batches in a specified table.
@@ -366,11 +286,6 @@ class AirtableApp(APIApplication):
366
286
  try:
367
287
  client = self._get_client()
368
288
  table = client.table(base_id, table_id_or_name)
369
- # pyairtable.Table.batch_update() signature:
370
- # batch_update(self, records: Iterable[UpdateRecordDict], replace: bool = False,
371
- # typecast: bool = False, use_field_ids: Optional[bool] = None)
372
- # It does NOT take a general **kwargs.
373
-
374
289
  prepared_options = self._prepare_pyairtable_params(options)
375
290
  call_kwargs = {}
376
291
  if "replace" in prepared_options:
@@ -379,12 +294,11 @@ class AirtableApp(APIApplication):
379
294
  call_kwargs["typecast"] = prepared_options["typecast"]
380
295
  if "use_field_ids" in prepared_options:
381
296
  call_kwargs["use_field_ids"] = prepared_options["use_field_ids"]
382
-
383
297
  return table.batch_update(records, **call_kwargs)
384
298
  except Exception as e:
385
299
  return f"Error batch updating records in '{table_id_or_name}' in '{base_id}': {type(e).__name__} - {e}"
386
300
 
387
- def batch_delete_records(
301
+ async def batch_delete_records(
388
302
  self, base_id: str, table_id_or_name: str, record_ids: Iterable[RecordId]
389
303
  ) -> list[RecordDeletedDict] | str:
390
304
  """
@@ -409,15 +323,8 @@ class AirtableApp(APIApplication):
409
323
  except Exception as e:
410
324
  return f"Error batch deleting records from '{table_id_or_name}' in '{base_id}': {type(e).__name__} - {e}"
411
325
 
412
- def batch_upsert_records(
413
- self,
414
- base_id: str,
415
- table_id_or_name: str,
416
- records: Iterable[
417
- dict[str, Any]
418
- ], # pyairtable expects Dict, not UpdateRecordDict here
419
- key_fields: list[str],
420
- **options: Any, # Captures replace, typecast, use_field_ids etc.
326
+ async def batch_upsert_records(
327
+ self, base_id: str, table_id_or_name: str, records: Iterable[dict[str, Any]], key_fields: list[str], **options: Any
421
328
  ) -> UpsertResultDict | str:
422
329
  """
423
330
  Updates or creates records in batches in a specified table.
@@ -444,11 +351,6 @@ class AirtableApp(APIApplication):
444
351
  try:
445
352
  client = self._get_client()
446
353
  table = client.table(base_id, table_id_or_name)
447
- # pyairtable.Table.batch_upsert() signature:
448
- # batch_upsert(self, records: Iterable[Dict[str, Any]], key_fields: List[FieldName],
449
- # replace: bool = False, typecast: bool = False, use_field_ids: Optional[bool] = None)
450
- # It does NOT take a general **kwargs.
451
-
452
354
  prepared_options = self._prepare_pyairtable_params(options)
453
355
  call_kwargs = {}
454
356
  if "replace" in prepared_options:
@@ -457,7 +359,6 @@ class AirtableApp(APIApplication):
457
359
  call_kwargs["typecast"] = prepared_options["typecast"]
458
360
  if "use_field_ids" in prepared_options:
459
361
  call_kwargs["use_field_ids"] = prepared_options["use_field_ids"]
460
-
461
362
  return table.batch_upsert(records, key_fields=key_fields, **call_kwargs)
462
363
  except Exception as e:
463
364
  return f"Error batch upserting records in '{table_id_or_name}' in '{base_id}': {type(e).__name__} - {e}"