universal-mcp-applications 0.1.32__py3-none-any.whl → 0.1.36rc2__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 (105) hide show
  1. universal_mcp/applications/ahrefs/app.py +52 -198
  2. universal_mcp/applications/airtable/app.py +23 -122
  3. universal_mcp/applications/apollo/app.py +111 -464
  4. universal_mcp/applications/asana/app.py +417 -1567
  5. universal_mcp/applications/aws_s3/app.py +36 -103
  6. universal_mcp/applications/bill/app.py +546 -1957
  7. universal_mcp/applications/box/app.py +1068 -3981
  8. universal_mcp/applications/braze/app.py +364 -1430
  9. universal_mcp/applications/browser_use/app.py +2 -8
  10. universal_mcp/applications/cal_com_v2/app.py +207 -625
  11. universal_mcp/applications/calendly/app.py +61 -200
  12. universal_mcp/applications/canva/app.py +45 -110
  13. universal_mcp/applications/clickup/app.py +207 -674
  14. universal_mcp/applications/coda/app.py +146 -426
  15. universal_mcp/applications/confluence/app.py +310 -1098
  16. universal_mcp/applications/contentful/app.py +36 -151
  17. universal_mcp/applications/crustdata/app.py +28 -107
  18. universal_mcp/applications/dialpad/app.py +283 -756
  19. universal_mcp/applications/digitalocean/app.py +1766 -5777
  20. universal_mcp/applications/domain_checker/app.py +3 -54
  21. universal_mcp/applications/e2b/app.py +14 -64
  22. universal_mcp/applications/elevenlabs/app.py +9 -47
  23. universal_mcp/applications/exa/app.py +6 -17
  24. universal_mcp/applications/falai/app.py +24 -101
  25. universal_mcp/applications/figma/app.py +53 -137
  26. universal_mcp/applications/file_system/app.py +2 -13
  27. universal_mcp/applications/firecrawl/app.py +51 -152
  28. universal_mcp/applications/fireflies/app.py +59 -281
  29. universal_mcp/applications/fpl/app.py +91 -528
  30. universal_mcp/applications/fpl/utils/fixtures.py +15 -49
  31. universal_mcp/applications/fpl/utils/helper.py +25 -89
  32. universal_mcp/applications/fpl/utils/league_utils.py +20 -64
  33. universal_mcp/applications/ghost_content/app.py +52 -161
  34. universal_mcp/applications/github/app.py +19 -56
  35. universal_mcp/applications/gong/app.py +88 -248
  36. universal_mcp/applications/google_calendar/app.py +16 -68
  37. universal_mcp/applications/google_docs/app.py +85 -189
  38. universal_mcp/applications/google_drive/app.py +141 -463
  39. universal_mcp/applications/google_gemini/app.py +12 -64
  40. universal_mcp/applications/google_mail/app.py +28 -157
  41. universal_mcp/applications/google_searchconsole/app.py +15 -48
  42. universal_mcp/applications/google_sheet/app.py +100 -581
  43. universal_mcp/applications/google_sheet/helper.py +10 -37
  44. universal_mcp/applications/hashnode/app.py +57 -269
  45. universal_mcp/applications/heygen/app.py +44 -122
  46. universal_mcp/applications/http_tools/app.py +10 -32
  47. universal_mcp/applications/hubspot/api_segments/crm_api.py +460 -1573
  48. universal_mcp/applications/hubspot/api_segments/marketing_api.py +74 -262
  49. universal_mcp/applications/hubspot/app.py +23 -87
  50. universal_mcp/applications/jira/app.py +2071 -7986
  51. universal_mcp/applications/klaviyo/app.py +494 -1376
  52. universal_mcp/applications/linkedin/README.md +9 -2
  53. universal_mcp/applications/linkedin/app.py +240 -181
  54. universal_mcp/applications/mailchimp/app.py +450 -1605
  55. universal_mcp/applications/markitdown/app.py +8 -20
  56. universal_mcp/applications/miro/app.py +217 -699
  57. universal_mcp/applications/ms_teams/app.py +64 -186
  58. universal_mcp/applications/neon/app.py +86 -192
  59. universal_mcp/applications/notion/app.py +21 -36
  60. universal_mcp/applications/onedrive/app.py +16 -38
  61. universal_mcp/applications/openai/app.py +42 -165
  62. universal_mcp/applications/outlook/app.py +24 -84
  63. universal_mcp/applications/perplexity/app.py +4 -19
  64. universal_mcp/applications/pipedrive/app.py +832 -3142
  65. universal_mcp/applications/posthog/app.py +163 -432
  66. universal_mcp/applications/reddit/app.py +40 -139
  67. universal_mcp/applications/resend/app.py +41 -107
  68. universal_mcp/applications/retell/app.py +14 -41
  69. universal_mcp/applications/rocketlane/app.py +221 -934
  70. universal_mcp/applications/scraper/README.md +7 -4
  71. universal_mcp/applications/scraper/app.py +50 -109
  72. universal_mcp/applications/semanticscholar/app.py +22 -64
  73. universal_mcp/applications/semrush/app.py +43 -77
  74. universal_mcp/applications/sendgrid/app.py +512 -1262
  75. universal_mcp/applications/sentry/app.py +271 -906
  76. universal_mcp/applications/serpapi/app.py +40 -143
  77. universal_mcp/applications/sharepoint/app.py +17 -39
  78. universal_mcp/applications/shopify/app.py +1551 -4287
  79. universal_mcp/applications/shortcut/app.py +155 -417
  80. universal_mcp/applications/slack/app.py +33 -115
  81. universal_mcp/applications/spotify/app.py +126 -325
  82. universal_mcp/applications/supabase/app.py +104 -213
  83. universal_mcp/applications/tavily/app.py +1 -1
  84. universal_mcp/applications/trello/app.py +693 -2656
  85. universal_mcp/applications/twilio/app.py +14 -50
  86. universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
  87. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
  88. universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
  89. universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
  90. universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
  91. universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
  92. universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
  93. universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
  94. universal_mcp/applications/whatsapp/app.py +35 -186
  95. universal_mcp/applications/whatsapp/audio.py +2 -6
  96. universal_mcp/applications/whatsapp/whatsapp.py +17 -51
  97. universal_mcp/applications/whatsapp_business/app.py +70 -283
  98. universal_mcp/applications/wrike/app.py +45 -118
  99. universal_mcp/applications/yahoo_finance/app.py +19 -65
  100. universal_mcp/applications/youtube/app.py +75 -261
  101. universal_mcp/applications/zenquotes/app.py +2 -2
  102. {universal_mcp_applications-0.1.32.dist-info → universal_mcp_applications-0.1.36rc2.dist-info}/METADATA +2 -2
  103. {universal_mcp_applications-0.1.32.dist-info → universal_mcp_applications-0.1.36rc2.dist-info}/RECORD +105 -105
  104. {universal_mcp_applications-0.1.32.dist-info → universal_mcp_applications-0.1.36rc2.dist-info}/WHEEL +0 -0
  105. {universal_mcp_applications-0.1.32.dist-info → universal_mcp_applications-0.1.36rc2.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}"