google-workspace-mcp 1.1.5__py3-none-any.whl → 1.2.0__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.
- google_workspace_mcp/__main__.py +5 -6
- google_workspace_mcp/models.py +486 -0
- google_workspace_mcp/services/calendar.py +14 -4
- google_workspace_mcp/services/drive.py +237 -14
- google_workspace_mcp/services/sheets_service.py +273 -35
- google_workspace_mcp/services/slides.py +42 -1829
- google_workspace_mcp/tools/calendar.py +116 -100
- google_workspace_mcp/tools/docs_tools.py +99 -57
- google_workspace_mcp/tools/drive.py +112 -92
- google_workspace_mcp/tools/gmail.py +131 -66
- google_workspace_mcp/tools/sheets_tools.py +137 -64
- google_workspace_mcp/tools/slides.py +295 -743
- {google_workspace_mcp-1.1.5.dist-info → google_workspace_mcp-1.2.0.dist-info}/METADATA +3 -2
- {google_workspace_mcp-1.1.5.dist-info → google_workspace_mcp-1.2.0.dist-info}/RECORD +16 -17
- google_workspace_mcp/tools/add_image.py +0 -1781
- google_workspace_mcp/utils/unit_conversion.py +0 -201
- {google_workspace_mcp-1.1.5.dist-info → google_workspace_mcp-1.2.0.dist-info}/WHEEL +0 -0
- {google_workspace_mcp-1.1.5.dist-info → google_workspace_mcp-1.2.0.dist-info}/entry_points.txt +0 -0
@@ -3,9 +3,14 @@ Google Calendar tool handlers for Google Workspace MCP.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import logging
|
6
|
-
from typing import Any
|
7
6
|
|
8
7
|
from google_workspace_mcp.app import mcp # Import from central app module
|
8
|
+
from google_workspace_mcp.models import (
|
9
|
+
CalendarEventCreationOutput,
|
10
|
+
CalendarEventDeletionOutput,
|
11
|
+
CalendarEventDetailsOutput,
|
12
|
+
CalendarEventsOutput,
|
13
|
+
)
|
9
14
|
from google_workspace_mcp.services.calendar import CalendarService
|
10
15
|
|
11
16
|
logger = logging.getLogger(__name__)
|
@@ -16,6 +21,7 @@ logger = logging.getLogger(__name__)
|
|
16
21
|
|
17
22
|
# @mcp.tool(
|
18
23
|
# name="list_calendars",
|
24
|
+
# description="Lists all calendars accessible by the user.",
|
19
25
|
# )
|
20
26
|
# async def list_calendars() -> dict[str, Any]:
|
21
27
|
# """
|
@@ -39,186 +45,196 @@ logger = logging.getLogger(__name__)
|
|
39
45
|
# return {"count": len(calendars), "calendars": calendars}
|
40
46
|
|
41
47
|
|
42
|
-
|
43
|
-
|
44
|
-
|
48
|
+
@mcp.tool(
|
49
|
+
name="calendar_get_events",
|
50
|
+
description="Retrieve calendar events within a specified time range.",
|
51
|
+
)
|
45
52
|
async def calendar_get_events(
|
46
53
|
time_min: str,
|
47
54
|
time_max: str,
|
48
55
|
calendar_id: str = "primary",
|
49
56
|
max_results: int = 250,
|
50
57
|
show_deleted: bool = False,
|
51
|
-
) ->
|
58
|
+
) -> CalendarEventsOutput:
|
52
59
|
"""
|
53
60
|
Retrieve calendar events within a specified time range.
|
54
61
|
|
55
62
|
Args:
|
56
|
-
time_min: Start time
|
57
|
-
time_max: End time
|
58
|
-
calendar_id:
|
59
|
-
max_results: Maximum number of events to return
|
60
|
-
show_deleted: Whether to include deleted events
|
63
|
+
time_min: Start of time range (ISO datetime string)
|
64
|
+
time_max: End of time range (ISO datetime string)
|
65
|
+
calendar_id: Calendar identifier (default: 'primary')
|
66
|
+
max_results: Maximum number of events to return
|
67
|
+
show_deleted: Whether to include deleted events
|
61
68
|
|
62
69
|
Returns:
|
63
|
-
|
70
|
+
CalendarEventsOutput: Structured output containing the events data
|
64
71
|
"""
|
65
|
-
logger.info(f"Executing calendar_get_events tool
|
66
|
-
|
67
|
-
if not calendar_id:
|
68
|
-
raise ValueError("calendar_id parameter is required")
|
69
|
-
if not time_min:
|
70
|
-
raise ValueError("time_min parameter is required")
|
71
|
-
if not time_max:
|
72
|
-
raise ValueError("time_max parameter is required")
|
72
|
+
logger.info(f"Executing calendar_get_events tool for calendar {calendar_id}")
|
73
73
|
|
74
74
|
calendar_service = CalendarService()
|
75
|
-
|
76
|
-
calendar_id=calendar_id,
|
75
|
+
result = calendar_service.get_events(
|
77
76
|
time_min=time_min,
|
78
77
|
time_max=time_max,
|
78
|
+
calendar_id=calendar_id,
|
79
79
|
max_results=max_results,
|
80
80
|
show_deleted=show_deleted,
|
81
81
|
)
|
82
82
|
|
83
|
-
|
84
|
-
|
83
|
+
# Check for errors in the service result
|
84
|
+
if isinstance(result, dict) and result.get("error"):
|
85
|
+
raise ValueError(result.get("message", "Error retrieving calendar events"))
|
85
86
|
|
87
|
+
# Extract events list - the service returns a dict with 'items' key containing events
|
88
|
+
events = result.get("items", []) if isinstance(result, dict) else result
|
86
89
|
if not events:
|
87
|
-
|
90
|
+
events = []
|
88
91
|
|
89
|
-
# Return
|
90
|
-
return
|
92
|
+
# Return the Pydantic model instance
|
93
|
+
return CalendarEventsOutput(count=len(events), events=events)
|
91
94
|
|
92
95
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
96
|
+
@mcp.tool(
|
97
|
+
name="calendar_get_event_details",
|
98
|
+
description="Retrieves detailed information for a specific calendar event by its ID.",
|
99
|
+
)
|
100
|
+
async def calendar_get_event_details(
|
101
|
+
event_id: str, calendar_id: str = "primary"
|
102
|
+
) -> CalendarEventDetailsOutput:
|
97
103
|
"""
|
98
|
-
Retrieves
|
104
|
+
Retrieves detailed information for a specific calendar event by its ID.
|
99
105
|
|
100
106
|
Args:
|
101
|
-
event_id: The
|
102
|
-
calendar_id:
|
107
|
+
event_id: The unique identifier of the event
|
108
|
+
calendar_id: Calendar identifier (default: 'primary')
|
103
109
|
|
104
110
|
Returns:
|
105
|
-
|
106
|
-
or an error message.
|
111
|
+
CalendarEventDetailsOutput: Structured output containing the event details
|
107
112
|
"""
|
108
|
-
logger.info(f"Executing calendar_get_event_details tool for
|
109
|
-
if not event_id or not event_id.strip():
|
110
|
-
raise ValueError("Event ID cannot be empty.")
|
111
|
-
if not calendar_id or not calendar_id.strip():
|
112
|
-
raise ValueError("Calendar ID cannot be empty.") # Ensure calendar_id is also validated
|
113
|
+
logger.info(f"Executing calendar_get_event_details tool for event {event_id}")
|
113
114
|
|
114
115
|
calendar_service = CalendarService()
|
115
|
-
|
116
|
+
result = calendar_service.get_event_details(
|
117
|
+
event_id=event_id, calendar_id=calendar_id
|
118
|
+
)
|
116
119
|
|
117
|
-
|
118
|
-
|
120
|
+
# Check for errors in the service result
|
121
|
+
if isinstance(result, dict) and result.get("error"):
|
122
|
+
raise ValueError(result.get("message", "Error retrieving event details"))
|
119
123
|
|
120
|
-
if not
|
124
|
+
if not result: # Should be caught by error dict check
|
121
125
|
raise ValueError(f"Failed to retrieve details for event '{event_id}'")
|
122
126
|
|
123
|
-
|
127
|
+
# Return the Pydantic model instance
|
128
|
+
return CalendarEventDetailsOutput(
|
129
|
+
id=result["id"],
|
130
|
+
summary=result.get("summary", ""),
|
131
|
+
start=result.get("start", {}),
|
132
|
+
end=result.get("end", {}),
|
133
|
+
description=result.get("description"),
|
134
|
+
attendees=result.get("attendees"),
|
135
|
+
location=result.get("location"),
|
136
|
+
)
|
124
137
|
|
125
138
|
|
126
|
-
|
127
|
-
|
128
|
-
|
139
|
+
@mcp.tool(
|
140
|
+
name="create_calendar_event",
|
141
|
+
description="Creates a new event in a specified Google Calendar.",
|
142
|
+
)
|
129
143
|
async def create_calendar_event(
|
130
144
|
summary: str,
|
131
145
|
start_time: str,
|
132
146
|
end_time: str,
|
133
147
|
calendar_id: str = "primary",
|
134
|
-
location: str
|
135
|
-
description: str
|
136
|
-
attendees: list[str]
|
148
|
+
location: str = None,
|
149
|
+
description: str = None,
|
150
|
+
attendees: list[str] = None,
|
137
151
|
send_notifications: bool = True,
|
138
|
-
timezone: str
|
139
|
-
) ->
|
152
|
+
timezone: str = None,
|
153
|
+
) -> CalendarEventCreationOutput:
|
140
154
|
"""
|
141
|
-
|
155
|
+
Creates a new event in a specified Google Calendar.
|
142
156
|
|
143
157
|
Args:
|
144
|
-
summary:
|
145
|
-
start_time:
|
146
|
-
end_time:
|
147
|
-
calendar_id: Calendar
|
148
|
-
location:
|
149
|
-
description:
|
150
|
-
attendees: List of attendee email addresses (optional)
|
151
|
-
send_notifications: Whether to send notifications
|
152
|
-
timezone: Timezone for the event (
|
158
|
+
summary: Event title/summary
|
159
|
+
start_time: Event start time (ISO datetime string)
|
160
|
+
end_time: Event end time (ISO datetime string)
|
161
|
+
calendar_id: Calendar identifier (default: 'primary')
|
162
|
+
location: Event location (optional)
|
163
|
+
description: Event description (optional)
|
164
|
+
attendees: List of attendee email addresses (optional)
|
165
|
+
send_notifications: Whether to send notifications (default: True)
|
166
|
+
timezone: Timezone for the event (optional)
|
153
167
|
|
154
168
|
Returns:
|
155
|
-
|
169
|
+
CalendarEventCreationOutput: Structured output containing the created event data
|
156
170
|
"""
|
157
|
-
logger.info(f"Executing create_calendar_event
|
158
|
-
if not summary or not start_time or not end_time:
|
159
|
-
raise ValueError("Summary, start_time, and end_time are required")
|
171
|
+
logger.info(f"Executing create_calendar_event tool for summary: {summary}")
|
160
172
|
|
161
173
|
calendar_service = CalendarService()
|
162
174
|
result = calendar_service.create_event(
|
163
175
|
summary=summary,
|
164
176
|
start_time=start_time,
|
165
177
|
end_time=end_time,
|
178
|
+
calendar_id=calendar_id,
|
166
179
|
location=location,
|
167
180
|
description=description,
|
168
181
|
attendees=attendees,
|
169
182
|
send_notifications=send_notifications,
|
170
183
|
timezone=timezone,
|
171
|
-
calendar_id=calendar_id,
|
172
184
|
)
|
173
185
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
error_msg = result.get("message", error_msg)
|
178
|
-
raise ValueError(error_msg)
|
186
|
+
# Check for errors in the service result
|
187
|
+
if isinstance(result, dict) and result.get("error"):
|
188
|
+
raise ValueError(result.get("message", "Error creating calendar event"))
|
179
189
|
|
180
|
-
|
190
|
+
if not result:
|
191
|
+
raise ValueError("Error creating calendar event")
|
181
192
|
|
193
|
+
# Return the Pydantic model instance
|
194
|
+
return CalendarEventCreationOutput(
|
195
|
+
id=result["id"],
|
196
|
+
html_link=result.get("htmlLink", ""),
|
197
|
+
summary=result.get("summary", summary),
|
198
|
+
start=result.get("start", {}),
|
199
|
+
end=result.get("end", {}),
|
200
|
+
)
|
182
201
|
|
183
|
-
|
184
|
-
|
185
|
-
|
202
|
+
|
203
|
+
@mcp.tool(
|
204
|
+
name="delete_calendar_event",
|
205
|
+
description="Deletes an event from Google Calendar by its event ID.",
|
206
|
+
)
|
186
207
|
async def delete_calendar_event(
|
187
208
|
event_id: str,
|
188
209
|
calendar_id: str = "primary",
|
189
210
|
send_notifications: bool = True,
|
190
|
-
) ->
|
211
|
+
) -> CalendarEventDeletionOutput:
|
191
212
|
"""
|
192
|
-
|
213
|
+
Deletes an event from Google Calendar by its event ID.
|
193
214
|
|
194
215
|
Args:
|
195
|
-
event_id: The
|
196
|
-
calendar_id: Calendar
|
197
|
-
send_notifications: Whether to send
|
216
|
+
event_id: The unique identifier of the event to delete
|
217
|
+
calendar_id: Calendar identifier (default: 'primary')
|
218
|
+
send_notifications: Whether to send notifications (default: True)
|
198
219
|
|
199
220
|
Returns:
|
200
|
-
|
221
|
+
CalendarEventDeletionOutput: Structured output containing the deletion result
|
201
222
|
"""
|
202
|
-
logger.info(f"Executing delete_calendar_event
|
203
|
-
if not event_id:
|
204
|
-
raise ValueError("Event ID is required")
|
223
|
+
logger.info(f"Executing delete_calendar_event tool for event {event_id}")
|
205
224
|
|
206
225
|
calendar_service = CalendarService()
|
207
|
-
|
226
|
+
result = calendar_service.delete_event(
|
208
227
|
event_id=event_id,
|
209
|
-
send_notifications=send_notifications,
|
210
228
|
calendar_id=calendar_id,
|
229
|
+
send_notifications=send_notifications,
|
211
230
|
)
|
212
231
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
"message": f"Event with ID '{event_id}' deleted successfully from calendar '{calendar_id}'.",
|
223
|
-
"success": True,
|
224
|
-
}
|
232
|
+
# Check for errors in the service result
|
233
|
+
if isinstance(result, dict) and result.get("error"):
|
234
|
+
raise ValueError(result.get("message", "Error deleting calendar event"))
|
235
|
+
|
236
|
+
# Return the Pydantic model instance
|
237
|
+
return CalendarEventDeletionOutput(
|
238
|
+
message=f"Event with ID '{event_id}' deleted successfully from calendar '{calendar_id}'.",
|
239
|
+
success=True,
|
240
|
+
)
|
@@ -3,18 +3,26 @@ Google Docs tool handlers for Google Workspace MCP.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import logging
|
6
|
-
from typing import Any
|
7
6
|
|
8
7
|
from google_workspace_mcp.app import mcp
|
8
|
+
from google_workspace_mcp.models import (
|
9
|
+
DocumentBatchUpdateOutput,
|
10
|
+
DocumentContentOutput,
|
11
|
+
DocumentCreationOutput,
|
12
|
+
DocumentImageInsertOutput,
|
13
|
+
DocumentMetadataOutput,
|
14
|
+
DocumentUpdateOutput,
|
15
|
+
)
|
9
16
|
from google_workspace_mcp.services.docs_service import DocsService
|
10
17
|
|
11
18
|
logger = logging.getLogger(__name__)
|
12
19
|
|
13
20
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
21
|
+
@mcp.tool(
|
22
|
+
name="docs_create_document",
|
23
|
+
description="Creates a new Google Document with a specified title.",
|
24
|
+
)
|
25
|
+
async def docs_create_document(title: str) -> DocumentCreationOutput:
|
18
26
|
"""
|
19
27
|
Creates a new, empty Google Document.
|
20
28
|
|
@@ -22,8 +30,7 @@ async def docs_create_document(title: str) -> dict[str, Any]:
|
|
22
30
|
title: The title for the new Google Document.
|
23
31
|
|
24
32
|
Returns:
|
25
|
-
|
26
|
-
or an error message.
|
33
|
+
DocumentCreationOutput containing document_id, title, and document_link.
|
27
34
|
"""
|
28
35
|
logger.info(f"Executing docs_create_document tool with title: '{title}'")
|
29
36
|
if not title or not title.strip():
|
@@ -40,13 +47,18 @@ async def docs_create_document(title: str) -> dict[str, Any]:
|
|
40
47
|
f"Failed to create document '{title}' or did not receive a document ID."
|
41
48
|
)
|
42
49
|
|
43
|
-
return
|
50
|
+
return DocumentCreationOutput(
|
51
|
+
document_id=result["document_id"],
|
52
|
+
title=result["title"],
|
53
|
+
document_link=result["document_link"],
|
54
|
+
)
|
44
55
|
|
45
56
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
57
|
+
@mcp.tool(
|
58
|
+
name="docs_get_document_metadata",
|
59
|
+
description="Retrieves metadata (like title and ID) for a Google Document.",
|
60
|
+
)
|
61
|
+
async def docs_get_document_metadata(document_id: str) -> DocumentMetadataOutput:
|
50
62
|
"""
|
51
63
|
Retrieves metadata for a specific Google Document.
|
52
64
|
|
@@ -54,8 +66,7 @@ async def docs_get_document_metadata(document_id: str) -> dict[str, Any]:
|
|
54
66
|
document_id: The ID of the Google Document.
|
55
67
|
|
56
68
|
Returns:
|
57
|
-
|
58
|
-
or an error message.
|
69
|
+
DocumentMetadataOutput containing document_id, title, and document_link.
|
59
70
|
"""
|
60
71
|
logger.info(
|
61
72
|
f"Executing docs_get_document_metadata tool for document_id: '{document_id}'"
|
@@ -72,13 +83,18 @@ async def docs_get_document_metadata(document_id: str) -> dict[str, Any]:
|
|
72
83
|
if not result or not result.get("document_id"):
|
73
84
|
raise ValueError(f"Failed to retrieve metadata for document '{document_id}'.")
|
74
85
|
|
75
|
-
return
|
86
|
+
return DocumentMetadataOutput(
|
87
|
+
document_id=result["document_id"],
|
88
|
+
title=result["title"],
|
89
|
+
document_link=result["document_link"],
|
90
|
+
)
|
76
91
|
|
77
92
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
93
|
+
@mcp.tool(
|
94
|
+
name="docs_get_content_as_markdown",
|
95
|
+
description="Retrieves the content of a Google Document, attempting to convert it to Markdown. Note: Direct Markdown export from Google Docs via Drive API is not officially guaranteed for all document complexities and may result in errors or suboptimal formatting. For critical conversions, consider exporting as HTML and using a dedicated Markdown conversion library.",
|
96
|
+
)
|
97
|
+
async def docs_get_content_as_markdown(document_id: str) -> DocumentContentOutput:
|
82
98
|
"""
|
83
99
|
Retrieves the main textual content of a Google Document, converted to Markdown.
|
84
100
|
|
@@ -86,8 +102,7 @@ async def docs_get_content_as_markdown(document_id: str) -> dict[str, Any]:
|
|
86
102
|
document_id: The ID of the Google Document.
|
87
103
|
|
88
104
|
Returns:
|
89
|
-
|
90
|
-
or an error message.
|
105
|
+
DocumentContentOutput containing document_id and markdown_content.
|
91
106
|
"""
|
92
107
|
logger.info(
|
93
108
|
f"Executing docs_get_content_as_markdown tool for document_id: '{document_id}'"
|
@@ -108,15 +123,18 @@ async def docs_get_content_as_markdown(document_id: str) -> dict[str, Any]:
|
|
108
123
|
f"Failed to retrieve Markdown content for document '{document_id}'."
|
109
124
|
)
|
110
125
|
|
111
|
-
return
|
126
|
+
return DocumentContentOutput(
|
127
|
+
document_id=result["document_id"], markdown_content=result["markdown_content"]
|
128
|
+
)
|
112
129
|
|
113
130
|
|
114
|
-
|
115
|
-
|
116
|
-
|
131
|
+
@mcp.tool(
|
132
|
+
name="docs_append_text",
|
133
|
+
description="Appends text to the end of a specified Google Document.",
|
134
|
+
)
|
117
135
|
async def docs_append_text(
|
118
136
|
document_id: str, text: str, ensure_newline: bool = True
|
119
|
-
) ->
|
137
|
+
) -> DocumentUpdateOutput:
|
120
138
|
"""
|
121
139
|
Appends the given text to the end of the specified Google Document.
|
122
140
|
|
@@ -127,7 +145,7 @@ async def docs_append_text(
|
|
127
145
|
if the document is not empty, to ensure the new text starts on a new line. (Default: True)
|
128
146
|
|
129
147
|
Returns:
|
130
|
-
|
148
|
+
DocumentUpdateOutput indicating success or failure.
|
131
149
|
"""
|
132
150
|
logger.info(f"Executing docs_append_text tool for document_id: '{document_id}'")
|
133
151
|
if not document_id or not document_id.strip():
|
@@ -145,15 +163,20 @@ async def docs_append_text(
|
|
145
163
|
if not result or not result.get("success"):
|
146
164
|
raise ValueError(f"Failed to append text to document '{document_id}'.")
|
147
165
|
|
148
|
-
return
|
166
|
+
return DocumentUpdateOutput(
|
167
|
+
success=result["success"],
|
168
|
+
message=result.get("message", "Text appended successfully"),
|
169
|
+
updated_range=result.get("updated_range"),
|
170
|
+
)
|
149
171
|
|
150
172
|
|
151
|
-
|
152
|
-
|
153
|
-
|
173
|
+
@mcp.tool(
|
174
|
+
name="docs_prepend_text",
|
175
|
+
description="Prepends text to the beginning of a specified Google Document.",
|
176
|
+
)
|
154
177
|
async def docs_prepend_text(
|
155
178
|
document_id: str, text: str, ensure_newline: bool = True
|
156
|
-
) ->
|
179
|
+
) -> DocumentUpdateOutput:
|
157
180
|
"""
|
158
181
|
Prepends the given text to the beginning of the specified Google Document.
|
159
182
|
|
@@ -164,7 +187,7 @@ async def docs_prepend_text(
|
|
164
187
|
if the document was not empty, to ensure existing content starts on a new line. (Default: True)
|
165
188
|
|
166
189
|
Returns:
|
167
|
-
|
190
|
+
DocumentUpdateOutput indicating success or failure.
|
168
191
|
"""
|
169
192
|
logger.info(f"Executing docs_prepend_text tool for document_id: '{document_id}'")
|
170
193
|
if not document_id or not document_id.strip():
|
@@ -182,15 +205,20 @@ async def docs_prepend_text(
|
|
182
205
|
if not result or not result.get("success"):
|
183
206
|
raise ValueError(f"Failed to prepend text to document '{document_id}'.")
|
184
207
|
|
185
|
-
return
|
208
|
+
return DocumentUpdateOutput(
|
209
|
+
success=result["success"],
|
210
|
+
message=result.get("message", "Text prepended successfully"),
|
211
|
+
updated_range=result.get("updated_range"),
|
212
|
+
)
|
186
213
|
|
187
214
|
|
188
|
-
|
189
|
-
|
190
|
-
|
215
|
+
@mcp.tool(
|
216
|
+
name="docs_insert_text",
|
217
|
+
description="Inserts text at a specified location in a Google Document. For simple appends or prepends, use 'docs_append_text' or 'docs_prepend_text'.",
|
218
|
+
)
|
191
219
|
async def docs_insert_text(
|
192
220
|
document_id: str, text: str, index: int | None = None, segment_id: str | None = None
|
193
|
-
) ->
|
221
|
+
) -> DocumentUpdateOutput:
|
194
222
|
"""
|
195
223
|
Inserts the given text at a specific location within the specified Google Document.
|
196
224
|
|
@@ -198,14 +226,14 @@ async def docs_insert_text(
|
|
198
226
|
document_id: The ID of the Google Document.
|
199
227
|
text: The text to insert.
|
200
228
|
index: Optional. The 0-based index where the text should be inserted within the segment.
|
201
|
-
|
202
|
-
|
203
|
-
|
229
|
+
For the main body, an index of 1 typically refers to the beginning of the content.
|
230
|
+
Consult Google Docs API documentation for details on indexing if precise placement is needed.
|
231
|
+
If omitted, defaults to a sensible starting position (e.g., beginning of the body).
|
204
232
|
segment_id: Optional. The ID of a specific document segment (e.g., header, footer).
|
205
233
|
If omitted, the text is inserted into the main document body.
|
206
234
|
|
207
235
|
Returns:
|
208
|
-
|
236
|
+
DocumentUpdateOutput indicating success or failure.
|
209
237
|
"""
|
210
238
|
logger.info(
|
211
239
|
f"Executing docs_insert_text tool for document_id: '{document_id}' at index: {index}"
|
@@ -225,13 +253,20 @@ async def docs_insert_text(
|
|
225
253
|
if not result or not result.get("success"):
|
226
254
|
raise ValueError(f"Failed to insert text into document '{document_id}'.")
|
227
255
|
|
228
|
-
return
|
256
|
+
return DocumentUpdateOutput(
|
257
|
+
success=result["success"],
|
258
|
+
message=result.get("message", "Text inserted successfully"),
|
259
|
+
updated_range=result.get("updated_range"),
|
260
|
+
)
|
229
261
|
|
230
262
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
263
|
+
@mcp.tool(
|
264
|
+
name="docs_batch_update",
|
265
|
+
description="Applies a list of raw Google Docs API update requests to a document. For advanced users familiar with Docs API request structures.",
|
266
|
+
)
|
267
|
+
async def docs_batch_update(
|
268
|
+
document_id: str, requests: list[dict]
|
269
|
+
) -> DocumentBatchUpdateOutput:
|
235
270
|
"""
|
236
271
|
Applies a list of Google Docs API update requests to the specified document.
|
237
272
|
This is an advanced tool; requests must conform to the Google Docs API format.
|
@@ -240,11 +275,10 @@ async def docs_batch_update(document_id: str, requests: list[dict]) -> dict[str,
|
|
240
275
|
Args:
|
241
276
|
document_id: The ID of the Google Document.
|
242
277
|
requests: A list of request objects (as dictionaries) to apply.
|
243
|
-
|
278
|
+
Example request: {"insertText": {"location": {"index": 1}, "text": "Hello"}}
|
244
279
|
|
245
280
|
Returns:
|
246
|
-
|
247
|
-
or an error message.
|
281
|
+
DocumentBatchUpdateOutput containing the API response from the batchUpdate call.
|
248
282
|
"""
|
249
283
|
logger.info(
|
250
284
|
f"Executing docs_batch_update tool for document_id: '{document_id}' with {len(requests)} requests."
|
@@ -267,19 +301,23 @@ async def docs_batch_update(document_id: str, requests: list[dict]) -> dict[str,
|
|
267
301
|
if not result: # Should be caught by error dict check
|
268
302
|
raise ValueError(f"Failed to execute batch update on document '{document_id}'.")
|
269
303
|
|
270
|
-
return
|
304
|
+
return DocumentBatchUpdateOutput(
|
305
|
+
document_id=result.get("documentId", document_id),
|
306
|
+
replies=result.get("replies", []),
|
307
|
+
)
|
271
308
|
|
272
309
|
|
273
|
-
|
274
|
-
|
275
|
-
|
310
|
+
@mcp.tool(
|
311
|
+
name="docs_insert_image",
|
312
|
+
description="Inserts an image into a Google Document from a URL at a specific index. The image URL must be publicly accessible and in PNG, JPEG, or GIF format.",
|
313
|
+
)
|
276
314
|
async def docs_insert_image(
|
277
315
|
document_id: str,
|
278
316
|
image_url: str,
|
279
317
|
index: int,
|
280
318
|
width: float | None = None,
|
281
319
|
height: float | None = None,
|
282
|
-
) ->
|
320
|
+
) -> DocumentImageInsertOutput:
|
283
321
|
"""
|
284
322
|
Inserts an image into a Google Document from a URL at a specific index.
|
285
323
|
|
@@ -291,7 +329,7 @@ async def docs_insert_image(
|
|
291
329
|
height: Optional height of the image in points (PT).
|
292
330
|
|
293
331
|
Returns:
|
294
|
-
|
332
|
+
DocumentImageInsertOutput containing the inserted image details.
|
295
333
|
"""
|
296
334
|
logger.info(
|
297
335
|
f"Executing docs_insert_image tool for document_id: '{document_id}' at index: {index}"
|
@@ -327,4 +365,8 @@ async def docs_insert_image(
|
|
327
365
|
if not result or not result.get("success"):
|
328
366
|
raise ValueError(f"Failed to insert image into document '{document_id}'.")
|
329
367
|
|
330
|
-
return
|
368
|
+
return DocumentImageInsertOutput(
|
369
|
+
success=result["success"],
|
370
|
+
image_id=result.get("image_id"),
|
371
|
+
message=result.get("message", "Image inserted successfully"),
|
372
|
+
)
|