google-workspace-mcp 1.0.5__tar.gz → 1.2.0__tar.gz

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 (41) hide show
  1. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/.gitignore +0 -13
  2. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/PKG-INFO +4 -3
  3. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/pyproject.toml +4 -3
  4. google_workspace_mcp-1.2.0/src/google_workspace_mcp/models.py +486 -0
  5. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/services/calendar.py +14 -4
  6. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/services/drive.py +268 -18
  7. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/services/sheets_service.py +273 -35
  8. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/services/slides.py +242 -53
  9. google_workspace_mcp-1.2.0/src/google_workspace_mcp/tools/calendar.py +240 -0
  10. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/tools/docs_tools.py +67 -33
  11. google_workspace_mcp-1.2.0/src/google_workspace_mcp/tools/drive.py +489 -0
  12. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/tools/gmail.py +95 -39
  13. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/tools/sheets_tools.py +112 -46
  14. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/tools/slides.py +317 -46
  15. google_workspace_mcp-1.0.5/src/google_workspace_mcp/tools/calendar.py +0 -229
  16. google_workspace_mcp-1.0.5/src/google_workspace_mcp/tools/drive.py +0 -226
  17. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/README.md +0 -0
  18. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/__init__.py +0 -0
  19. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/__main__.py +0 -0
  20. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/app.py +0 -0
  21. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/auth/__init__.py +0 -0
  22. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/auth/gauth.py +0 -0
  23. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/config.py +0 -0
  24. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/prompts/__init__.py +0 -0
  25. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/prompts/calendar.py +0 -0
  26. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/prompts/drive.py +0 -0
  27. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/prompts/gmail.py +0 -0
  28. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/prompts/slides.py +0 -0
  29. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/resources/__init__.py +0 -0
  30. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/resources/calendar.py +0 -0
  31. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/resources/drive.py +0 -0
  32. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/resources/gmail.py +0 -0
  33. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/resources/sheets_resources.py +0 -0
  34. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/resources/slides.py +0 -0
  35. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/services/__init__.py +0 -0
  36. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/services/base.py +0 -0
  37. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/services/docs_service.py +0 -0
  38. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/services/gmail.py +0 -0
  39. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/tools/__init__.py +0 -0
  40. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/utils/__init__.py +0 -0
  41. {google_workspace_mcp-1.0.5 → google_workspace_mcp-1.2.0}/src/google_workspace_mcp/utils/markdown_slides.py +0 -0
@@ -20,8 +20,6 @@ coverage.xml
20
20
  .hypothesis/
21
21
  .pytype/
22
22
  cython_debug/
23
- .cursor/
24
- docs/
25
23
 
26
24
  # Build and Distribution
27
25
  build/
@@ -74,20 +72,9 @@ local_settings.py
74
72
  db.sqlite3
75
73
  db.sqlite3-journal
76
74
 
77
- # Documentation
78
- docs/_build/
79
- /site
80
-
81
75
  # OS specific
82
76
  .DS_Store
83
77
 
84
- # Custom project files
85
- CONTRIBUTING.md
86
- cp.md
87
- integration_test_slides.py
88
- *GOTCHA*
89
- *real_integration_test*
90
-
91
78
  # Services
92
79
  # Celery
93
80
  celerybeat-schedule
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-workspace-mcp
3
- Version: 1.0.5
3
+ Version: 1.2.0
4
4
  Summary: MCP server for Google Workspace integration
5
5
  Author-email: Arclio Team <info@arclio.com>
6
6
  License: MIT
@@ -11,8 +11,9 @@ Requires-Dist: google-auth-httplib2>=0.1.0
11
11
  Requires-Dist: google-auth-oauthlib>=1.0.0
12
12
  Requires-Dist: google-auth>=2.22.0
13
13
  Requires-Dist: markdown>=3.5.0
14
- Requires-Dist: markdowndeck>=0.1.4
15
- Requires-Dist: mcp>=1.7.0
14
+ Requires-Dist: markdowndeck>=0.1.5
15
+ Requires-Dist: mcp>=1.12.0
16
+ Requires-Dist: pyhumps>=3.8.0
16
17
  Requires-Dist: python-dotenv>=1.0.0
17
18
  Requires-Dist: pytz>=2023.3
18
19
  Provides-Extra: dev
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "google-workspace-mcp"
7
- version = "1.0.5"
7
+ version = "1.2.0"
8
8
  description = "MCP server for Google Workspace integration"
9
9
  authors = [
10
10
  {name = "Arclio Team", email = "info@arclio.com"},
@@ -21,8 +21,9 @@ dependencies = [
21
21
  "python-dotenv>=1.0.0",
22
22
  "markdown>=3.5.0",
23
23
  "beautifulsoup4>=4.12.0",
24
- "mcp>=1.7.0",
25
- "markdowndeck>=0.1.4",
24
+ "mcp>=1.12.0",
25
+ "markdowndeck>=0.1.5",
26
+ "pyhumps>=3.8.0",
26
27
  ]
27
28
 
28
29
  [project.scripts]
@@ -0,0 +1,486 @@
1
+ """
2
+ Pydantic output models for Google Workspace MCP tools.
3
+
4
+ These models define the exact structure of tool outputs to ensure proper
5
+ output schemas are generated by the MCP Python SDK.
6
+ """
7
+
8
+ from typing import Any
9
+
10
+ from pydantic import BaseModel, Field
11
+
12
+ # === Document (Google Docs) Output Models ===
13
+
14
+
15
+ class DocumentCreationOutput(BaseModel):
16
+ """Output schema for document creation operations."""
17
+
18
+ document_id: str = Field(..., description="The ID of the created document")
19
+ title: str = Field(..., description="The title of the document")
20
+ document_link: str = Field(..., description="The link to access the document")
21
+
22
+
23
+ class DocumentMetadataOutput(BaseModel):
24
+ """Output schema for document metadata retrieval."""
25
+
26
+ document_id: str = Field(..., description="The ID of the document")
27
+ title: str = Field(..., description="The title of the document")
28
+ document_link: str = Field(..., description="The link to access the document")
29
+
30
+
31
+ class DocumentContentOutput(BaseModel):
32
+ """Output schema for document content retrieval."""
33
+
34
+ document_id: str = Field(..., description="The ID of the document")
35
+ markdown_content: str = Field(
36
+ ..., description="The document content in Markdown format"
37
+ )
38
+
39
+
40
+ class DocumentUpdateOutput(BaseModel):
41
+ """Output schema for document update operations."""
42
+
43
+ success: bool = Field(..., description="Whether the operation was successful")
44
+ message: str = Field(..., description="Success or error message")
45
+ updated_range: str | None = Field(None, description="The range that was updated")
46
+
47
+
48
+ class DocumentBatchUpdateOutput(BaseModel):
49
+ """Output schema for document batch update operations."""
50
+
51
+ document_id: str = Field(..., description="The ID of the document")
52
+ replies: list[dict[str, Any]] = Field(
53
+ ..., description="The API response replies for each request"
54
+ )
55
+
56
+
57
+ class DocumentImageInsertOutput(BaseModel):
58
+ """Output schema for image insertion operations."""
59
+
60
+ success: bool = Field(
61
+ ..., description="Whether the image was inserted successfully"
62
+ )
63
+ image_id: str | None = Field(None, description="The ID of the inserted image")
64
+ message: str = Field(..., description="Success or error message")
65
+
66
+
67
+ # === Calendar Output Models ===
68
+
69
+
70
+ class CalendarEventsOutput(BaseModel):
71
+ """Output schema for calendar events retrieval."""
72
+
73
+ count: int = Field(..., description="Number of events returned")
74
+ events: list[dict[str, Any]] = Field(..., description="List of calendar events")
75
+
76
+
77
+ class CalendarEventDetailsOutput(BaseModel):
78
+ """Output schema for single calendar event details."""
79
+
80
+ id: str = Field(..., description="The event ID")
81
+ summary: str = Field(..., description="The event title/summary")
82
+ start: dict[str, Any] = Field(..., description="Event start time information")
83
+ end: dict[str, Any] = Field(..., description="Event end time information")
84
+ description: str | None = Field(None, description="Event description")
85
+ attendees: list[dict[str, Any]] | None = Field(
86
+ None, description="List of attendees"
87
+ )
88
+ location: str | None = Field(None, description="Event location")
89
+
90
+
91
+ class CalendarEventCreationOutput(BaseModel):
92
+ """Output schema for calendar event creation."""
93
+
94
+ id: str = Field(..., description="The created event ID")
95
+ html_link: str = Field(..., description="Link to view the event")
96
+ summary: str = Field(..., description="The event title/summary")
97
+ start: dict[str, Any] = Field(..., description="Event start time information")
98
+ end: dict[str, Any] = Field(..., description="Event end time information")
99
+
100
+
101
+ class CalendarEventDeletionOutput(BaseModel):
102
+ """Output schema for calendar event deletion."""
103
+
104
+ message: str = Field(..., description="Confirmation message")
105
+ success: bool = Field(..., description="Whether the deletion was successful")
106
+
107
+
108
+ # === Drive Output Models ===
109
+
110
+
111
+ class DriveSearchOutput(BaseModel):
112
+ """Output schema for Drive file search operations."""
113
+
114
+ files: list[dict[str, Any]] = Field(..., description="List of found files")
115
+
116
+
117
+ class DriveFileContentOutput(BaseModel):
118
+ """Output schema for Drive file content reading."""
119
+
120
+ file_id: str = Field(..., description="The ID of the file")
121
+ name: str = Field(..., description="The name of the file")
122
+ content: str = Field(..., description="The file content")
123
+ mime_type: str = Field(..., description="The MIME type of the file")
124
+
125
+
126
+ class DriveFileUploadOutput(BaseModel):
127
+ """Output schema for Drive file upload operations."""
128
+
129
+ id: str = Field(..., description="The ID of the uploaded file")
130
+ name: str = Field(..., description="The name of the uploaded file")
131
+ web_view_link: str = Field(..., description="Link to view the file")
132
+ size: str = Field(..., description="Size of the uploaded file")
133
+
134
+
135
+ class DriveFolderCreationOutput(BaseModel):
136
+ """Output schema for Drive folder creation."""
137
+
138
+ id: str = Field(..., description="The ID of the created folder")
139
+ name: str = Field(..., description="The name of the created folder")
140
+ web_view_link: str = Field(..., description="Link to view the folder")
141
+
142
+
143
+ class DriveFileDeletionOutput(BaseModel):
144
+ """Output schema for Drive file deletion."""
145
+
146
+ success: bool = Field(..., description="Whether the deletion was successful")
147
+ message: str = Field(..., description="Confirmation message")
148
+ file_id: str = Field(..., description="The ID of the deleted file")
149
+
150
+
151
+ class DriveSharedDrivesOutput(BaseModel):
152
+ """Output schema for shared drives listing."""
153
+
154
+ count: int = Field(..., description="Number of shared drives returned")
155
+ shared_drives: list[dict[str, Any]] = Field(
156
+ ..., description="List of shared drives"
157
+ )
158
+
159
+
160
+ class DriveFolderSearchOutput(BaseModel):
161
+ """Output schema for folder file search operations."""
162
+
163
+ folder_id: str = Field(..., description="The ID of the searched folder")
164
+ files: list[dict[str, Any]] = Field(..., description="List of files in the folder")
165
+
166
+
167
+ class DriveFolderFindOutput(BaseModel):
168
+ """Output schema for folder finding operations."""
169
+
170
+ folder_name: str = Field(..., description="The searched folder name")
171
+ folders_found: list[dict[str, Any]] = Field(
172
+ ..., description="List of found folders"
173
+ )
174
+ folder_count: int = Field(..., description="Number of folders found")
175
+ target_folder: dict[str, Any] | None = Field(
176
+ None, description="The primary target folder"
177
+ )
178
+ files: list[dict[str, Any]] | None = Field(
179
+ None, description="Files in the target folder"
180
+ )
181
+ file_count: int | None = Field(None, description="Number of files in target folder")
182
+ message: str | None = Field(None, description="Additional status message")
183
+
184
+
185
+ # === Gmail Output Models ===
186
+
187
+
188
+ class GmailEmailSearchOutput(BaseModel):
189
+ """Output schema for Gmail email search operations."""
190
+
191
+ count: int = Field(..., description="Number of emails returned")
192
+ emails: list[dict[str, Any]] = Field(..., description="List of email messages")
193
+
194
+
195
+ class GmailMessageDetailsOutput(BaseModel):
196
+ """Output schema for Gmail message details retrieval."""
197
+
198
+ id: str = Field(..., description="The message ID")
199
+ thread_id: str = Field(..., description="The thread ID")
200
+ subject: str = Field(..., description="Email subject")
201
+ from_email: str = Field(..., description="Sender email address")
202
+ to_email: list[str] = Field(..., description="Recipient email addresses")
203
+ date: str = Field(..., description="Email date")
204
+ body: str = Field(..., description="Email body content")
205
+ attachments: list[dict[str, Any]] | None = Field(
206
+ None, description="List of attachments"
207
+ )
208
+
209
+
210
+ class GmailAttachmentOutput(BaseModel):
211
+ """Output schema for Gmail attachment retrieval."""
212
+
213
+ filename: str = Field(..., description="The attachment filename")
214
+ mime_type: str = Field(..., description="The MIME type of the attachment")
215
+ size: int = Field(..., description="Size of the attachment in bytes")
216
+ data: str = Field(..., description="Base64 encoded attachment data")
217
+
218
+
219
+ class GmailDraftCreationOutput(BaseModel):
220
+ """Output schema for Gmail draft creation."""
221
+
222
+ id: str = Field(..., description="The draft ID")
223
+ message: dict[str, Any] = Field(..., description="The draft message details")
224
+
225
+
226
+ class GmailDraftDeletionOutput(BaseModel):
227
+ """Output schema for Gmail draft deletion."""
228
+
229
+ message: str = Field(..., description="Confirmation message")
230
+ success: bool = Field(..., description="Whether the deletion was successful")
231
+
232
+
233
+ class GmailDraftSendOutput(BaseModel):
234
+ """Output schema for Gmail draft sending."""
235
+
236
+ id: str = Field(..., description="The sent message ID")
237
+ thread_id: str = Field(..., description="The thread ID")
238
+ label_ids: list[str] = Field(..., description="Labels applied to the sent message")
239
+
240
+
241
+ class GmailReplyOutput(BaseModel):
242
+ """Output schema for Gmail reply operations."""
243
+
244
+ id: str = Field(..., description="The reply message ID")
245
+ thread_id: str = Field(..., description="The thread ID")
246
+ in_reply_to: str = Field(..., description="The original message ID")
247
+
248
+
249
+ class GmailBulkDeleteOutput(BaseModel):
250
+ """Output schema for Gmail bulk deletion operations."""
251
+
252
+ deleted_count: int = Field(..., description="Number of messages deleted")
253
+ success: bool = Field(..., description="Whether the operation was successful")
254
+ message: str = Field(..., description="Operation summary message")
255
+
256
+
257
+ class GmailSendOutput(BaseModel):
258
+ """Output schema for Gmail email sending."""
259
+
260
+ id: str = Field(..., description="The sent message ID")
261
+ thread_id: str = Field(..., description="The thread ID")
262
+ label_ids: list[str] = Field(..., description="Labels applied to the sent message")
263
+
264
+
265
+ # === Sheets Output Models ===
266
+
267
+
268
+ class SheetsCreationOutput(BaseModel):
269
+ """Output schema for spreadsheet creation."""
270
+
271
+ spreadsheet_id: str = Field(..., description="The ID of the created spreadsheet")
272
+ title: str = Field(..., description="The title of the spreadsheet")
273
+ spreadsheet_url: str = Field(..., description="URL to access the spreadsheet")
274
+
275
+
276
+ class SheetsReadOutput(BaseModel):
277
+ """Output schema for spreadsheet range reading."""
278
+
279
+ range: str = Field(..., description="The A1 notation range that was read")
280
+ values: list[list[Any]] = Field(..., description="The cell values as a 2D array")
281
+ major_dimension: str = Field(..., description="The major dimension of the data")
282
+
283
+
284
+ class SheetsWriteOutput(BaseModel):
285
+ """Output schema for spreadsheet range writing."""
286
+
287
+ updated_range: str = Field(
288
+ ..., description="The A1 notation range that was updated"
289
+ )
290
+ updated_rows: int = Field(..., description="Number of rows updated")
291
+ updated_columns: int = Field(..., description="Number of columns updated")
292
+ updated_cells: int = Field(..., description="Number of cells updated")
293
+
294
+
295
+ class SheetsAppendOutput(BaseModel):
296
+ """Output schema for spreadsheet row appending."""
297
+
298
+ spreadsheet_id: str = Field(..., description="The ID of the spreadsheet")
299
+ table_range: str = Field(
300
+ ..., description="The range of the table that was appended to"
301
+ )
302
+ updates: dict[str, Any] = Field(..., description="Information about the update")
303
+
304
+
305
+ class SheetsClearOutput(BaseModel):
306
+ """Output schema for spreadsheet range clearing."""
307
+
308
+ cleared_range: str = Field(
309
+ ..., description="The A1 notation range that was cleared"
310
+ )
311
+ spreadsheet_id: str = Field(..., description="The ID of the spreadsheet")
312
+
313
+
314
+ class SheetsAddSheetOutput(BaseModel):
315
+ """Output schema for adding a new sheet."""
316
+
317
+ sheet_properties: dict[str, Any] = Field(
318
+ ..., description="Properties of the newly created sheet"
319
+ )
320
+ spreadsheet_id: str = Field(..., description="The ID of the spreadsheet")
321
+
322
+
323
+ class SheetsDeleteSheetOutput(BaseModel):
324
+ """Output schema for sheet deletion."""
325
+
326
+ success: bool = Field(..., description="Whether the deletion was successful")
327
+ message: str = Field(..., description="Confirmation message")
328
+ spreadsheet_id: str = Field(..., description="The ID of the spreadsheet")
329
+ deleted_sheet_id: int = Field(..., description="The ID of the deleted sheet")
330
+
331
+
332
+ # === Slides Output Models ===
333
+
334
+
335
+ class SlidesGetPresentationOutput(BaseModel):
336
+ """Output schema for presentation retrieval."""
337
+
338
+ presentation_id: str = Field(..., description="The ID of the presentation")
339
+ title: str = Field(..., description="The title of the presentation")
340
+ slides: list[dict[str, Any]] = Field(
341
+ ..., description="List of slides in the presentation"
342
+ )
343
+ masters: list[dict[str, Any]] = Field(..., description="List of slide masters")
344
+ layouts: list[dict[str, Any]] = Field(..., description="List of slide layouts")
345
+
346
+
347
+ class SlidesGetSlidesOutput(BaseModel):
348
+ """Output schema for slides retrieval."""
349
+
350
+ count: int = Field(..., description="Number of slides returned")
351
+ slides: list[dict[str, Any]] = Field(
352
+ ..., description="List of slides with their elements"
353
+ )
354
+
355
+
356
+ class SlidesCreatePresentationOutput(BaseModel):
357
+ """Output schema for presentation creation."""
358
+
359
+ presentation_id: str = Field(..., description="The ID of the created presentation")
360
+ title: str = Field(..., description="The title of the presentation")
361
+ presentation_url: str = Field(..., description="URL to access the presentation")
362
+
363
+
364
+ class SlidesCreateSlideOutput(BaseModel):
365
+ """Output schema for slide creation."""
366
+
367
+ slide_id: str = Field(..., description="The ID of the created slide")
368
+ presentation_id: str = Field(..., description="The ID of the presentation")
369
+ layout: str = Field(..., description="The layout used for the slide")
370
+
371
+
372
+ class SlidesAddTextOutput(BaseModel):
373
+ """Output schema for text addition to slides."""
374
+
375
+ element_id: str = Field(..., description="The ID of the created text element")
376
+ presentation_id: str = Field(..., description="The ID of the presentation")
377
+ slide_id: str = Field(..., description="The ID of the slide")
378
+
379
+
380
+ class SlidesAddFormattedTextOutput(BaseModel):
381
+ """Output schema for formatted text addition to slides."""
382
+
383
+ element_id: str = Field(..., description="The ID of the created text element")
384
+ presentation_id: str = Field(..., description="The ID of the presentation")
385
+ slide_id: str = Field(..., description="The ID of the slide")
386
+ formatting_applied: bool = Field(
387
+ ..., description="Whether formatting was successfully applied"
388
+ )
389
+
390
+
391
+ class SlidesAddListOutput(BaseModel):
392
+ """Output schema for bulleted list addition to slides."""
393
+
394
+ element_id: str = Field(..., description="The ID of the created list element")
395
+ presentation_id: str = Field(..., description="The ID of the presentation")
396
+ slide_id: str = Field(..., description="The ID of the slide")
397
+ items_count: int = Field(..., description="Number of list items added")
398
+
399
+
400
+ class SlidesAddTableOutput(BaseModel):
401
+ """Output schema for table addition to slides."""
402
+
403
+ element_id: str = Field(..., description="The ID of the created table element")
404
+ presentation_id: str = Field(..., description="The ID of the presentation")
405
+ slide_id: str = Field(..., description="The ID of the slide")
406
+ rows: int = Field(..., description="Number of rows in the table")
407
+ columns: int = Field(..., description="Number of columns in the table")
408
+
409
+
410
+ class SlidesAddNotesOutput(BaseModel):
411
+ """Output schema for slide notes addition."""
412
+
413
+ success: bool = Field(..., description="Whether the notes were added successfully")
414
+ presentation_id: str = Field(..., description="The ID of the presentation")
415
+ slide_id: str = Field(..., description="The ID of the slide")
416
+ notes_length: int = Field(..., description="Length of the added notes")
417
+
418
+
419
+ class SlidesDuplicateSlideOutput(BaseModel):
420
+ """Output schema for slide duplication."""
421
+
422
+ new_slide_id: str = Field(..., description="The ID of the duplicated slide")
423
+ presentation_id: str = Field(..., description="The ID of the presentation")
424
+ source_slide_id: str = Field(..., description="The ID of the original slide")
425
+
426
+
427
+ class SlidesDeleteSlideOutput(BaseModel):
428
+ """Output schema for slide deletion."""
429
+
430
+ success: bool = Field(..., description="Whether the deletion was successful")
431
+ presentation_id: str = Field(..., description="The ID of the presentation")
432
+ deleted_slide_id: str = Field(..., description="The ID of the deleted slide")
433
+
434
+
435
+ class SlidesCreateFromMarkdownOutput(BaseModel):
436
+ """Output schema for presentation creation from Markdown."""
437
+
438
+ presentation_id: str = Field(..., description="The ID of the created presentation")
439
+ title: str = Field(..., description="The title of the presentation")
440
+ presentation_url: str = Field(..., description="URL to access the presentation")
441
+ slides_created: int = Field(
442
+ ..., description="Number of slides created from the Markdown"
443
+ )
444
+
445
+
446
+ class SlidesSharePresentationOutput(BaseModel):
447
+ """Output schema for presentation sharing."""
448
+
449
+ success: bool = Field(..., description="Whether the sharing was successful")
450
+ message: str = Field(..., description="Confirmation message")
451
+ presentation_id: str = Field(..., description="The ID of the presentation")
452
+ presentation_link: str = Field(..., description="Link to access the presentation")
453
+ domain: str = Field(..., description="The domain the presentation was shared with")
454
+ role: str = Field(..., description="The access role granted")
455
+
456
+
457
+ class SlidesInsertChartOutput(BaseModel):
458
+ """Output schema for chart insertion into slides."""
459
+
460
+ success: bool = Field(
461
+ ..., description="Whether the chart was inserted successfully"
462
+ )
463
+ message: str = Field(..., description="Confirmation message")
464
+ presentation_id: str = Field(..., description="The ID of the presentation")
465
+ slide_id: str = Field(..., description="The ID of the slide")
466
+ chart_element_id: str | None = Field(
467
+ None, description="The ID of the chart element"
468
+ )
469
+
470
+
471
+ # === Generic Success/Error Output Models ===
472
+
473
+
474
+ class SuccessOutput(BaseModel):
475
+ """Generic success output schema."""
476
+
477
+ success: bool = Field(..., description="Whether the operation was successful")
478
+ message: str = Field(..., description="Success message")
479
+
480
+
481
+ class ErrorOutput(BaseModel):
482
+ """Generic error output schema."""
483
+
484
+ error: bool = Field(..., description="Whether an error occurred")
485
+ message: str = Field(..., description="Error message")
486
+ details: dict[str, Any] | None = Field(None, description="Additional error details")
@@ -226,7 +226,9 @@ class CalendarService(BaseGoogleService):
226
226
  self.handle_api_error("delete_event", e)
227
227
  return False
228
228
 
229
- def get_event_details(self, event_id: str, calendar_id: str = "primary") -> dict[str, Any] | None:
229
+ def get_event_details(
230
+ self, event_id: str, calendar_id: str = "primary"
231
+ ) -> dict[str, Any] | None:
230
232
  """
231
233
  Retrieves details for a specific event.
232
234
 
@@ -238,9 +240,17 @@ class CalendarService(BaseGoogleService):
238
240
  A dictionary containing the event details or an error dictionary.
239
241
  """
240
242
  try:
241
- logger.info(f"Fetching details for event ID: {event_id} from calendar: {calendar_id}")
242
- event = self.service.events().get(calendarId=calendar_id, eventId=event_id).execute()
243
- logger.info(f"Successfully fetched details for event: {event.get('summary')}")
243
+ logger.info(
244
+ f"Fetching details for event ID: {event_id} from calendar: {calendar_id}"
245
+ )
246
+ event = (
247
+ self.service.events()
248
+ .get(calendarId=calendar_id, eventId=event_id)
249
+ .execute()
250
+ )
251
+ logger.info(
252
+ f"Successfully fetched details for event: {event.get('summary')}"
253
+ )
244
254
  return event # Return the full event resource as per API
245
255
  except Exception as e:
246
256
  return self.handle_api_error("get_event_details", e)