workspace-mcp 1.0.0__py3-none-any.whl → 1.0.2__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.
- auth/service_decorator.py +31 -32
- core/server.py +3 -10
- core/utils.py +36 -0
- gcalendar/calendar_tools.py +308 -258
- gchat/chat_tools.py +131 -158
- gdocs/docs_tools.py +121 -149
- gdrive/drive_tools.py +168 -171
- gforms/forms_tools.py +118 -157
- gmail/gmail_tools.py +319 -400
- gsheets/sheets_tools.py +144 -197
- gslides/slides_tools.py +113 -157
- main.py +31 -25
- workspace_mcp-1.0.2.dist-info/METADATA +422 -0
- workspace_mcp-1.0.2.dist-info/RECORD +32 -0
- workspace_mcp-1.0.0.dist-info/METADATA +0 -29
- workspace_mcp-1.0.0.dist-info/RECORD +0 -32
- {workspace_mcp-1.0.0.dist-info → workspace_mcp-1.0.2.dist-info}/WHEEL +0 -0
- {workspace_mcp-1.0.0.dist-info → workspace_mcp-1.0.2.dist-info}/entry_points.txt +0 -0
- {workspace_mcp-1.0.0.dist-info → workspace_mcp-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {workspace_mcp-1.0.0.dist-info → workspace_mcp-1.0.2.dist-info}/top_level.txt +0 -0
gforms/forms_tools.py
CHANGED
@@ -13,12 +13,14 @@ from googleapiclient.errors import HttpError
|
|
13
13
|
|
14
14
|
from auth.service_decorator import require_google_service
|
15
15
|
from core.server import server
|
16
|
+
from core.utils import handle_http_errors
|
16
17
|
|
17
18
|
logger = logging.getLogger(__name__)
|
18
19
|
|
19
20
|
|
20
21
|
@server.tool()
|
21
22
|
@require_google_service("forms", "forms")
|
23
|
+
@handle_http_errors("create_form")
|
22
24
|
async def create_form(
|
23
25
|
service,
|
24
26
|
user_google_email: str,
|
@@ -40,42 +42,34 @@ async def create_form(
|
|
40
42
|
"""
|
41
43
|
logger.info(f"[create_form] Invoked. Email: '{user_google_email}', Title: {title}")
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
"
|
46
|
-
"title": title
|
47
|
-
}
|
45
|
+
form_body: Dict[str, Any] = {
|
46
|
+
"info": {
|
47
|
+
"title": title
|
48
48
|
}
|
49
|
+
}
|
50
|
+
|
51
|
+
if description:
|
52
|
+
form_body["info"]["description"] = description
|
49
53
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
if document_title:
|
54
|
-
form_body["info"]["document_title"] = document_title
|
55
|
-
|
56
|
-
created_form = await asyncio.to_thread(
|
57
|
-
service.forms().create(body=form_body).execute
|
58
|
-
)
|
54
|
+
if document_title:
|
55
|
+
form_body["info"]["document_title"] = document_title
|
59
56
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
except Exception as e:
|
72
|
-
message = f"Unexpected error creating form: {e}."
|
73
|
-
logger.exception(message)
|
74
|
-
raise Exception(message)
|
57
|
+
created_form = await asyncio.to_thread(
|
58
|
+
service.forms().create(body=form_body).execute
|
59
|
+
)
|
60
|
+
|
61
|
+
form_id = created_form.get("formId")
|
62
|
+
edit_url = f"https://docs.google.com/forms/d/{form_id}/edit"
|
63
|
+
responder_url = created_form.get("responderUri", f"https://docs.google.com/forms/d/{form_id}/viewform")
|
64
|
+
|
65
|
+
confirmation_message = f"Successfully created form '{created_form.get('info', {}).get('title', title)}' for {user_google_email}. Form ID: {form_id}. Edit URL: {edit_url}. Responder URL: {responder_url}"
|
66
|
+
logger.info(f"Form created successfully for {user_google_email}. ID: {form_id}")
|
67
|
+
return confirmation_message
|
75
68
|
|
76
69
|
|
77
70
|
@server.tool()
|
78
71
|
@require_google_service("forms", "forms")
|
72
|
+
@handle_http_errors("get_form")
|
79
73
|
async def get_form(
|
80
74
|
service,
|
81
75
|
user_google_email: str,
|
@@ -93,30 +87,29 @@ async def get_form(
|
|
93
87
|
"""
|
94
88
|
logger.info(f"[get_form] Invoked. Email: '{user_google_email}', Form ID: {form_id}")
|
95
89
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
result = f"""Form Details for {user_google_email}:
|
90
|
+
form = await asyncio.to_thread(
|
91
|
+
service.forms().get(formId=form_id).execute
|
92
|
+
)
|
93
|
+
|
94
|
+
form_info = form.get("info", {})
|
95
|
+
title = form_info.get("title", "No Title")
|
96
|
+
description = form_info.get("description", "No Description")
|
97
|
+
document_title = form_info.get("documentTitle", title)
|
98
|
+
|
99
|
+
edit_url = f"https://docs.google.com/forms/d/{form_id}/edit"
|
100
|
+
responder_url = form.get("responderUri", f"https://docs.google.com/forms/d/{form_id}/viewform")
|
101
|
+
|
102
|
+
items = form.get("items", [])
|
103
|
+
questions_summary = []
|
104
|
+
for i, item in enumerate(items, 1):
|
105
|
+
item_title = item.get("title", f"Question {i}")
|
106
|
+
item_type = item.get("questionItem", {}).get("question", {}).get("required", False)
|
107
|
+
required_text = " (Required)" if item_type else ""
|
108
|
+
questions_summary.append(f" {i}. {item_title}{required_text}")
|
109
|
+
|
110
|
+
questions_text = "\n".join(questions_summary) if questions_summary else " No questions found"
|
111
|
+
|
112
|
+
result = f"""Form Details for {user_google_email}:
|
120
113
|
- Title: "{title}"
|
121
114
|
- Description: "{description}"
|
122
115
|
- Document Title: "{document_title}"
|
@@ -125,21 +118,14 @@ async def get_form(
|
|
125
118
|
- Responder URL: {responder_url}
|
126
119
|
- Questions ({len(items)} total):
|
127
120
|
{questions_text}"""
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
except HttpError as error:
|
132
|
-
message = f"API error getting form: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Forms'."
|
133
|
-
logger.error(message, exc_info=True)
|
134
|
-
raise Exception(message)
|
135
|
-
except Exception as e:
|
136
|
-
message = f"Unexpected error getting form: {e}."
|
137
|
-
logger.exception(message)
|
138
|
-
raise Exception(message)
|
121
|
+
|
122
|
+
logger.info(f"Successfully retrieved form for {user_google_email}. ID: {form_id}")
|
123
|
+
return result
|
139
124
|
|
140
125
|
|
141
126
|
@server.tool()
|
142
127
|
@require_google_service("forms", "forms")
|
128
|
+
@handle_http_errors("set_publish_settings")
|
143
129
|
async def set_publish_settings(
|
144
130
|
service,
|
145
131
|
user_google_email: str,
|
@@ -161,31 +147,23 @@ async def set_publish_settings(
|
|
161
147
|
"""
|
162
148
|
logger.info(f"[set_publish_settings] Invoked. Email: '{user_google_email}', Form ID: {form_id}")
|
163
149
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
}
|
150
|
+
settings_body = {
|
151
|
+
"publishAsTemplate": publish_as_template,
|
152
|
+
"requireAuthentication": require_authentication
|
153
|
+
}
|
169
154
|
|
170
|
-
|
171
|
-
|
172
|
-
|
155
|
+
await asyncio.to_thread(
|
156
|
+
service.forms().setPublishSettings(formId=form_id, body=settings_body).execute
|
157
|
+
)
|
173
158
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
except HttpError as error:
|
178
|
-
message = f"API error updating publish settings: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Forms'."
|
179
|
-
logger.error(message, exc_info=True)
|
180
|
-
raise Exception(message)
|
181
|
-
except Exception as e:
|
182
|
-
message = f"Unexpected error updating publish settings: {e}."
|
183
|
-
logger.exception(message)
|
184
|
-
raise Exception(message)
|
159
|
+
confirmation_message = f"Successfully updated publish settings for form {form_id} for {user_google_email}. Publish as template: {publish_as_template}, Require authentication: {require_authentication}"
|
160
|
+
logger.info(f"Publish settings updated successfully for {user_google_email}. Form ID: {form_id}")
|
161
|
+
return confirmation_message
|
185
162
|
|
186
163
|
|
187
164
|
@server.tool()
|
188
165
|
@require_google_service("forms", "forms")
|
166
|
+
@handle_http_errors("get_form_response")
|
189
167
|
async def get_form_response(
|
190
168
|
service,
|
191
169
|
user_google_email: str,
|
@@ -205,49 +183,41 @@ async def get_form_response(
|
|
205
183
|
"""
|
206
184
|
logger.info(f"[get_form_response] Invoked. Email: '{user_google_email}', Form ID: {form_id}, Response ID: {response_id}")
|
207
185
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
result = f"""Form Response Details for {user_google_email}:
|
186
|
+
response = await asyncio.to_thread(
|
187
|
+
service.forms().responses().get(formId=form_id, responseId=response_id).execute
|
188
|
+
)
|
189
|
+
|
190
|
+
response_id = response.get("responseId", "Unknown")
|
191
|
+
create_time = response.get("createTime", "Unknown")
|
192
|
+
last_submitted_time = response.get("lastSubmittedTime", "Unknown")
|
193
|
+
|
194
|
+
answers = response.get("answers", {})
|
195
|
+
answer_details = []
|
196
|
+
for question_id, answer_data in answers.items():
|
197
|
+
question_response = answer_data.get("textAnswers", {}).get("answers", [])
|
198
|
+
if question_response:
|
199
|
+
answer_text = ", ".join([ans.get("value", "") for ans in question_response])
|
200
|
+
answer_details.append(f" Question ID {question_id}: {answer_text}")
|
201
|
+
else:
|
202
|
+
answer_details.append(f" Question ID {question_id}: No answer provided")
|
203
|
+
|
204
|
+
answers_text = "\n".join(answer_details) if answer_details else " No answers found"
|
205
|
+
|
206
|
+
result = f"""Form Response Details for {user_google_email}:
|
230
207
|
- Form ID: {form_id}
|
231
208
|
- Response ID: {response_id}
|
232
209
|
- Created: {create_time}
|
233
210
|
- Last Submitted: {last_submitted_time}
|
234
211
|
- Answers:
|
235
212
|
{answers_text}"""
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
except HttpError as error:
|
240
|
-
message = f"API error getting form response: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Forms'."
|
241
|
-
logger.error(message, exc_info=True)
|
242
|
-
raise Exception(message)
|
243
|
-
except Exception as e:
|
244
|
-
message = f"Unexpected error getting form response: {e}."
|
245
|
-
logger.exception(message)
|
246
|
-
raise Exception(message)
|
213
|
+
|
214
|
+
logger.info(f"Successfully retrieved response for {user_google_email}. Response ID: {response_id}")
|
215
|
+
return result
|
247
216
|
|
248
217
|
|
249
218
|
@server.tool()
|
250
219
|
@require_google_service("forms", "forms")
|
220
|
+
@handle_http_errors("list_form_responses")
|
251
221
|
async def list_form_responses(
|
252
222
|
service,
|
253
223
|
user_google_email: str,
|
@@ -269,50 +239,41 @@ async def list_form_responses(
|
|
269
239
|
"""
|
270
240
|
logger.info(f"[list_form_responses] Invoked. Email: '{user_google_email}', Form ID: {form_id}")
|
271
241
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
242
|
+
params = {
|
243
|
+
"formId": form_id,
|
244
|
+
"pageSize": page_size
|
245
|
+
}
|
246
|
+
if page_token:
|
247
|
+
params["pageToken"] = page_token
|
248
|
+
|
249
|
+
responses_result = await asyncio.to_thread(
|
250
|
+
service.forms().responses().list(**params).execute
|
251
|
+
)
|
252
|
+
|
253
|
+
responses = responses_result.get("responses", [])
|
254
|
+
next_page_token = responses_result.get("nextPageToken")
|
255
|
+
|
256
|
+
if not responses:
|
257
|
+
return f"No responses found for form {form_id} for {user_google_email}."
|
258
|
+
|
259
|
+
response_details = []
|
260
|
+
for i, response in enumerate(responses, 1):
|
261
|
+
response_id = response.get("responseId", "Unknown")
|
262
|
+
create_time = response.get("createTime", "Unknown")
|
263
|
+
last_submitted_time = response.get("lastSubmittedTime", "Unknown")
|
264
|
+
|
265
|
+
answers_count = len(response.get("answers", {}))
|
266
|
+
response_details.append(
|
267
|
+
f" {i}. Response ID: {response_id} | Created: {create_time} | Last Submitted: {last_submitted_time} | Answers: {answers_count}"
|
282
268
|
)
|
283
269
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
if not responses:
|
288
|
-
return f"No responses found for form {form_id} for {user_google_email}."
|
289
|
-
|
290
|
-
response_details = []
|
291
|
-
for i, response in enumerate(responses, 1):
|
292
|
-
response_id = response.get("responseId", "Unknown")
|
293
|
-
create_time = response.get("createTime", "Unknown")
|
294
|
-
last_submitted_time = response.get("lastSubmittedTime", "Unknown")
|
295
|
-
|
296
|
-
answers_count = len(response.get("answers", {}))
|
297
|
-
response_details.append(
|
298
|
-
f" {i}. Response ID: {response_id} | Created: {create_time} | Last Submitted: {last_submitted_time} | Answers: {answers_count}"
|
299
|
-
)
|
300
|
-
|
301
|
-
pagination_info = f"\nNext page token: {next_page_token}" if next_page_token else "\nNo more pages."
|
302
|
-
|
303
|
-
result = f"""Form Responses for {user_google_email}:
|
270
|
+
pagination_info = f"\nNext page token: {next_page_token}" if next_page_token else "\nNo more pages."
|
271
|
+
|
272
|
+
result = f"""Form Responses for {user_google_email}:
|
304
273
|
- Form ID: {form_id}
|
305
274
|
- Total responses returned: {len(responses)}
|
306
275
|
- Responses:
|
307
276
|
{chr(10).join(response_details)}{pagination_info}"""
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
except HttpError as error:
|
312
|
-
message = f"API error listing form responses: {error}. You might need to re-authenticate. LLM: Try 'start_google_auth' with the user's email ({user_google_email}) and service_name='Google Forms'."
|
313
|
-
logger.error(message, exc_info=True)
|
314
|
-
raise Exception(message)
|
315
|
-
except Exception as e:
|
316
|
-
message = f"Unexpected error listing form responses: {e}."
|
317
|
-
logger.exception(message)
|
318
|
-
raise Exception(message)
|
277
|
+
|
278
|
+
logger.info(f"Successfully retrieved {len(responses)} responses for {user_google_email}. Form ID: {form_id}")
|
279
|
+
return result
|