universal-mcp 0.1.7rc1__py3-none-any.whl → 0.1.8__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 (61) hide show
  1. universal_mcp/__init__.py +0 -2
  2. universal_mcp/analytics.py +75 -0
  3. universal_mcp/applications/ahrefs/README.md +76 -0
  4. universal_mcp/applications/ahrefs/app.py +2291 -0
  5. universal_mcp/applications/application.py +95 -5
  6. universal_mcp/applications/calendly/README.md +78 -0
  7. universal_mcp/applications/calendly/__init__.py +0 -0
  8. universal_mcp/applications/calendly/app.py +1195 -0
  9. universal_mcp/applications/coda/README.md +133 -0
  10. universal_mcp/applications/coda/__init__.py +0 -0
  11. universal_mcp/applications/coda/app.py +3671 -0
  12. universal_mcp/applications/e2b/app.py +14 -28
  13. universal_mcp/applications/figma/README.md +74 -0
  14. universal_mcp/applications/figma/__init__.py +0 -0
  15. universal_mcp/applications/figma/app.py +1261 -0
  16. universal_mcp/applications/firecrawl/app.py +38 -35
  17. universal_mcp/applications/github/app.py +127 -85
  18. universal_mcp/applications/google_calendar/app.py +62 -138
  19. universal_mcp/applications/google_docs/app.py +47 -52
  20. universal_mcp/applications/google_drive/app.py +119 -113
  21. universal_mcp/applications/google_mail/app.py +124 -50
  22. universal_mcp/applications/google_sheet/app.py +89 -91
  23. universal_mcp/applications/markitdown/app.py +9 -8
  24. universal_mcp/applications/notion/app.py +254 -134
  25. universal_mcp/applications/perplexity/app.py +13 -41
  26. universal_mcp/applications/reddit/app.py +94 -85
  27. universal_mcp/applications/resend/app.py +12 -13
  28. universal_mcp/applications/{serp → serpapi}/app.py +14 -25
  29. universal_mcp/applications/tavily/app.py +11 -18
  30. universal_mcp/applications/wrike/README.md +71 -0
  31. universal_mcp/applications/wrike/__init__.py +0 -0
  32. universal_mcp/applications/wrike/app.py +1372 -0
  33. universal_mcp/applications/youtube/README.md +82 -0
  34. universal_mcp/applications/youtube/__init__.py +0 -0
  35. universal_mcp/applications/youtube/app.py +1428 -0
  36. universal_mcp/applications/zenquotes/app.py +12 -2
  37. universal_mcp/exceptions.py +9 -2
  38. universal_mcp/integrations/__init__.py +24 -1
  39. universal_mcp/integrations/agentr.py +27 -4
  40. universal_mcp/integrations/integration.py +146 -32
  41. universal_mcp/logger.py +3 -56
  42. universal_mcp/servers/__init__.py +6 -14
  43. universal_mcp/servers/server.py +201 -146
  44. universal_mcp/stores/__init__.py +7 -2
  45. universal_mcp/stores/store.py +103 -40
  46. universal_mcp/tools/__init__.py +3 -0
  47. universal_mcp/tools/adapters.py +43 -0
  48. universal_mcp/tools/func_metadata.py +213 -0
  49. universal_mcp/tools/tools.py +342 -0
  50. universal_mcp/utils/docgen.py +325 -119
  51. universal_mcp/utils/docstring_parser.py +179 -0
  52. universal_mcp/utils/dump_app_tools.py +33 -23
  53. universal_mcp/utils/installation.py +201 -10
  54. universal_mcp/utils/openapi.py +229 -46
  55. {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.8.dist-info}/METADATA +9 -5
  56. universal_mcp-0.1.8.dist-info/RECORD +81 -0
  57. universal_mcp-0.1.7rc1.dist-info/RECORD +0 -58
  58. /universal_mcp/{utils/bridge.py → applications/ahrefs/__init__.py} +0 -0
  59. /universal_mcp/applications/{serp → serpapi}/README.md +0 -0
  60. {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.8.dist-info}/WHEEL +0 -0
  61. {universal_mcp-0.1.7rc1.dist-info → universal_mcp-0.1.8.dist-info}/entry_points.txt +0 -0
@@ -11,17 +11,6 @@ class GoogleCalendarApp(APIApplication):
11
11
  super().__init__(name="google-calendar", integration=integration)
12
12
  self.base_api_url = "https://www.googleapis.com/calendar/v3/calendars/primary"
13
13
 
14
- def _get_headers(self):
15
- if not self.integration:
16
- raise ValueError("Integration not configured for GoogleCalendarApp")
17
- credentials = self.integration.get_credentials()
18
- if "headers" in credentials:
19
- return credentials["headers"]
20
- return {
21
- "Authorization": f"Bearer {credentials['access_token']}",
22
- "Accept": "application/json",
23
- }
24
-
25
14
  def _format_datetime(self, dt_string: str) -> str:
26
15
  """Format a datetime string from ISO format to a human-readable format.
27
16
 
@@ -59,7 +48,8 @@ class GoogleCalendarApp(APIApplication):
59
48
  def get_today_events(
60
49
  self, days: int = 1, max_results: int = None, time_zone: str = None
61
50
  ) -> str:
62
- """Get events from your Google Calendar for today or a specified number of days
51
+ """
52
+ Retrieves and formats events from Google Calendar for today or a specified number of future days, with optional result limiting and timezone specification.
63
53
 
64
54
  Args:
65
55
  days: Number of days to retrieve events for (default: 1, which is just today)
@@ -67,42 +57,36 @@ class GoogleCalendarApp(APIApplication):
67
57
  time_zone: Time zone used in the response (optional, default is calendar's time zone)
68
58
 
69
59
  Returns:
70
- A formatted list of events or an error message
60
+ A formatted string containing a list of calendar events with their times and IDs, or a message indicating no events were found
61
+
62
+ Raises:
63
+ HTTPError: Raised when the API request fails or returns an error status code
64
+
65
+ Tags:
66
+ fetch, list, calendar, events, date-time, important, api, formatting
71
67
  """
72
- # Get today's date in ISO format
73
68
  today = datetime.utcnow().date()
74
69
  end_date = today + timedelta(days=days)
75
-
76
- # Format dates for API
77
70
  time_min = f"{today.isoformat()}T00:00:00Z"
78
71
  time_max = f"{end_date.isoformat()}T00:00:00Z"
79
-
80
72
  url = f"{self.base_api_url}/events"
81
-
82
- # Build query parameters
83
73
  params = {
84
74
  "timeMin": time_min,
85
75
  "timeMax": time_max,
86
76
  "singleEvents": "true",
87
77
  "orderBy": "startTime",
88
78
  }
89
-
90
79
  if max_results is not None:
91
80
  params["maxResults"] = max_results
92
-
93
81
  if time_zone:
94
82
  params["timeZone"] = time_zone
95
-
96
83
  date_range = "today" if days == 1 else f"the next {days} days"
97
84
  logger.info(f"Retrieving calendar events for {date_range}")
98
-
99
85
  response = self._get(url, params=params)
100
86
  response.raise_for_status()
101
-
102
87
  events = response.json().get("items", [])
103
88
  if not events:
104
89
  return f"No events scheduled for {date_range}."
105
-
106
90
  result = f"Events for {date_range}:\n\n"
107
91
  for event in events:
108
92
  # Extract event date and time
@@ -137,62 +121,51 @@ class GoogleCalendarApp(APIApplication):
137
121
  event_id = event.get("id", "No ID")
138
122
 
139
123
  result += f"- {time_display}: {summary} (ID: {event_id})\n"
140
-
141
124
  return result
142
125
 
143
126
  def get_event(
144
127
  self, event_id: str, max_attendees: int = None, time_zone: str = None
145
128
  ) -> str:
146
- """Get a specific event from your Google Calendar by ID
129
+ """
130
+ Retrieves and formats detailed information about a specific Google Calendar event by its ID
147
131
 
148
132
  Args:
149
- event_id: The ID of the event to retrieve
150
- max_attendees: Optional. The maximum number of attendees to include in the response
151
- time_zone: Optional. Time zone used in the response (default is calendar's time zone)
133
+ event_id: The unique identifier of the calendar event to retrieve
134
+ max_attendees: Optional. The maximum number of attendees to include in the response. If None, includes all attendees
135
+ time_zone: Optional. The time zone to use for formatting dates in the response. If None, uses the calendar's default time zone
152
136
 
153
137
  Returns:
154
- A formatted event details or an error message
138
+ A formatted string containing comprehensive event details including summary, time, location, description, creator, organizer, recurrence status, and attendee information
139
+
140
+ Raises:
141
+ HTTPError: Raised when the API request fails or returns an error status code
142
+ JSONDecodeError: Raised when the API response cannot be parsed as JSON
143
+
144
+ Tags:
145
+ retrieve, calendar, event, format, api, important
155
146
  """
156
147
  url = f"{self.base_api_url}/events/{event_id}"
157
-
158
- # Build query parameters
159
148
  params = {}
160
149
  if max_attendees is not None:
161
150
  params["maxAttendees"] = max_attendees
162
151
  if time_zone:
163
152
  params["timeZone"] = time_zone
164
-
165
153
  logger.info(f"Retrieving calendar event with ID: {event_id}")
166
-
167
154
  response = self._get(url, params=params)
168
155
  response.raise_for_status()
169
-
170
156
  event = response.json()
171
-
172
- # Extract event details
173
157
  summary = event.get("summary", "Untitled event")
174
158
  description = event.get("description", "No description")
175
159
  location = event.get("location", "No location specified")
176
-
177
- # Format dates
178
160
  start = event.get("start", {})
179
161
  end = event.get("end", {})
180
-
181
162
  start_time = start.get("dateTime", start.get("date", "Unknown"))
182
163
  end_time = end.get("dateTime", end.get("date", "Unknown"))
183
-
184
- # Format datetimes using the helper function
185
164
  start_formatted = self._format_datetime(start_time)
186
165
  end_formatted = self._format_datetime(end_time)
187
-
188
- # Get creator and organizer
189
166
  creator = event.get("creator", {}).get("email", "Unknown")
190
167
  organizer = event.get("organizer", {}).get("email", "Unknown")
191
-
192
- # Check if it's a recurring event
193
168
  recurrence = "Yes" if "recurrence" in event else "No"
194
-
195
- # Get attendees if any
196
169
  attendees = event.get("attendees", [])
197
170
  attendee_info = ""
198
171
  if attendees:
@@ -211,8 +184,6 @@ class GoogleCalendarApp(APIApplication):
211
184
 
212
185
  formatted_status = status_mapping.get(response_status, response_status)
213
186
  attendee_info += f" {i}. {name} ({email}) - {formatted_status}\n"
214
-
215
- # Format the response
216
187
  result = f"Event: {summary}\n"
217
188
  result += f"ID: {event_id}\n"
218
189
  result += f"When: {start_formatted} to {end_formatted}\n"
@@ -222,7 +193,6 @@ class GoogleCalendarApp(APIApplication):
222
193
  result += f"Organizer: {organizer}\n"
223
194
  result += f"Recurring: {recurrence}\n"
224
195
  result += attendee_info
225
-
226
196
  return result
227
197
 
228
198
  def list_events(
@@ -236,69 +206,58 @@ class GoogleCalendarApp(APIApplication):
236
206
  time_zone: str = None,
237
207
  page_token: str = None,
238
208
  ) -> str:
239
- """List events from your Google Calendar with various filtering options
209
+ """
210
+ Retrieves and formats a list of events from Google Calendar with customizable filtering, sorting, and pagination options
240
211
 
241
212
  Args:
242
213
  max_results: Maximum number of events to return (default: 10, max: 2500)
243
- time_min: Start time (ISO format, e.g. '2023-12-01T00:00:00Z') - defaults to now if not specified
244
- time_max: End time (ISO format, e.g. '2023-12-31T23:59:59Z')
245
- q: Free text search terms (searches summary, description, location, attendees, etc.)
246
- order_by: How to order results - 'startTime' (default) or 'updated'
247
- single_events: Whether to expand recurring events (default: True)
248
- time_zone: Time zone used in the response (default is calendar's time zone)
249
- page_token: Token for retrieving a specific page of results
214
+ time_min: Start time in ISO format (e.g., '2023-12-01T00:00:00Z'). Defaults to current time if not specified
215
+ time_max: End time in ISO format (e.g., '2023-12-31T23:59:59Z')
216
+ q: Free text search terms to filter events (searches across summary, description, location, attendees)
217
+ order_by: Sort order for results - either 'startTime' (default) or 'updated'
218
+ single_events: Whether to expand recurring events into individual instances (default: True)
219
+ time_zone: Time zone for response formatting (defaults to calendar's time zone)
220
+ page_token: Token for retrieving a specific page of results in paginated responses
250
221
 
251
222
  Returns:
252
- A formatted list of events or an error message
223
+ A formatted string containing the list of events with details including summary, ID, start time, and location, or a message if no events are found
224
+
225
+ Raises:
226
+ HTTPError: Raised when the API request fails or returns an error status code
227
+
228
+ Tags:
229
+ list, calendar, events, search, filter, pagination, format, important
253
230
  """
254
231
  url = f"{self.base_api_url}/events"
255
-
256
- # Build query parameters
257
232
  params = {
258
233
  "maxResults": max_results,
259
234
  "singleEvents": str(single_events).lower(),
260
235
  "orderBy": order_by,
261
236
  }
262
-
263
- # Set time boundaries if provided, otherwise default to now for time_min
264
237
  if time_min:
265
238
  params["timeMin"] = time_min
266
239
  else:
267
240
  # Default to current time if not specified
268
241
  now = datetime.utcnow().isoformat() + "Z" # 'Z' indicates UTC time
269
242
  params["timeMin"] = now
270
-
271
243
  if time_max:
272
244
  params["timeMax"] = time_max
273
-
274
- # Add optional filters if provided
275
245
  if q:
276
246
  params["q"] = q
277
-
278
247
  if time_zone:
279
248
  params["timeZone"] = time_zone
280
-
281
249
  if page_token:
282
250
  params["pageToken"] = page_token
283
-
284
251
  logger.info(f"Retrieving calendar events with params: {params}")
285
-
286
252
  response = self._get(url, params=params)
287
253
  response.raise_for_status()
288
-
289
254
  data = response.json()
290
255
  events = data.get("items", [])
291
-
292
256
  if not events:
293
257
  return "No events found matching your criteria."
294
-
295
- # Extract calendar information
296
258
  calendar_summary = data.get("summary", "Your Calendar")
297
259
  time_zone_info = data.get("timeZone", "Unknown")
298
-
299
260
  result = f"Events from {calendar_summary} (Time Zone: {time_zone_info}):\n\n"
300
-
301
- # Process and format each event
302
261
  for i, event in enumerate(events, 1):
303
262
  # Get basic event details
304
263
  event_id = event.get("id", "No ID")
@@ -327,75 +286,53 @@ class GoogleCalendarApp(APIApplication):
327
286
  # Add a separator between events
328
287
  if i < len(events):
329
288
  result += "\n"
330
-
331
- # Add pagination info if available
332
289
  if "nextPageToken" in data:
333
290
  next_token = data.get("nextPageToken")
334
291
  result += (
335
292
  f"\nMore events available. Use page_token='{next_token}' to see more."
336
293
  )
337
-
338
294
  return result
339
295
 
340
296
  def quick_add_event(self, text: str, send_updates: str = "none") -> str:
341
- """Create a calendar event using natural language description
342
-
343
- This method allows you to quickly create an event using a simple text string,
344
- similar to how you would add events in the Google Calendar UI.
297
+ """
298
+ Creates a calendar event using natural language text input and returns a formatted confirmation message with event details.
345
299
 
346
300
  Args:
347
- text: Text describing the event (e.g., "Meeting with John at Coffee Shop tomorrow 3pm-4pm")
348
- send_updates: Who should receive notifications - "all", "externalOnly", or "none" (default)
301
+ text: Natural language text describing the event (e.g., 'Meeting with John at Coffee Shop tomorrow 3pm-4pm')
302
+ send_updates: Specifies who should receive event notifications: 'all', 'externalOnly', or 'none' (default)
349
303
 
350
304
  Returns:
351
- A confirmation message with the created event details or an error message
305
+ A formatted string containing the confirmation message with event details including summary, time, location, and event ID
306
+
307
+ Raises:
308
+ HTTPError: Raised when the API request fails or returns an error status code
309
+
310
+ Tags:
311
+ create, calendar, event, quick-add, natural-language, important
352
312
  """
353
313
  url = f"{self.base_api_url}/events/quickAdd"
354
-
355
- # Use params argument instead of manually constructing URL
356
314
  params = {"text": text, "sendUpdates": send_updates}
357
-
358
315
  logger.info(f"Creating event via quickAdd: '{text}'")
359
-
360
- # Pass params to _post method
361
316
  response = self._post(url, data=None, params=params)
362
317
  response.raise_for_status()
363
-
364
318
  event = response.json()
365
-
366
- # Extract event details
367
319
  event_id = event.get("id", "Unknown")
368
320
  summary = event.get("summary", "Untitled event")
369
-
370
- # Format dates
371
321
  start = event.get("start", {})
372
322
  end = event.get("end", {})
373
-
374
323
  start_time = start.get("dateTime", start.get("date", "Unknown"))
375
324
  end_time = end.get("dateTime", end.get("date", "Unknown"))
376
-
377
- # Format datetimes using the helper function
378
325
  start_formatted = self._format_datetime(start_time)
379
326
  end_formatted = self._format_datetime(end_time)
380
-
381
- # Get location if available
382
327
  location = event.get("location", "No location specified")
383
-
384
- # Format the confirmation message
385
328
  result = "Successfully created event!\n\n"
386
329
  result += f"Summary: {summary}\n"
387
330
  result += f"When: {start_formatted}"
388
-
389
- # Only add end time if it's different from start (for all-day events they might be the same)
390
331
  if start_formatted != end_formatted:
391
332
  result += f" to {end_formatted}"
392
-
393
333
  result += f"\nWhere: {location}\n"
394
334
  result += f"Event ID: {event_id}\n"
395
-
396
- # Add a note about viewing the event
397
335
  result += f"\nUse get_event('{event_id}') to see full details."
398
-
399
336
  return result
400
337
 
401
338
  def get_event_instances(
@@ -408,57 +345,47 @@ class GoogleCalendarApp(APIApplication):
408
345
  show_deleted: bool = False,
409
346
  page_token: str = None,
410
347
  ) -> str:
411
- """Get all instances of a recurring event
412
-
413
- This method retrieves all occurrences of a recurring event within a specified time range.
348
+ """
349
+ Retrieves and formats all instances of a recurring calendar event within a specified time range, showing details like time, status, and modifications for each occurrence.
414
350
 
415
351
  Args:
416
352
  event_id: ID of the recurring event
417
353
  max_results: Maximum number of event instances to return (default: 25, max: 2500)
418
- time_min: Lower bound (inclusive) for event's end time (ISO format)
419
- time_max: Upper bound (exclusive) for event's start time (ISO format)
420
- time_zone: Time zone used in the response (default is calendar's time zone)
354
+ time_min: Lower bound (inclusive) for event's end time in ISO format
355
+ time_max: Upper bound (exclusive) for event's start time in ISO format
356
+ time_zone: Time zone used in the response (defaults to calendar's time zone)
421
357
  show_deleted: Whether to include deleted instances (default: False)
422
358
  page_token: Token for retrieving a specific page of results
423
359
 
424
360
  Returns:
425
- A formatted list of event instances or an error message
361
+ A formatted string containing a list of event instances with details including time, status, instance ID, and modification information, plus pagination token if applicable.
362
+
363
+ Raises:
364
+ HTTPError: Raised when the API request fails or returns an error status code
365
+ JSONDecodeError: Raised when the API response cannot be parsed as JSON
366
+
367
+ Tags:
368
+ list, retrieve, calendar, events, recurring, pagination, formatting, important
426
369
  """
427
370
  url = f"{self.base_api_url}/events/{event_id}/instances"
428
-
429
- # Build query parameters
430
371
  params = {"maxResults": max_results, "showDeleted": str(show_deleted).lower()}
431
-
432
- # Add optional parameters if provided
433
372
  if time_min:
434
373
  params["timeMin"] = time_min
435
-
436
374
  if time_max:
437
375
  params["timeMax"] = time_max
438
-
439
376
  if time_zone:
440
377
  params["timeZone"] = time_zone
441
-
442
378
  if page_token:
443
379
  params["pageToken"] = page_token
444
-
445
380
  logger.info(f"Retrieving instances of recurring event with ID: {event_id}")
446
-
447
381
  response = self._get(url, params=params)
448
382
  response.raise_for_status()
449
-
450
383
  data = response.json()
451
384
  instances = data.get("items", [])
452
-
453
385
  if not instances:
454
386
  return f"No instances found for recurring event with ID: {event_id}"
455
-
456
- # Extract event summary from the first instance
457
387
  parent_summary = instances[0].get("summary", "Untitled recurring event")
458
-
459
388
  result = f"Instances of recurring event: {parent_summary}\n\n"
460
-
461
- # Process and format each instance
462
389
  for i, instance in enumerate(instances, 1):
463
390
  # Get instance ID and status
464
391
  instance_id = instance.get("id", "No ID")
@@ -500,12 +427,9 @@ class GoogleCalendarApp(APIApplication):
500
427
  # Add a separator between instances
501
428
  if i < len(instances):
502
429
  result += "\n"
503
-
504
- # Add pagination info if available
505
430
  if "nextPageToken" in data:
506
431
  next_token = data.get("nextPageToken")
507
432
  result += f"\nMore instances available. Use page_token='{next_token}' to see more."
508
-
509
433
  return result
510
434
 
511
435
  def list_tools(self):
@@ -1,9 +1,6 @@
1
1
  from typing import Any
2
2
 
3
- from loguru import logger
4
-
5
3
  from universal_mcp.applications.application import APIApplication
6
- from universal_mcp.exceptions import NotAuthorizedError
7
4
  from universal_mcp.integrations import Integration
8
5
 
9
6
 
@@ -11,83 +8,81 @@ class GoogleDocsApp(APIApplication):
11
8
  def __init__(self, integration: Integration) -> None:
12
9
  super().__init__(name="google-docs", integration=integration)
13
10
  self.base_api_url = "https://docs.googleapis.com/v1/documents"
14
-
15
- def _get_headers(self):
16
- if not self.integration:
17
- raise ValueError("Integration not configured for GoogleDocsApp")
18
- credentials = self.integration.get_credentials()
19
- if not credentials:
20
- logger.warning("No Google credentials found via integration.")
21
- action = self.integration.authorize()
22
- raise NotAuthorizedError(action)
23
- if "headers" in credentials:
24
- return credentials["headers"]
25
- return {
26
- "Authorization": f"Bearer {credentials['access_token']}",
27
- "Content-Type": "application/json",
28
- }
29
-
11
+
30
12
  def create_document(self, title: str) -> dict[str, Any]:
31
13
  """
32
- Creates a new blank Google Document with the specified title.
33
-
14
+ Creates a new blank Google Document with the specified title and returns the API response.
15
+
34
16
  Args:
35
- title: The title of the document to create
36
-
17
+ title: The title for the new Google Document to be created
18
+
37
19
  Returns:
38
- The response from the Google Docs API
20
+ A dictionary containing the Google Docs API response with document details and metadata
21
+
22
+ Raises:
23
+ HTTPError: If the API request fails due to network issues, authentication errors, or invalid parameters
24
+ RequestException: If there are connection errors or timeout issues during the API request
25
+
26
+ Tags:
27
+ create, document, api, important, google-docs, http
39
28
  """
40
29
  url = self.base_api_url
41
30
  document_data = {"title": title}
42
31
  response = self._post(url, data=document_data)
43
32
  response.raise_for_status()
44
33
  return response.json()
45
-
34
+
46
35
  def get_document(self, document_id: str) -> dict[str, Any]:
47
36
  """
48
- Gets the latest version of the specified document.
49
-
37
+ Retrieves the latest version of a specified document from the Google Docs API.
38
+
50
39
  Args:
51
- document_id: The ID of the document to retrieve
52
-
40
+ document_id: The unique identifier of the document to retrieve
41
+
53
42
  Returns:
54
- The response from the Google Docs API containing the document data
43
+ A dictionary containing the document data from the Google Docs API response
44
+
45
+ Raises:
46
+ HTTPError: If the API request fails or the document is not found
47
+ JSONDecodeError: If the API response cannot be parsed as JSON
48
+
49
+ Tags:
50
+ retrieve, read, api, document, google-docs, important
55
51
  """
56
52
  url = f"{self.base_api_url}/{document_id}"
57
53
  response = self._get(url)
58
54
  return response.json()
59
-
60
- def add_content(self, document_id: str, content: str, index: int = 1) -> dict[str, Any]:
55
+
56
+ def add_content(
57
+ self, document_id: str, content: str, index: int = 1
58
+ ) -> dict[str, Any]:
61
59
  """
62
- Adds text content to an existing Google Document.
63
-
60
+ Adds text content at a specified position in an existing Google Document via the Google Docs API.
61
+
64
62
  Args:
65
- document_id: The ID of the document to update
66
- content: The text content to insert
67
- index: The position at which to insert the text (default: 1, beginning of document)
68
-
63
+ document_id: The unique identifier of the Google Document to be updated
64
+ content: The text content to be inserted into the document
65
+ index: The zero-based position in the document where the text should be inserted (default: 1)
66
+
69
67
  Returns:
70
- The response from the Google Docs API
68
+ A dictionary containing the Google Docs API response after performing the batch update operation
69
+
70
+ Raises:
71
+ HTTPError: When the API request fails, such as invalid document_id or insufficient permissions
72
+ RequestException: When there are network connectivity issues or API endpoint problems
73
+
74
+ Tags:
75
+ update, insert, document, api, google-docs, batch, content-management, important
71
76
  """
72
77
  url = f"{self.base_api_url}/{document_id}:batchUpdate"
73
78
  batch_update_data = {
74
79
  "requests": [
75
- {
76
- "insertText": {
77
- "location": {"index": index},
78
- "text": content
79
- }
80
- }
80
+ {"insertText": {"location": {"index": index}, "text": content}}
81
81
  ]
82
82
  }
83
-
84
83
  response = self._post(url, data=batch_update_data)
85
84
  response.raise_for_status()
86
85
  return response.json()
87
-
86
+
88
87
  def list_tools(self):
89
- return [
90
- self.create_document,
91
- self.get_document,
92
- self.add_content
93
- ]
88
+ return [self.create_document, self.get_document, self.add_content]