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,5 +1,4 @@
1
1
  from typing import Any
2
-
3
2
  from universal_mcp.applications.application import APIApplication
4
3
  from universal_mcp.integrations import Integration
5
4
 
@@ -15,13 +14,9 @@ class NotionApp(APIApplication):
15
14
  credentials = self.integration.get_credentials()
16
15
  if "headers" in credentials:
17
16
  return credentials["headers"]
18
- return {
19
- "Authorization": f"Bearer {credentials['access_token']}",
20
- "Accept": "application/json",
21
- "Notion-Version": "2022-06-28",
22
- }
17
+ return {"Authorization": f"Bearer {credentials['access_token']}", "Accept": "application/json", "Notion-Version": "2022-06-28"}
23
18
 
24
- def retrieve_a_user(self, id, request_body=None) -> dict[str, Any]:
19
+ async def retrieve_a_user(self, id, request_body=None) -> dict[str, Any]:
25
20
  """
26
21
  Retrieves a user's details from the server using their unique identifier.
27
22
 
@@ -43,13 +38,11 @@ class NotionApp(APIApplication):
43
38
  raise ValueError("Missing required parameter 'id'")
44
39
  url = f"{self.base_url}/v1/users/{id}"
45
40
  query_params = {}
46
- response = self._get(url, params=query_params)
41
+ response = await self._aget(url, params=query_params)
47
42
  response.raise_for_status()
48
43
  return response.json()
49
44
 
50
- def list_all_users(
51
- self,
52
- ) -> dict[str, Any]:
45
+ async def list_all_users(self) -> dict[str, Any]:
53
46
  """
54
47
  Retrieves a complete list of users from the API endpoint.
55
48
 
@@ -68,13 +61,11 @@ class NotionApp(APIApplication):
68
61
  """
69
62
  url = f"{self.base_url}/v1/users"
70
63
  query_params = {}
71
- response = self._get(url, params=query_params)
64
+ response = await self._aget(url, params=query_params)
72
65
  response.raise_for_status()
73
66
  return response.json()
74
67
 
75
- def retrieve_your_token_sbot_user(
76
- self,
77
- ) -> dict[str, Any]:
68
+ async def retrieve_your_token_sbot_user(self) -> dict[str, Any]:
78
69
  """
79
70
  Retrieves the current user's authentication token information from the SBOT service.
80
71
 
@@ -90,11 +81,11 @@ class NotionApp(APIApplication):
90
81
  """
91
82
  url = f"{self.base_url}/v1/users/me"
92
83
  query_params = {}
93
- response = self._get(url, params=query_params)
84
+ response = await self._aget(url, params=query_params)
94
85
  response.raise_for_status()
95
86
  return response.json()
96
87
 
97
- def retrieve_a_database(self, id) -> dict[str, Any]:
88
+ async def retrieve_a_database(self, id) -> dict[str, Any]:
98
89
  """
99
90
  Retrieves detailed information about a specific database using its unique identifier.
100
91
 
@@ -115,11 +106,11 @@ class NotionApp(APIApplication):
115
106
  raise ValueError("Missing required parameter 'id'")
116
107
  url = f"{self.base_url}/v1/databases/{id}"
117
108
  query_params = {}
118
- response = self._get(url, params=query_params)
109
+ response = await self._aget(url, params=query_params)
119
110
  response.raise_for_status()
120
111
  return response.json()
121
112
 
122
- def update_a_database(self, id, request_body=None) -> dict[str, Any]:
113
+ async def update_a_database(self, id, request_body=None) -> dict[str, Any]:
123
114
  """
124
115
  Updates a database entry with the specified ID using a PATCH request.
125
116
 
@@ -145,7 +136,7 @@ class NotionApp(APIApplication):
145
136
  response.raise_for_status()
146
137
  return response.json()
147
138
 
148
- def query_a_database(self, id, request_body=None) -> dict[str, Any]:
139
+ async def query_a_database(self, id, request_body=None) -> dict[str, Any]:
149
140
  """
150
141
  Executes a database query operation using a specified database ID and optional request parameters
151
142
 
@@ -167,11 +158,11 @@ class NotionApp(APIApplication):
167
158
  raise ValueError("Missing required parameter 'id'")
168
159
  url = f"{self.base_url}/v1/databases/{id}/query"
169
160
  query_params = {}
170
- response = self._post(url, data=request_body, params=query_params)
161
+ response = await self._apost(url, data=request_body, params=query_params)
171
162
  response.raise_for_status()
172
163
  return response.json()
173
164
 
174
- def create_a_database(self, request_body=None) -> dict[str, Any]:
165
+ async def create_a_database(self, request_body=None) -> dict[str, Any]:
175
166
  """
176
167
  Creates a new database on the server by sending a POST request to the database endpoint.
177
168
 
@@ -191,11 +182,11 @@ class NotionApp(APIApplication):
191
182
  """
192
183
  url = f"{self.base_url}/v1/databases/"
193
184
  query_params = {}
194
- response = self._post(url, data=request_body, params=query_params)
185
+ response = await self._apost(url, data=request_body, params=query_params)
195
186
  response.raise_for_status()
196
187
  return response.json()
197
188
 
198
- def create_a_page(self, request_body=None) -> dict[str, Any]:
189
+ async def create_a_page(self, request_body=None) -> dict[str, Any]:
199
190
  """
200
191
  Creates a new page by sending a POST request to the API endpoint.
201
192
 
@@ -214,11 +205,11 @@ class NotionApp(APIApplication):
214
205
  """
215
206
  url = f"{self.base_url}/v1/pages/"
216
207
  query_params = {}
217
- response = self._post(url, data=request_body, params=query_params)
208
+ response = await self._apost(url, data=request_body, params=query_params)
218
209
  response.raise_for_status()
219
210
  return response.json()
220
211
 
221
- def retrieve_a_page(self, id) -> dict[str, Any]:
212
+ async def retrieve_a_page(self, id) -> dict[str, Any]:
222
213
  """
223
214
  Retrieves a specific page's data from a remote server using its unique identifier.
224
215
 
@@ -239,11 +230,11 @@ class NotionApp(APIApplication):
239
230
  raise ValueError("Missing required parameter 'id'")
240
231
  url = f"{self.base_url}/v1/pages/{id}"
241
232
  query_params = {}
242
- response = self._get(url, params=query_params)
233
+ response = await self._aget(url, params=query_params)
243
234
  response.raise_for_status()
244
235
  return response.json()
245
236
 
246
- def update_page_properties(self, id, request_body=None) -> dict[str, Any]:
237
+ async def update_page_properties(self, id, request_body=None) -> dict[str, Any]:
247
238
  """
248
239
  Updates the properties of a page with the specified ID using the provided request body.
249
240
 
@@ -270,7 +261,7 @@ class NotionApp(APIApplication):
270
261
  response.raise_for_status()
271
262
  return response.json()
272
263
 
273
- def retrieve_a_page_property_item(self, page_id, property_id) -> dict[str, Any]:
264
+ async def retrieve_a_page_property_item(self, page_id, property_id) -> dict[str, Any]:
274
265
  """
275
266
  Retrieves a specific property item from a Notion page using the page ID and property ID.
276
267
 
@@ -294,11 +285,11 @@ class NotionApp(APIApplication):
294
285
  raise ValueError("Missing required parameter 'property_id'")
295
286
  url = f"{self.base_url}/v1/pages/{page_id}/properties/{property_id}"
296
287
  query_params = {}
297
- response = self._get(url, params=query_params)
288
+ response = await self._aget(url, params=query_params)
298
289
  response.raise_for_status()
299
290
  return response.json()
300
291
 
301
- def retrieve_block_children(self, id, page_size=None) -> dict[str, Any]:
292
+ async def retrieve_block_children(self, id, page_size=None) -> dict[str, Any]:
302
293
  """
303
294
  Retrieves all child blocks for a specified parent block using its ID via the API.
304
295
 
@@ -320,11 +311,11 @@ class NotionApp(APIApplication):
320
311
  raise ValueError("Missing required parameter 'id'")
321
312
  url = f"{self.base_url}/v1/blocks/{id}/children"
322
313
  query_params = {k: v for k, v in [("page_size", page_size)] if v is not None}
323
- response = self._get(url, params=query_params)
314
+ response = await self._aget(url, params=query_params)
324
315
  response.raise_for_status()
325
316
  return response.json()
326
317
 
327
- def append_block_children(self, id, request_body=None) -> dict[str, Any]:
318
+ async def append_block_children(self, id, request_body=None) -> dict[str, Any]:
328
319
  """
329
320
  Appends child elements to a specified block and returns the updated block data.
330
321
 
@@ -350,7 +341,7 @@ class NotionApp(APIApplication):
350
341
  response.raise_for_status()
351
342
  return response.json()
352
343
 
353
- def retrieve_a_block(self, id) -> dict[str, Any]:
344
+ async def retrieve_a_block(self, id) -> dict[str, Any]:
354
345
  """
355
346
  Retrieves a specific block of data from the API using its unique identifier.
356
347
 
@@ -371,11 +362,11 @@ class NotionApp(APIApplication):
371
362
  raise ValueError("Missing required parameter 'id'")
372
363
  url = f"{self.base_url}/v1/blocks/{id}"
373
364
  query_params = {}
374
- response = self._get(url, params=query_params)
365
+ response = await self._aget(url, params=query_params)
375
366
  response.raise_for_status()
376
367
  return response.json()
377
368
 
378
- def delete_a_block(self, id) -> dict[str, Any]:
369
+ async def delete_a_block(self, id) -> dict[str, Any]:
379
370
  """
380
371
  Deletes a specified block by its ID and returns the server response.
381
372
 
@@ -396,11 +387,11 @@ class NotionApp(APIApplication):
396
387
  raise ValueError("Missing required parameter 'id'")
397
388
  url = f"{self.base_url}/v1/blocks/{id}"
398
389
  query_params = {}
399
- response = self._delete(url, params=query_params)
390
+ response = await self._adelete(url, params=query_params)
400
391
  response.raise_for_status()
401
392
  return response.json()
402
393
 
403
- def update_a_block(self, id, request_body=None) -> dict[str, Any]:
394
+ async def update_a_block(self, id, request_body=None) -> dict[str, Any]:
404
395
  """
405
396
  Updates a specific block resource via a PATCH request to the API endpoint
406
397
 
@@ -426,7 +417,7 @@ class NotionApp(APIApplication):
426
417
  response.raise_for_status()
427
418
  return response.json()
428
419
 
429
- def search(self, request_body=None) -> dict[str, Any]:
420
+ async def search(self, request_body=None) -> dict[str, Any]:
430
421
  """
431
422
  Executes a search operation by sending a POST request to the search endpoint and returns the results
432
423
 
@@ -445,13 +436,11 @@ class NotionApp(APIApplication):
445
436
  """
446
437
  url = f"{self.base_url}/v1/search"
447
438
  query_params = {}
448
- response = self._post(url, data=request_body, params=query_params)
439
+ response = await self._apost(url, data=request_body, params=query_params)
449
440
  response.raise_for_status()
450
441
  return response.json()
451
442
 
452
- def retrieve_comments(
453
- self, block_id=None, page_size=None, request_body=None
454
- ) -> dict[str, Any]:
443
+ async def retrieve_comments(self, block_id=None, page_size=None, request_body=None) -> dict[str, Any]:
455
444
  """
456
445
  Retrieves comments from a remote server with optional block filtering and pagination support.
457
446
 
@@ -471,16 +460,12 @@ class NotionApp(APIApplication):
471
460
  retrieve, fetch, comments, api, pagination, http
472
461
  """
473
462
  url = f"{self.base_url}/v1/comments"
474
- query_params = {
475
- k: v
476
- for k, v in [("block_id", block_id), ("page_size", page_size)]
477
- if v is not None
478
- }
479
- response = self._get(url, params=query_params)
463
+ query_params = {k: v for k, v in [("block_id", block_id), ("page_size", page_size)] if v is not None}
464
+ response = await self._aget(url, params=query_params)
480
465
  response.raise_for_status()
481
466
  return response.json()
482
467
 
483
- def add_comment_to_page(self, request_body=None) -> dict[str, Any]:
468
+ async def add_comment_to_page(self, request_body=None) -> dict[str, Any]:
484
469
  """
485
470
  Adds a comment to a page by making an HTTP POST request to the comments endpoint.
486
471
 
@@ -499,7 +484,7 @@ class NotionApp(APIApplication):
499
484
  """
500
485
  url = f"{self.base_url}/v1/comments"
501
486
  query_params = {}
502
- response = self._post(url, data=request_body, params=query_params)
487
+ response = await self._apost(url, data=request_body, params=query_params)
503
488
  response.raise_for_status()
504
489
  return response.json()
505
490
 
@@ -1,7 +1,6 @@
1
1
  import base64
2
2
  import os
3
3
  from typing import Any
4
-
5
4
  from loguru import logger
6
5
  from universal_mcp.applications.application import APIApplication
7
6
  from universal_mcp.integrations import Integration
@@ -17,7 +16,7 @@ class OnedriveApp(APIApplication):
17
16
  super().__init__(name="onedrive", integration=integration, **kwargs)
18
17
  self.base_url = "https://graph.microsoft.com/v1.0"
19
18
 
20
- def get_my_profile(self) -> dict[str, Any]:
19
+ async def get_my_profile(self) -> dict[str, Any]:
21
20
  """
22
21
  Fetches the profile for the currently authenticated user, specifically retrieving their ID and user principal name. This function confirms user identity, distinguishing it from `get_drive_info`, which returns details about the OneDrive storage space (e.g., quota) rather than the user's personal profile.
23
22
 
@@ -32,10 +31,10 @@ class OnedriveApp(APIApplication):
32
31
  """
33
32
  url = f"{self.base_url}/me"
34
33
  query_params = {"$select": "id,userPrincipalName"}
35
- response = self._get(url, params=query_params)
34
+ response = await self._aget(url, params=query_params)
36
35
  return self._handle_response(response)
37
36
 
38
- def get_drive_info(self) -> dict[str, Any]:
37
+ async def get_drive_info(self) -> dict[str, Any]:
39
38
  """
40
39
  Fetches high-level information about the user's entire OneDrive. It returns drive-wide details like the owner and storage quota, differing from `get_item_metadata` which describes a specific item, and `get_my_profile` which retrieves general user account information.
41
40
 
@@ -46,7 +45,7 @@ class OnedriveApp(APIApplication):
46
45
  drive, storage, quota, info
47
46
  """
48
47
  url = f"{self.base_url}/me/drive"
49
- response = self._get(url)
48
+ response = await self._aget(url)
50
49
  return self._handle_response(response)
51
50
 
52
51
  def _list_drive_items(self, item_id: str = "root") -> dict[str, Any]:
@@ -63,7 +62,7 @@ class OnedriveApp(APIApplication):
63
62
  response = self._get(url)
64
63
  return self._handle_response(response)
65
64
 
66
- def search_files(self, query: str) -> dict[str, Any]:
65
+ async def search_files(self, query: str) -> dict[str, Any]:
67
66
  """
68
67
  Searches the user's entire OneDrive for files and folders matching a specified text query. This function performs a comprehensive search from the drive's root, distinguishing it from `list_files` or `list_folders` which only browse the contents of a single directory.
69
68
 
@@ -78,12 +77,11 @@ class OnedriveApp(APIApplication):
78
77
  """
79
78
  if not query:
80
79
  raise ValueError("Search query cannot be empty.")
81
-
82
80
  url = f"{self.base_url}/me/drive/root/search(q='{query}')"
83
- response = self._get(url)
81
+ response = await self._aget(url)
84
82
  return self._handle_response(response)
85
83
 
86
- def get_item_metadata(self, item_id: str) -> dict[str, Any]:
84
+ async def get_item_metadata(self, item_id: str) -> dict[str, Any]:
87
85
  """
88
86
  Fetches detailed metadata for a specific file or folder using its unique ID. It returns properties like name, size, and type. Unlike `get_document_content`, it doesn't retrieve the file's actual content, focusing solely on the item's attributes for quick inspection without a full download.
89
87
 
@@ -98,12 +96,11 @@ class OnedriveApp(APIApplication):
98
96
  """
99
97
  if not item_id:
100
98
  raise ValueError("Missing required parameter 'item_id'.")
101
-
102
99
  url = f"{self.base_url}/me/drive/items/{item_id}"
103
- response = self._get(url)
100
+ response = await self._aget(url)
104
101
  return self._handle_response(response)
105
102
 
106
- def create_folder(self, name: str, parent_id: str = "root") -> dict[str, Any]:
103
+ async def create_folder(self, name: str, parent_id: str = "root") -> dict[str, Any]:
107
104
  """
108
105
  Creates a new folder with a specified name within a parent directory, which defaults to the root. Returns metadata for the new folder. Unlike `create_folder_and_list`, this function only creates the folder and returns its specific metadata, not the parent directory's contents.
109
106
 
@@ -119,13 +116,12 @@ class OnedriveApp(APIApplication):
119
116
  """
120
117
  if not name:
121
118
  raise ValueError("Folder name cannot be empty.")
122
-
123
119
  url = f"{self.base_url}/me/drive/items/{parent_id}/children"
124
120
  data = {"name": name, "folder": {}, "@microsoft.graph.conflictBehavior": "rename"}
125
- response = self._post(url, data=data)
121
+ response = await self._apost(url, data=data)
126
122
  return self._handle_response(response)
127
123
 
128
- def delete_item(self, item_id: str) -> dict[str, Any]:
124
+ async def delete_item(self, item_id: str) -> dict[str, Any]:
129
125
  """
130
126
  Permanently deletes a specified file or folder from OneDrive using its unique item ID. This versatile function can remove any type of drive item, distinguished from functions that only list or create specific types. A successful deletion returns an empty response, confirming the item's removal.
131
127
 
@@ -140,12 +136,11 @@ class OnedriveApp(APIApplication):
140
136
  """
141
137
  if not item_id:
142
138
  raise ValueError("Missing required parameter 'item_id'.")
143
-
144
139
  url = f"{self.base_url}/me/drive/items/{item_id}"
145
- response = self._delete(url)
140
+ response = await self._adelete(url)
146
141
  return self._handle_response(response)
147
142
 
148
- def download_file(self, item_id: str) -> dict[str, Any]:
143
+ async def download_file(self, item_id: str) -> dict[str, Any]:
149
144
  """
150
145
  Retrieves a temporary, pre-authenticated download URL for a specific file using its item ID. This function provides a link for subsequent download, differing from `get_document_content` which directly fetches the file's raw content. The URL is returned within a dictionary.
151
146
 
@@ -160,16 +155,15 @@ class OnedriveApp(APIApplication):
160
155
  """
161
156
  if not item_id:
162
157
  raise ValueError("Missing required parameter 'item_id'.")
163
-
164
158
  url = f"{self.base_url}/me/drive/items/{item_id}"
165
- response = self._get(url)
159
+ response = await self._aget(url)
166
160
  metadata = self._handle_response(response)
167
161
  download_url = metadata.get("@microsoft.graph.downloadUrl")
168
162
  if not download_url:
169
163
  raise ValueError("Could not retrieve download URL for the item.")
170
164
  return {"download_url": download_url}
171
165
 
172
- def upload_file(self, file_path: str, parent_id: str = "root", file_name: str | None = None) -> dict[str, Any]:
166
+ async def upload_file(self, file_path: str, parent_id: str = "root", file_name: str | None = None) -> dict[str, Any]:
173
167
  """
174
168
  Uploads a local binary file (under 4MB) from a given path to a specified OneDrive folder. Unlike `upload_text_file`, which uploads string content, this function reads from the filesystem. The destination filename can be customized, and it returns the new file's metadata upon completion.
175
169
 
@@ -186,17 +180,15 @@ class OnedriveApp(APIApplication):
186
180
  """
187
181
  if not os.path.exists(file_path):
188
182
  raise FileNotFoundError(f"The file was not found at path: {file_path}")
189
-
190
183
  if not file_name:
191
184
  file_name = os.path.basename(file_path)
192
-
193
185
  url = f"{self.base_url}/me/drive/items/{parent_id}:/{file_name}:/content"
194
186
  with open(file_path, "rb") as f:
195
187
  data = f.read()
196
- response = self._put(url, data=data, content_type="application/octet-stream")
188
+ response = await self._aput(url, data=data, content_type="application/octet-stream")
197
189
  return self._handle_response(response)
198
190
 
199
- def list_folders(self, item_id: str = "root") -> dict[str, Any]:
191
+ async def list_folders(self, item_id: str = "root") -> dict[str, Any]:
200
192
  """
201
193
  Retrieves a list of only the folders within a specified parent directory in OneDrive. Unlike `_list_drive_items` which returns all items, this function filters the results to exclude files. Defaults to the root directory if no parent `item_id` is provided.
202
194
 
@@ -213,7 +205,7 @@ class OnedriveApp(APIApplication):
213
205
  folders = [item for item in all_items.get("value", []) if "folder" in item]
214
206
  return {"value": folders}
215
207
 
216
- def list_files(self, item_id: str = "root") -> dict[str, Any]:
208
+ async def list_files(self, item_id: str = "root") -> dict[str, Any]:
217
209
  """
218
210
  Retrieves a list of files within a specified OneDrive folder, defaulting to the root. Unlike `_list_drive_items` which fetches all items, this function filters the results to exclusively return items identified as files, excluding any subdirectories.
219
211
 
@@ -230,7 +222,7 @@ class OnedriveApp(APIApplication):
230
222
  files = [item for item in all_items.get("value", []) if "file" in item]
231
223
  return {"value": files}
232
224
 
233
- def create_folder_and_list(self, name: str, parent_id: str = "root") -> dict[str, Any]:
225
+ async def create_folder_and_list(self, name: str, parent_id: str = "root") -> dict[str, Any]:
234
226
  """
235
227
  Performs a composite action: creates a new folder, then lists all items (files and folders) within that parent directory. This confirms creation by returning the parent's updated contents, distinct from `create_folder` which only returns the new folder's metadata.
236
228
 
@@ -244,10 +236,10 @@ class OnedriveApp(APIApplication):
244
236
  Tags:
245
237
  create, folder, list, important
246
238
  """
247
- self.create_folder(name=name, parent_id=parent_id)
239
+ await self.create_folder(name=name, parent_id=parent_id)
248
240
  return self._list_drive_items(item_id=parent_id)
249
241
 
250
- def upload_text_file(self, content: str, parent_id: str = "root", file_name: str = "new_file.txt") -> dict[str, Any]:
242
+ async def upload_text_file(self, content: str, parent_id: str = "root", file_name: str = "new_file.txt") -> dict[str, Any]:
251
243
  """
252
244
  Creates and uploads a new file to OneDrive directly from a string of text content. Unlike `upload_file`, which requires a local file path, this function is specifically for creating a text file from in-memory string data, with a customizable name and destination folder.
253
245
 
@@ -264,13 +256,12 @@ class OnedriveApp(APIApplication):
264
256
  """
265
257
  if not file_name:
266
258
  raise ValueError("File name cannot be empty.")
267
-
268
259
  url = f"{self.base_url}/me/drive/items/{parent_id}:/{file_name}:/content"
269
260
  data = content.encode("utf-8")
270
- response = self._put(url, data=data, content_type="text/plain")
261
+ response = await self._aput(url, data=data, content_type="text/plain")
271
262
  return self._handle_response(response)
272
263
 
273
- def get_document_content(self, item_id: str) -> dict[str, Any]:
264
+ async def get_document_content(self, item_id: str) -> dict[str, Any]:
274
265
  """
275
266
  Retrieves the content of a specific file by its item ID and returns it directly as base64-encoded data. This function is distinct from `download_file`, which only provides a temporary URL for the content, and from `get_item_metadata`, which returns file attributes without the content itself. The function fetches the content by following the file's pre-authenticated download URL.
276
267
 
@@ -289,36 +280,23 @@ class OnedriveApp(APIApplication):
289
280
  """
290
281
  if not item_id:
291
282
  raise ValueError("Missing required parameter 'item_id'.")
292
-
293
- metadata = self.get_item_metadata(item_id=item_id)
283
+ metadata = await self.get_item_metadata(item_id=item_id)
294
284
  file_metadata = metadata.get("file")
295
285
  if not file_metadata:
296
286
  raise ValueError(f"Item with ID '{item_id}' is not a file.")
297
-
298
287
  file_mime_type = file_metadata.get("mimeType", "application/octet-stream")
299
288
  file_name = metadata.get("name")
300
-
301
289
  download_url = metadata.get("@microsoft.graph.downloadUrl")
302
290
  if not download_url:
303
291
  logger.error(f"Could not find @microsoft.graph.downloadUrl in metadata for item {item_id}")
304
292
  raise ValueError("Could not retrieve download URL for the item.")
305
-
306
- response = self._get(download_url)
307
-
293
+ response = await self._aget(download_url)
308
294
  response.raise_for_status()
309
-
310
295
  content = response.content
311
-
312
296
  attachment_type = file_mime_type.split("/")[0] if "/" in file_mime_type else "file"
313
297
  if attachment_type not in ["image", "audio", "video", "text"]:
314
298
  attachment_type = "file"
315
-
316
- return {
317
- "type": attachment_type,
318
- "data": content,
319
- "mime_type": file_mime_type,
320
- "file_name": file_name,
321
- }
299
+ return {"type": attachment_type, "data": content, "mime_type": file_mime_type, "file_name": file_name}
322
300
 
323
301
  def list_tools(self):
324
302
  return [