universal-mcp-applications 0.1.20__py3-none-any.whl → 0.1.22__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 (78) hide show
  1. universal_mcp/applications/BEST_PRACTICES.md +166 -0
  2. universal_mcp/applications/airtable/app.py +0 -1
  3. universal_mcp/applications/apollo/app.py +0 -1
  4. universal_mcp/applications/aws_s3/app.py +40 -39
  5. universal_mcp/applications/browser_use/README.md +1 -0
  6. universal_mcp/applications/browser_use/__init__.py +0 -0
  7. universal_mcp/applications/browser_use/app.py +76 -0
  8. universal_mcp/applications/calendly/app.py +125 -125
  9. universal_mcp/applications/canva/app.py +95 -99
  10. universal_mcp/applications/confluence/app.py +0 -1
  11. universal_mcp/applications/contentful/app.py +4 -5
  12. universal_mcp/applications/domain_checker/app.py +11 -15
  13. universal_mcp/applications/e2b/app.py +4 -4
  14. universal_mcp/applications/elevenlabs/app.py +18 -15
  15. universal_mcp/applications/exa/app.py +17 -17
  16. universal_mcp/applications/falai/app.py +28 -29
  17. universal_mcp/applications/file_system/app.py +9 -9
  18. universal_mcp/applications/firecrawl/app.py +36 -36
  19. universal_mcp/applications/fireflies/app.py +55 -56
  20. universal_mcp/applications/fpl/app.py +49 -50
  21. universal_mcp/applications/ghost_content/app.py +0 -1
  22. universal_mcp/applications/github/app.py +41 -43
  23. universal_mcp/applications/google_calendar/app.py +40 -39
  24. universal_mcp/applications/google_docs/app.py +56 -56
  25. universal_mcp/applications/google_drive/app.py +212 -215
  26. universal_mcp/applications/google_gemini/app.py +1 -5
  27. universal_mcp/applications/google_mail/app.py +91 -90
  28. universal_mcp/applications/google_searchconsole/app.py +29 -29
  29. universal_mcp/applications/google_sheet/app.py +115 -115
  30. universal_mcp/applications/hashnode/README.md +6 -3
  31. universal_mcp/applications/hashnode/app.py +174 -25
  32. universal_mcp/applications/http_tools/app.py +10 -11
  33. universal_mcp/applications/hubspot/__init__.py +1 -1
  34. universal_mcp/applications/hubspot/api_segments/api_segment_base.py +36 -7
  35. universal_mcp/applications/hubspot/api_segments/crm_api.py +368 -368
  36. universal_mcp/applications/hubspot/api_segments/marketing_api.py +115 -115
  37. universal_mcp/applications/hubspot/app.py +131 -72
  38. universal_mcp/applications/jira/app.py +0 -1
  39. universal_mcp/applications/linkedin/app.py +20 -20
  40. universal_mcp/applications/markitdown/app.py +10 -5
  41. universal_mcp/applications/ms_teams/app.py +123 -123
  42. universal_mcp/applications/openai/app.py +40 -39
  43. universal_mcp/applications/outlook/app.py +32 -32
  44. universal_mcp/applications/perplexity/app.py +4 -4
  45. universal_mcp/applications/reddit/app.py +69 -70
  46. universal_mcp/applications/resend/app.py +116 -117
  47. universal_mcp/applications/rocketlane/app.py +0 -1
  48. universal_mcp/applications/scraper/__init__.py +1 -1
  49. universal_mcp/applications/scraper/app.py +234 -16
  50. universal_mcp/applications/serpapi/app.py +14 -14
  51. universal_mcp/applications/sharepoint/app.py +19 -20
  52. universal_mcp/applications/shopify/app.py +0 -1
  53. universal_mcp/applications/slack/app.py +48 -48
  54. universal_mcp/applications/tavily/app.py +4 -4
  55. universal_mcp/applications/twitter/api_segments/compliance_api.py +13 -15
  56. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +20 -20
  57. universal_mcp/applications/twitter/api_segments/dm_events_api.py +12 -12
  58. universal_mcp/applications/twitter/api_segments/likes_api.py +12 -12
  59. universal_mcp/applications/twitter/api_segments/lists_api.py +37 -39
  60. universal_mcp/applications/twitter/api_segments/spaces_api.py +24 -24
  61. universal_mcp/applications/twitter/api_segments/trends_api.py +4 -4
  62. universal_mcp/applications/twitter/api_segments/tweets_api.py +105 -105
  63. universal_mcp/applications/twitter/api_segments/usage_api.py +4 -4
  64. universal_mcp/applications/twitter/api_segments/users_api.py +136 -136
  65. universal_mcp/applications/twitter/app.py +6 -2
  66. universal_mcp/applications/unipile/app.py +321 -71
  67. universal_mcp/applications/whatsapp/app.py +53 -54
  68. universal_mcp/applications/whatsapp/audio.py +39 -35
  69. universal_mcp/applications/whatsapp/whatsapp.py +176 -154
  70. universal_mcp/applications/whatsapp_business/app.py +92 -92
  71. universal_mcp/applications/yahoo_finance/app.py +105 -63
  72. universal_mcp/applications/youtube/app.py +206 -199
  73. universal_mcp/applications/zenquotes/__init__.py +2 -0
  74. universal_mcp/applications/zenquotes/app.py +3 -3
  75. {universal_mcp_applications-0.1.20.dist-info → universal_mcp_applications-0.1.22.dist-info}/METADATA +2 -1
  76. {universal_mcp_applications-0.1.20.dist-info → universal_mcp_applications-0.1.22.dist-info}/RECORD +78 -74
  77. {universal_mcp_applications-0.1.20.dist-info → universal_mcp_applications-0.1.22.dist-info}/WHEEL +0 -0
  78. {universal_mcp_applications-0.1.20.dist-info → universal_mcp_applications-0.1.22.dist-info}/licenses/LICENSE +0 -0
@@ -1,15 +1,14 @@
1
- import os
2
1
  from dotenv import load_dotenv
3
2
 
4
3
  load_dotenv()
5
4
 
6
5
  from typing import Any
7
6
 
7
+ from loguru import logger
8
8
  from universal_mcp.applications.application import APIApplication
9
- from universal_mcp.applications.unipile import UnipileApp
10
- from typing import Any, Optional
11
9
  from universal_mcp.integrations import Integration
12
- from loguru import logger
10
+
11
+ from universal_mcp.applications.unipile import UnipileApp
13
12
 
14
13
 
15
14
  class ScraperApp(APIApplication):
@@ -33,7 +32,7 @@ class ScraperApp(APIApplication):
33
32
  self.account_id = credentials.get("account_id")
34
33
  self._unipile_app = UnipileApp(integration=self.integration)
35
34
  else:
36
- logger.warning(f"Integration not found")
35
+ logger.warning("Integration not found")
37
36
  self.account_id = None
38
37
  self._unipile_app = None
39
38
 
@@ -41,12 +40,12 @@ class ScraperApp(APIApplication):
41
40
  self,
42
41
  category: str = "posts",
43
42
  api: str = "classic",
44
- cursor: Optional[str] = None,
45
- limit: Optional[int] = None,
46
- keywords: Optional[str] = None,
47
- sort_by: Optional[str] = None,
48
- date_posted: Optional[str] = None,
49
- content_type: Optional[str] = None,
43
+ cursor: str | None = None,
44
+ limit: int | None = None,
45
+ keywords: str | None = None,
46
+ sort_by: str | None = None,
47
+ date_posted: str | None = None,
48
+ content_type: str | None = None,
50
49
  ) -> dict[str, Any]:
51
50
  """
52
51
  Performs a general LinkedIn search for posts using keywords and filters like date and content type. It supports pagination and can utilize either the 'classic' or 'sales_navigator' API, searching broadly across the platform rather than fetching posts from a specific user's profile.
@@ -86,8 +85,8 @@ class ScraperApp(APIApplication):
86
85
  def linkedin_list_profile_posts(
87
86
  self,
88
87
  identifier: str,
89
- cursor: Optional[str] = None,
90
- limit: Optional[int] = None,
88
+ cursor: str | None = None,
89
+ limit: int | None = None,
91
90
  ) -> dict[str, Any]:
92
91
  """
93
92
  Fetches a paginated list of all LinkedIn posts from a specific user or company profile using their unique identifier. This function retrieves content directly from a profile, unlike `linkedin_post_search` which finds posts across LinkedIn based on keywords and other filters.
@@ -143,9 +142,9 @@ class ScraperApp(APIApplication):
143
142
  def linkedin_list_post_comments(
144
143
  self,
145
144
  post_id: str,
146
- comment_id: Optional[str] = None,
147
- cursor: Optional[str] = None,
148
- limit: Optional[int] = None,
145
+ comment_id: str | None = None,
146
+ cursor: str | None = None,
147
+ limit: int | None = None,
149
148
  ) -> dict[str, Any]:
150
149
  """
151
150
  Fetches comments for a specified LinkedIn post. If a `comment_id` is provided, it retrieves replies to that comment instead of top-level comments. This function supports pagination and specifically targets comments, unlike others in the class that search for or list entire posts.
@@ -174,6 +173,223 @@ class ScraperApp(APIApplication):
174
173
  limit=limit,
175
174
  )
176
175
 
176
+ def linkedin_people_search(
177
+ self,
178
+ cursor: str | None = None,
179
+ limit: int | None = None,
180
+ keywords: str | None = None,
181
+ last_viewed_at: int | None = None,
182
+ saved_search_id: str | None = None,
183
+ recent_search_id: str | None = None,
184
+ location: dict[str, Any] | None = None,
185
+ location_by_postal_code: dict[str, Any] | None = None,
186
+ industry: dict[str, Any] | None = None,
187
+ first_name: str | None = None,
188
+ last_name: str | None = None,
189
+ tenure: list[dict[str, Any]] | None = None,
190
+ groups: list[str] | None = None,
191
+ school: dict[str, Any] | None = None,
192
+ profile_language: list[str] | None = None,
193
+ company: dict[str, Any] | None = None,
194
+ company_headcount: list[dict[str, Any]] | None = None,
195
+ company_type: list[str] | None = None,
196
+ company_location: dict[str, Any] | None = None,
197
+ tenure_at_company: list[dict[str, Any]] | None = None,
198
+ past_company: dict[str, Any] | None = None,
199
+ function: dict[str, Any] | None = None,
200
+ role: dict[str, Any] | None = None,
201
+ tenure_at_role: list[dict[str, Any]] | None = None,
202
+ seniority: dict[str, Any] | None = None,
203
+ past_role: dict[str, Any] | None = None,
204
+ following_your_company: bool | None = None,
205
+ viewed_your_profile_recently: bool | None = None,
206
+ network_distance: list[str] | None = None,
207
+ connections_of: list[str] | None = None,
208
+ past_colleague: bool | None = None,
209
+ shared_experiences: bool | None = None,
210
+ changed_jobs: bool | None = None,
211
+ posted_on_linkedin: bool | None = None,
212
+ mentionned_in_news: bool | None = None,
213
+ persona: list[str] | None = None,
214
+ account_lists: dict[str, Any] | None = None,
215
+ lead_lists: dict[str, Any] | None = None,
216
+ viewed_profile_recently: bool | None = None,
217
+ messaged_recently: bool | None = None,
218
+ include_saved_leads: bool | None = None,
219
+ include_saved_accounts: bool | None = None,
220
+ ) -> dict[str, Any]:
221
+ """
222
+ Performs a comprehensive LinkedIn Sales Navigator people search with advanced targeting options.
223
+ This function provides access to LinkedIn's Sales Navigator search capabilities for finding people
224
+ with precise filters including experience, company details, education, and relationship criteria.
225
+
226
+ Args:
227
+ cursor: Pagination cursor for the next page of entries.
228
+ limit: Number of items to return.
229
+ keywords: LinkedIn native filter: KEYWORDS.
230
+ last_viewed_at: Unix timestamp for saved search filtering.
231
+ saved_search_id: ID of saved search (overrides other parameters).
232
+ recent_search_id: ID of recent search (overrides other parameters).
233
+ location: LinkedIn native filter: GEOGRAPHY. Example: {"include": ["San Francisco Bay Area", "New York City Area"]}
234
+ location_by_postal_code: Location filter by postal code. Example: {"postal_code": "94105", "radius": "25"}
235
+ industry: LinkedIn native filter: INDUSTRY. Example: {"include": ["Information Technology and Services", "Financial Services"]}
236
+ first_name: LinkedIn native filter: FIRST NAME. Example: "John"
237
+ last_name: LinkedIn native filter: LAST NAME. Example: "Smith"
238
+ tenure: LinkedIn native filter: YEARS OF EXPERIENCE. Example: [{"min": 5, "max": 10}]
239
+ groups: LinkedIn native filter: GROUPS. Example: ["group_id_1", "group_id_2"]
240
+ school: LinkedIn native filter: SCHOOL. Example: {"include": ["Stanford University", "Harvard University"]}
241
+ profile_language: ISO 639-1 language codes, LinkedIn native filter: PROFILE LANGUAGE. Example: ["en", "es"]
242
+ company: LinkedIn native filter: CURRENT COMPANY. Example: {"include": ["Google", "Microsoft", "Apple"]}
243
+ company_headcount: LinkedIn native filter: COMPANY HEADCOUNT. Example: [{"min": 100, "max": 1000}]
244
+ company_type: LinkedIn native filter: COMPANY TYPE. Example: ["Public Company", "Privately Held"]
245
+ company_location: LinkedIn native filter: COMPANY HEADQUARTERS LOCATION. Example: {"include": ["San Francisco", "Seattle"]}
246
+ tenure_at_company: LinkedIn native filter: YEARS IN CURRENT COMPANY. Example: [{"min": 2, "max": 5}]
247
+ past_company: LinkedIn native filter: PAST COMPANY. Example: {"include": ["Facebook", "Amazon"]}
248
+ function: LinkedIn native filter: FUNCTION. Example: {"include": ["Engineering", "Sales", "Marketing"]}
249
+ role: LinkedIn native filter: CURRENT JOB TITLE. Example: {"include": ["Software Engineer", "Product Manager"]}
250
+ tenure_at_role: LinkedIn native filter: YEARS IN CURRENT POSITION. Example: [{"min": 1, "max": 3}]
251
+ seniority: LinkedIn native filter: SENIORITY LEVEL. Example: {"include": ["Senior", "Director", "VP"]}
252
+ past_role: LinkedIn native filter: PAST JOB TITLE. Example: {"include": ["Senior Developer", "Team Lead"]}
253
+ following_your_company: LinkedIn native filter: FOLLOWING YOUR COMPANY. Example: True
254
+ viewed_your_profile_recently: LinkedIn native filter: VIEWED YOUR PROFILE RECENTLY. Example: True
255
+ network_distance: First, second, third+ degree or GROUP, LinkedIn native filter: CONNECTION. Example: ["1st", "2nd"]
256
+ connections_of: LinkedIn native filter: CONNECTIONS OF. Example: ["person_id_1", "person_id_2"]
257
+ past_colleague: LinkedIn native filter: PAST COLLEAGUE. Example: True
258
+ shared_experiences: LinkedIn native filter: SHARED EXPERIENCES. Example: True
259
+ changed_jobs: LinkedIn native filter: CHANGED JOBS. Example: True
260
+ posted_on_linkedin: LinkedIn native filter: POSTED ON LINKEDIN. Example: True
261
+ mentionned_in_news: LinkedIn native filter: MENTIONNED IN NEWS. Example: True
262
+ persona: LinkedIn native filter: PERSONA. Example: ["persona_id_1", "persona_id_2"]
263
+ account_lists: LinkedIn native filter: ACCOUNT LISTS. Example: {"include": ["list_id_1"]}
264
+ lead_lists: LinkedIn native filter: LEAD LISTS. Example: {"include": ["lead_list_id_1"]}
265
+ viewed_profile_recently: LinkedIn native filter: PEOPLE YOU INTERACTED WITH / VIEWED PROFILE. Example: True
266
+ messaged_recently: LinkedIn native filter: PEOPLE YOU INTERACTED WITH / MESSAGED. Example: True
267
+ include_saved_leads: LinkedIn native filter: SAVED LEADS AND ACCOUNTS / ALL MY SAVED LEADS. Example: True
268
+ include_saved_accounts: LinkedIn native filter: SAVED LEADS AND ACCOUNTS / ALL MY SAVED ACCOUNTS. Example: True
269
+
270
+ Returns:
271
+ A dictionary containing search results and pagination details.
272
+
273
+ Raises:
274
+ httpx.HTTPError: If the API request fails.
275
+
276
+ Tags:
277
+ linkedin, sales_navigator, people, search, advanced, scraper, api, important
278
+ """
279
+ return self._unipile_app.people_search(
280
+ account_id=self.account_id,
281
+ cursor=cursor,
282
+ limit=limit,
283
+ keywords=keywords,
284
+ last_viewed_at=last_viewed_at,
285
+ saved_search_id=saved_search_id,
286
+ recent_search_id=recent_search_id,
287
+ location=location,
288
+ location_by_postal_code=location_by_postal_code,
289
+ industry=industry,
290
+ first_name=first_name,
291
+ last_name=last_name,
292
+ tenure=tenure,
293
+ groups=groups,
294
+ school=school,
295
+ profile_language=profile_language,
296
+ company=company,
297
+ company_headcount=company_headcount,
298
+ company_type=company_type,
299
+ company_location=company_location,
300
+ tenure_at_company=tenure_at_company,
301
+ past_company=past_company,
302
+ function=function,
303
+ role=role,
304
+ tenure_at_role=tenure_at_role,
305
+ seniority=seniority,
306
+ past_role=past_role,
307
+ following_your_company=following_your_company,
308
+ viewed_your_profile_recently=viewed_your_profile_recently,
309
+ network_distance=network_distance,
310
+ connections_of=connections_of,
311
+ past_colleague=past_colleague,
312
+ shared_experiences=shared_experiences,
313
+ changed_jobs=changed_jobs,
314
+ posted_on_linkedin=posted_on_linkedin,
315
+ mentionned_in_news=mentionned_in_news,
316
+ persona=persona,
317
+ account_lists=account_lists,
318
+ lead_lists=lead_lists,
319
+ viewed_profile_recently=viewed_profile_recently,
320
+ messaged_recently=messaged_recently,
321
+ include_saved_leads=include_saved_leads,
322
+ include_saved_accounts=include_saved_accounts,
323
+ )
324
+
325
+ def linkedin_company_search(
326
+ self,
327
+ cursor: str | None = None,
328
+ limit: int | None = None,
329
+ keywords: str | None = None,
330
+ last_viewed_at: int | None = None,
331
+ saved_search_id: str | None = None,
332
+ recent_search_id: str | None = None,
333
+ location: dict[str, Any] | None = None,
334
+ location_by_postal_code: dict[str, Any] | None = None,
335
+ industry: dict[str, Any] | None = None,
336
+ company_headcount: list[dict[str, Any]] | None = None,
337
+ company_type: list[str] | None = None,
338
+ company_location: dict[str, Any] | None = None,
339
+ following_your_company: bool | None = None,
340
+ account_lists: dict[str, Any] | None = None,
341
+ include_saved_accounts: bool | None = None,
342
+ ) -> dict[str, Any]:
343
+ """
344
+ Performs a comprehensive LinkedIn Sales Navigator company search with advanced targeting options.
345
+ This function provides access to LinkedIn's Sales Navigator search capabilities for finding companies
346
+ with precise filters including size, location, industry, and relationship criteria.
347
+
348
+ Args:
349
+ cursor: Pagination cursor for the next page of entries.
350
+ limit: Number of items to return.
351
+ keywords: LinkedIn native filter: KEYWORDS. Example: "fintech startup"
352
+ last_viewed_at: Unix timestamp for saved search filtering.
353
+ saved_search_id: ID of saved search (overrides other parameters).
354
+ recent_search_id: ID of recent search (overrides other parameters).
355
+ location: LinkedIn native filter: GEOGRAPHY. Example: {"include": ["San Francisco Bay Area", "New York City Area"]}
356
+ location_by_postal_code: Location filter by postal code. Example: {"postal_code": "94105", "radius": "25"}
357
+ industry: LinkedIn native filter: INDUSTRY. Example: {"include": ["Information Technology and Services", "Financial Services"]}
358
+ company_headcount: LinkedIn native filter: COMPANY HEADCOUNT. Example: [{"min": 10, "max": 100}]
359
+ company_type: LinkedIn native filter: COMPANY TYPE. Example: ["Public Company", "Privately Held", "Startup"]
360
+ company_location: LinkedIn native filter: COMPANY HEADQUARTERS LOCATION. Example: {"include": ["San Francisco", "Seattle", "Austin"]}
361
+ following_your_company: LinkedIn native filter: FOLLOWING YOUR COMPANY. Example: True
362
+ account_lists: LinkedIn native filter: ACCOUNT LISTS. Example: {"include": ["account_list_id_1"]}
363
+ include_saved_accounts: LinkedIn native filter: SAVED LEADS AND ACCOUNTS / ALL MY SAVED ACCOUNTS. Example: True
364
+
365
+ Returns:
366
+ A dictionary containing search results and pagination details.
367
+
368
+ Raises:
369
+ httpx.HTTPError: If the API request fails.
370
+
371
+ Tags:
372
+ linkedin, sales_navigator, companies, search, advanced, scraper, api, important
373
+ """
374
+ return self._unipile_app.company_search(
375
+ account_id=self.account_id,
376
+ cursor=cursor,
377
+ limit=limit,
378
+ keywords=keywords,
379
+ last_viewed_at=last_viewed_at,
380
+ saved_search_id=saved_search_id,
381
+ recent_search_id=recent_search_id,
382
+ location=location,
383
+ location_by_postal_code=location_by_postal_code,
384
+ industry=industry,
385
+ company_headcount=company_headcount,
386
+ company_type=company_type,
387
+ company_location=company_location,
388
+ following_your_company=following_your_company,
389
+ account_lists=account_lists,
390
+ include_saved_accounts=include_saved_accounts,
391
+ )
392
+
177
393
  def list_tools(self):
178
394
  """
179
395
  Returns a list of available tools/functions in this application.
@@ -186,4 +402,6 @@ class ScraperApp(APIApplication):
186
402
  self.linkedin_list_profile_posts,
187
403
  self.linkedin_retrieve_profile,
188
404
  self.linkedin_list_post_comments,
405
+ self.linkedin_people_search,
406
+ self.linkedin_company_search,
189
407
  ]
@@ -2,12 +2,12 @@ from typing import Any # For type hinting
2
2
 
3
3
  import httpx
4
4
  from loguru import logger
5
-
6
- from serpapi import SerpApiClient as SerpApiSearch # Added SerpApiError
7
5
  from universal_mcp.applications.application import APIApplication
8
6
  from universal_mcp.exceptions import NotAuthorizedError # For auth errors
9
7
  from universal_mcp.integrations import Integration # For integration type hint
10
8
 
9
+ from serpapi import SerpApiClient as SerpApiSearch # Added SerpApiError
10
+
11
11
 
12
12
  class SerpapiApp(APIApplication):
13
13
  def __init__(self, integration: Integration | None = None, **kwargs: Any) -> None:
@@ -78,17 +78,17 @@ class SerpapiApp(APIApplication):
78
78
  async def web_search(self, params: dict[str, Any] | None = None) -> str:
79
79
  """
80
80
  Performs a general web search via SerpApi, defaulting to the 'google_light' engine. It accepts custom parameters, retrieves organic results, and formats them into a string with titles, links, and snippets. It also handles API authentication and raises `NotAuthorizedError` for credential-related issues.
81
-
81
+
82
82
  Args:
83
83
  params: Dictionary of engine-specific parameters (e.g., {'q': 'Coffee', 'engine': 'google_light', 'location': 'Austin, TX'}). Defaults to None.
84
-
84
+
85
85
  Returns:
86
86
  A formatted string containing search results with titles, links, and snippets, or an error message if the search fails.
87
-
87
+
88
88
  Raises:
89
89
  NotAuthorizedError: If the API key cannot be retrieved or is invalid/rejected by SerpApi.
90
90
  Exception: For other unexpected errors during the search process. (Specific HTTP errors or SerpApiErrors are caught and returned as strings or raise NotAuthorizedError).
91
-
91
+
92
92
  Tags:
93
93
  search, async, web-scraping, api, serpapi, important
94
94
  """
@@ -194,19 +194,19 @@ class SerpapiApp(APIApplication):
194
194
  ) -> dict[str, Any]:
195
195
  """
196
196
  Executes a Google Maps search via SerpApi using a query, coordinates, or place ID. It enhances the results by adding a `google_maps_url` to each location, distinguishing it from `get_google_maps_reviews` which retrieves reviews for a known place.
197
-
197
+
198
198
  Args:
199
199
  q (string, optional): The search query for Google Maps (e.g., "Coffee", "Restaurants", "Gas stations").
200
200
  ll (string, optional): Latitude and longitude with zoom level in format "@lat,lng,zoom" (e.g., "@40.7455096,-74.0083012,14z"). The zoom attribute ranges from 3z (map completely zoomed out) to 21z (map completely zoomed in). Results are not guaranteed to be within the requested geographic location.
201
201
  place_id (string, optional): The unique reference to a place in Google Maps. Place IDs are available for most locations, including businesses, landmarks, parks, and intersections. You can find the place_id using our Google Maps API. place_id can be used without any other optional parameter. place_id and data_cid can't be used together.
202
-
202
+
203
203
  Returns:
204
204
  dict[str, Any]: Formatted Google Maps search results with place names, addresses, ratings, and other details.
205
-
205
+
206
206
  Raises:
207
207
  ValueError: Raised when required parameters are missing.
208
208
  HTTPStatusError: Raised when the API request fails with detailed error information including status code and response body.
209
-
209
+
210
210
  Tags:
211
211
  google-maps, search, location, places, important
212
212
  """
@@ -249,18 +249,18 @@ class SerpapiApp(APIApplication):
249
249
  ) -> dict[str, Any]:
250
250
  """
251
251
  Fetches Google Maps reviews for a specific location via SerpApi using its unique `data_id`. This function uses the `google_maps_reviews` engine, unlike `google_maps_search` which finds locations. Results can be returned in a specified language, defaulting to English.
252
-
252
+
253
253
  Args:
254
254
  data_id (string): The data ID of the place to get reviews for (e.g., "0x89c259af336b3341:0xa4969e07ce3108de").
255
255
  hl (string, optional): Language parameter for the search results. Defaults to "en".
256
-
256
+
257
257
  Returns:
258
258
  dict[str, Any]: Google Maps reviews data with ratings, comments, and other review details.
259
-
259
+
260
260
  Raises:
261
261
  ValueError: Raised when required parameters are missing.
262
262
  HTTPStatusError: Raised when the API request fails with detailed error information including status code and response body.
263
-
263
+
264
264
  Tags:
265
265
  google-maps, reviews, ratings, places, important
266
266
  """
@@ -6,7 +6,6 @@ from typing import Any
6
6
 
7
7
  from loguru import logger
8
8
  from office365.graph_client import GraphClient
9
-
10
9
  from universal_mcp.applications.application import BaseApplication
11
10
  from universal_mcp.integrations import Integration
12
11
 
@@ -37,7 +36,7 @@ class SharepointApp(BaseApplication):
37
36
  def client(self):
38
37
  """
39
38
  A lazy-loaded property that gets or creates an authenticated GraphClient instance. On first access, it uses integration credentials to initialize the client, fetches initial user and site data, and caches the instance for subsequent use, ensuring efficient connection management for all SharePoint operations.
40
-
39
+
41
40
  Returns:
42
41
  GraphClient: The authenticated GraphClient instance.
43
42
  """
@@ -75,13 +74,13 @@ class SharepointApp(BaseApplication):
75
74
  def list_folders(self, folder_path: str | None = None) -> list[dict[str, Any]]:
76
75
  """
77
76
  Retrieves a list of immediate subfolder names within a specified SharePoint directory. If no path is provided, it defaults to the root drive. This function is distinct from `list_files`, as it exclusively lists directories, not files.
78
-
77
+
79
78
  Args:
80
79
  folder_path (Optional[str], optional): The path to the parent folder. If None, lists folders in the root.
81
-
80
+
82
81
  Returns:
83
82
  List[Dict[str, Any]]: A list of folder names in the specified directory.
84
-
83
+
85
84
  Tags:
86
85
  important
87
86
  """
@@ -98,14 +97,14 @@ class SharepointApp(BaseApplication):
98
97
  ) -> dict[str, Any]:
99
98
  """
100
99
  Creates a new folder with a given name inside a specified parent directory (or the root). It then returns an updated list of all folder names within that same directory, effectively confirming that the creation operation was successful.
101
-
100
+
102
101
  Args:
103
102
  folder_name (str): The name of the folder to create.
104
103
  folder_path (str | None, optional): The path to the parent folder. If None, creates in the root.
105
-
104
+
106
105
  Returns:
107
106
  Dict[str, Any]: The updated list of folders in the target directory.
108
-
107
+
109
108
  Tags:
110
109
  important
111
110
  """
@@ -119,13 +118,13 @@ class SharepointApp(BaseApplication):
119
118
  def list_files(self, folder_path: str) -> list[dict[str, Any]]:
120
119
  """
121
120
  Retrieves metadata for all files in a specified folder. For each file, it returns key details like name, URL, size, and timestamps. This function exclusively lists file properties, distinguishing it from `list_folders` (which lists directories) and `get_document_content` (which retrieves file content).
122
-
121
+
123
122
  Args:
124
123
  folder_path (str): The path to the folder whose documents are to be listed.
125
-
124
+
126
125
  Returns:
127
126
  List[Dict[str, Any]]: A list of dictionaries containing document metadata.
128
-
127
+
129
128
  Tags:
130
129
  important
131
130
  """
@@ -148,15 +147,15 @@ class SharepointApp(BaseApplication):
148
147
  ) -> dict[str, Any]:
149
148
  """
150
149
  Uploads string content to create a new file in a specified SharePoint folder. To confirm the operation, it returns an updated list of all files and their metadata from that directory, including the newly created file.
151
-
150
+
152
151
  Args:
153
152
  file_path (str): The path to the folder where the document will be created.
154
153
  file_name (str): The name of the document to create.
155
154
  content (str): The content to write into the document.
156
-
155
+
157
156
  Returns:
158
157
  Dict[str, Any]: The updated list of documents in the folder.
159
-
158
+
160
159
  Tags: important
161
160
  """
162
161
  file = self.client.me.drive.root.get_by_path(file_path)
@@ -168,13 +167,13 @@ class SharepointApp(BaseApplication):
168
167
  def get_document_content(self, file_path: str) -> dict[str, Any]:
169
168
  """
170
169
  Retrieves a file's content from a specified SharePoint path. It returns a dictionary containing the file's name and size, decoding text files as a string and Base64-encoding binary files. Unlike `list_files`, which only fetches metadata, this function provides the actual file content.
171
-
170
+
172
171
  Args:
173
172
  file_path (str): The path to the document.
174
-
173
+
175
174
  Returns:
176
175
  Dict[str, Any]: A dictionary containing the document's name, content type, content (as text or base64), and size.
177
-
176
+
178
177
  Tags: important
179
178
  """
180
179
  file = self.client.me.drive.root.get_by_path(file_path).get().execute_query()
@@ -201,13 +200,13 @@ class SharepointApp(BaseApplication):
201
200
  def delete_document(self, file_path: str):
202
201
  """
203
202
  Permanently deletes a specified file from a SharePoint drive using its full path. This is the sole destructive file operation, contrasting with functions that read or create files. It returns `True` on successful deletion and raises an exception on failure, such as if the file is not found.
204
-
203
+
205
204
  Args:
206
205
  file_path (str): The path to the file to delete.
207
-
206
+
208
207
  Returns:
209
208
  bool: True if the file was deleted successfully.
210
-
209
+
211
210
  Tags:
212
211
  important
213
212
  """
@@ -1,7 +1,6 @@
1
1
  from typing import Any
2
2
 
3
3
  from loguru import logger
4
-
5
4
  from universal_mcp.applications.application import APIApplication
6
5
  from universal_mcp.integrations import Integration
7
6