google-services-mcp 0.1.0

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 (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +225 -0
  3. package/dist/auth/config.d.ts +43 -0
  4. package/dist/auth/config.d.ts.map +1 -0
  5. package/dist/auth/config.js +108 -0
  6. package/dist/auth/config.js.map +1 -0
  7. package/dist/auth/manager.d.ts +50 -0
  8. package/dist/auth/manager.d.ts.map +1 -0
  9. package/dist/auth/manager.js +140 -0
  10. package/dist/auth/manager.js.map +1 -0
  11. package/dist/auth/oauth.d.ts +49 -0
  12. package/dist/auth/oauth.d.ts.map +1 -0
  13. package/dist/auth/oauth.js +211 -0
  14. package/dist/auth/oauth.js.map +1 -0
  15. package/dist/auth/store.d.ts +18 -0
  16. package/dist/auth/store.d.ts.map +1 -0
  17. package/dist/auth/store.js +45 -0
  18. package/dist/auth/store.js.map +1 -0
  19. package/dist/cli.d.ts +7 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +112 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/main.d.ts +3 -0
  24. package/dist/main.d.ts.map +1 -0
  25. package/dist/main.js +21 -0
  26. package/dist/main.js.map +1 -0
  27. package/dist/server.d.ts +3 -0
  28. package/dist/server.d.ts.map +1 -0
  29. package/dist/server.js +11 -0
  30. package/dist/server.js.map +1 -0
  31. package/dist/services/calendar.d.ts +77 -0
  32. package/dist/services/calendar.d.ts.map +1 -0
  33. package/dist/services/calendar.js +141 -0
  34. package/dist/services/calendar.js.map +1 -0
  35. package/dist/services/contacts-tasks.d.ts +61 -0
  36. package/dist/services/contacts-tasks.d.ts.map +1 -0
  37. package/dist/services/contacts-tasks.js +103 -0
  38. package/dist/services/contacts-tasks.js.map +1 -0
  39. package/dist/services/docs.d.ts +30 -0
  40. package/dist/services/docs.d.ts.map +1 -0
  41. package/dist/services/docs.js +60 -0
  42. package/dist/services/docs.js.map +1 -0
  43. package/dist/services/drive.d.ts +51 -0
  44. package/dist/services/drive.d.ts.map +1 -0
  45. package/dist/services/drive.js +80 -0
  46. package/dist/services/drive.js.map +1 -0
  47. package/dist/services/forms.d.ts +28 -0
  48. package/dist/services/forms.d.ts.map +1 -0
  49. package/dist/services/forms.js +54 -0
  50. package/dist/services/forms.js.map +1 -0
  51. package/dist/services/gmail.d.ts +64 -0
  52. package/dist/services/gmail.d.ts.map +1 -0
  53. package/dist/services/gmail.js +144 -0
  54. package/dist/services/gmail.js.map +1 -0
  55. package/dist/services/sheets.d.ts +44 -0
  56. package/dist/services/sheets.d.ts.map +1 -0
  57. package/dist/services/sheets.js +53 -0
  58. package/dist/services/sheets.js.map +1 -0
  59. package/dist/services/slides.d.ts +28 -0
  60. package/dist/services/slides.d.ts.map +1 -0
  61. package/dist/services/slides.js +54 -0
  62. package/dist/services/slides.js.map +1 -0
  63. package/dist/services/youtube.d.ts +40 -0
  64. package/dist/services/youtube.d.ts.map +1 -0
  65. package/dist/services/youtube.js +91 -0
  66. package/dist/services/youtube.js.map +1 -0
  67. package/dist/tools/index.d.ts +3 -0
  68. package/dist/tools/index.d.ts.map +1 -0
  69. package/dist/tools/index.js +659 -0
  70. package/dist/tools/index.js.map +1 -0
  71. package/dist/util/result.d.ts +29 -0
  72. package/dist/util/result.d.ts.map +1 -0
  73. package/dist/util/result.js +21 -0
  74. package/dist/util/result.js.map +1 -0
  75. package/package.json +54 -0
@@ -0,0 +1,659 @@
1
+ import { z } from "zod";
2
+ import { ok, err } from "../util/result.js";
3
+ import { authManager } from "../auth/manager.js";
4
+ import { sendGmail, listGmailMessages, getGmailMessage, modifyGmailMessage, replyGmail } from "../services/gmail.js";
5
+ import { listCalendars, listEvents, createEvent, getEvent, updateEvent, deleteEvent, createMeetLink, } from "../services/calendar.js";
6
+ import { listDriveFiles, getDriveFile, uploadDriveFile, updateDriveFile, deleteDriveFile, shareDriveFile, } from "../services/drive.js";
7
+ import { listContacts, searchContacts, createContact, listTaskLists, listTasks, createTask, completeTask, deleteTask, } from "../services/contacts-tasks.js";
8
+ import { getSpreadsheet, readSheetRange, writeSheetRange, appendSheetRange, createSpreadsheet, batchUpdateSheet, } from "../services/sheets.js";
9
+ import { getDocument, getDocumentText, createDocument, insertText, replaceAllText, batchUpdateDocument, } from "../services/docs.js";
10
+ import { getPresentation, createPresentation, replaceAllText as replaceSlidesText, createSlide, deleteSlide, } from "../services/slides.js";
11
+ import { searchVideos, getVideo, getMyVideos, listPlaylists, createPlaylist, deletePlaylist, addVideoToPlaylist, listSubscriptions, } from "../services/youtube.js";
12
+ import { getForm, getFormResponses, createForm, addQuestion, } from "../services/forms.js";
13
+ /** Wrap a service call that resolves its own auth client. */
14
+ async function withClient(account, fn) {
15
+ try {
16
+ const client = await authManager.getClient(account);
17
+ return ok(await fn(client));
18
+ }
19
+ catch (error) {
20
+ return err(error);
21
+ }
22
+ }
23
+ export function registerTools(server) {
24
+ // ---- Account management -------------------------------------------------
25
+ server.registerTool("google_account_add", {
26
+ title: "Add a Google account",
27
+ description: "Start the OAuth consent flow to connect a new Google account. Opens a browser for sign-in.",
28
+ inputSchema: {
29
+ name: z.string().describe("Nickname for the account (e.g. personal, work)."),
30
+ openBrowser: z.boolean().optional().describe("Open a browser automatically (default true)."),
31
+ },
32
+ }, async ({ name, openBrowser }) => {
33
+ try {
34
+ const account = await authManager.addAccount(name, { openBrowser });
35
+ return ok({ status: "added", name: account.name, email: account.email });
36
+ }
37
+ catch (error) {
38
+ return err(error);
39
+ }
40
+ });
41
+ server.registerTool("google_account_list", {
42
+ title: "List connected Google accounts",
43
+ description: "List all connected accounts with their email and default status.",
44
+ inputSchema: {},
45
+ }, async () => {
46
+ try {
47
+ const accounts = await authManager.listAccounts();
48
+ const status = await authManager.getStatus();
49
+ return ok({
50
+ defaultAccount: status.defaultAccount,
51
+ accounts: accounts.map((a) => ({ name: a.name, email: a.email })),
52
+ });
53
+ }
54
+ catch (error) {
55
+ return err(error);
56
+ }
57
+ });
58
+ server.registerTool("google_account_remove", {
59
+ title: "Remove a Google account",
60
+ description: "Disconnect an account and delete its stored tokens.",
61
+ inputSchema: {
62
+ name: z.string().describe("Account nickname to remove."),
63
+ },
64
+ }, async ({ name }) => {
65
+ try {
66
+ const removed = await authManager.removeAccount(name);
67
+ return ok({ status: removed ? "removed" : "not_found", name });
68
+ }
69
+ catch (error) {
70
+ return err(error);
71
+ }
72
+ });
73
+ server.registerTool("google_account_set_default", {
74
+ title: "Set the default Google account",
75
+ description: "Set which account is used when no account is specified.",
76
+ inputSchema: {
77
+ name: z.string().describe("Account nickname to use as default."),
78
+ },
79
+ }, async ({ name }) => {
80
+ try {
81
+ await authManager.setDefaultAccount(name);
82
+ return ok({ status: "set", defaultAccount: name });
83
+ }
84
+ catch (error) {
85
+ return err(error);
86
+ }
87
+ });
88
+ server.registerTool("google_account_status", {
89
+ title: "Google services status",
90
+ description: "Show credential configuration, data directory, connected accounts and token health.",
91
+ inputSchema: {},
92
+ }, async () => {
93
+ try {
94
+ return ok(await authManager.getStatus());
95
+ }
96
+ catch (error) {
97
+ return err(error);
98
+ }
99
+ });
100
+ // ---- Gmail --------------------------------------------------------------
101
+ server.registerTool("google_gmail_send", {
102
+ title: "Send email",
103
+ description: "Send an email from the connected account.",
104
+ inputSchema: {
105
+ to: z.union([z.string(), z.array(z.string())]).describe("Recipient email(s)."),
106
+ subject: z.string().describe("Subject line."),
107
+ body: z.string().describe("Message body."),
108
+ cc: z.union([z.string(), z.array(z.string())]).optional().describe("CC recipient(s)."),
109
+ bcc: z.union([z.string(), z.array(z.string())]).optional().describe("BCC recipient(s)."),
110
+ bodyType: z.enum(["text", "html"]).optional().describe("Body format (default text)."),
111
+ account: z.string().optional().describe("Account nickname to use."),
112
+ },
113
+ }, async ({ to, subject, body, cc, bcc, bodyType, account }) => withClient(account, (client) => sendGmail(client, { to, subject, body, cc, bcc, bodyType })));
114
+ server.registerTool("google_gmail_list", {
115
+ title: "List emails",
116
+ description: "List messages from the inbox, newest first, with an optional Gmail search query.",
117
+ inputSchema: {
118
+ query: z.string().optional().describe("Gmail search query (e.g. from:bob, newer_than:2d)."),
119
+ maxResults: z.number().min(1).max(100).optional().describe("Max messages (default 25)."),
120
+ account: z.string().optional().describe("Account nickname to use."),
121
+ },
122
+ }, async ({ query, maxResults, account }) => withClient(account, (client) => listGmailMessages(client, { query, maxResults })));
123
+ server.registerTool("google_gmail_get", {
124
+ title: "Read an email",
125
+ description: "Fetch a single message with parsed headers, body and attachment flags.",
126
+ inputSchema: {
127
+ id: z.string().describe("Message ID."),
128
+ account: z.string().optional().describe("Account nickname to use."),
129
+ },
130
+ }, async ({ id, account }) => withClient(account, (client) => getGmailMessage(client, { id })));
131
+ server.registerTool("google_gmail_modify", {
132
+ title: "Modify email labels",
133
+ description: "Add or remove labels on a message (e.g. mark read/unread, star, archive).",
134
+ inputSchema: {
135
+ id: z.string().describe("Message ID."),
136
+ addLabels: z.array(z.string()).optional().describe("Labels to add (e.g. STARRED, INBOX, TRASH)."),
137
+ removeLabels: z.array(z.string()).optional().describe("Labels to remove (e.g. UNREAD)."),
138
+ account: z.string().optional().describe("Account nickname to use."),
139
+ },
140
+ }, async ({ id, addLabels, removeLabels, account }) => withClient(account, (client) => modifyGmailMessage(client, { id, addLabels, removeLabels })));
141
+ server.registerTool("google_gmail_reply", {
142
+ title: "Reply to an email",
143
+ description: "Reply to an existing message inside its thread, preserving threading headers.",
144
+ inputSchema: {
145
+ threadId: z.string().describe("Thread ID of the conversation."),
146
+ messageId: z.string().describe("ID of the message being replied to."),
147
+ body: z.string().describe("Reply body."),
148
+ bodyType: z.enum(["text", "html"]).optional().describe("Body format (default text)."),
149
+ account: z.string().optional().describe("Account nickname to use."),
150
+ },
151
+ }, async ({ threadId, messageId, body, bodyType, account }) => withClient(account, (client) => replyGmail(client, { threadId, messageId, body, bodyType })));
152
+ // ---- Calendar -----------------------------------------------------------
153
+ server.registerTool("google_calendar_list_calendars", {
154
+ title: "List calendars",
155
+ description: "List calendars the account can access.",
156
+ inputSchema: {
157
+ account: z.string().optional().describe("Account nickname to use."),
158
+ },
159
+ }, async ({ account }) => withClient(account, (client) => listCalendars(client)));
160
+ server.registerTool("google_calendar_list_events", {
161
+ title: "List calendar events",
162
+ description: "List upcoming events in a calendar, optionally filtered by time range or query.",
163
+ inputSchema: {
164
+ timeMin: z.string().optional().describe("Start of range (ISO 8601, default now)."),
165
+ timeMax: z.string().optional().describe("End of range (ISO 8601)."),
166
+ maxResults: z.number().min(1).max(250).optional().describe("Max events (default 25)."),
167
+ q: z.string().optional().describe("Free-text search (e.g. meeting)."),
168
+ calendarId: z.string().optional().describe("Calendar ID (default primary)."),
169
+ account: z.string().optional().describe("Account nickname to use."),
170
+ },
171
+ }, async ({ timeMin, timeMax, maxResults, q, calendarId, account }) => withClient(account, (client) => listEvents(client, { timeMin, timeMax, maxResults, q, calendarId })));
172
+ server.registerTool("google_calendar_create_event", {
173
+ title: "Create calendar event",
174
+ description: "Create a timed or all-day event. All-day events use YYYY-MM-DD dates.",
175
+ inputSchema: {
176
+ summary: z.string().describe("Event title."),
177
+ start: z.string().describe("Start: RFC3339 datetime or YYYY-MM-DD for all-day."),
178
+ end: z.string().describe("End: RFC3339 datetime or YYYY-MM-DD (exclusive) for all-day."),
179
+ description: z.string().optional(),
180
+ location: z.string().optional(),
181
+ attendees: z.array(z.string().email()).optional().describe("Attendee emails."),
182
+ calendarId: z.string().optional().describe("Calendar ID (default primary)."),
183
+ account: z.string().optional().describe("Account nickname to use."),
184
+ },
185
+ }, async ({ summary, start, end, description, location, attendees, calendarId, account }) => withClient(account, (client) => createEvent(client, { summary, start, end, description, location, attendees, calendarId })));
186
+ server.registerTool("google_calendar_create_meet", {
187
+ title: "Create event with Google Meet",
188
+ description: "Create a calendar event with an attached Google Meet link.",
189
+ inputSchema: {
190
+ summary: z.string().describe("Meeting title."),
191
+ start: z.string().describe("Start RFC3339 datetime."),
192
+ end: z.string().describe("End RFC3339 datetime."),
193
+ description: z.string().optional(),
194
+ attendees: z.array(z.string().email()).optional().describe("Attendee emails."),
195
+ calendarId: z.string().optional().describe("Calendar ID (default primary)."),
196
+ account: z.string().optional().describe("Account nickname to use."),
197
+ },
198
+ }, async ({ summary, start, end, description, attendees, calendarId, account }) => withClient(account, (client) => createMeetLink(client, { summary, start, end, description, attendees, calendarId })));
199
+ server.registerTool("google_calendar_get_event", {
200
+ title: "Get calendar event",
201
+ description: "Fetch a single event by ID.",
202
+ inputSchema: {
203
+ eventId: z.string().describe("Event ID."),
204
+ calendarId: z.string().optional().describe("Calendar ID (default primary)."),
205
+ account: z.string().optional().describe("Account nickname to use."),
206
+ },
207
+ }, async ({ eventId, calendarId, account }) => withClient(account, (client) => getEvent(client, { eventId, calendarId })));
208
+ server.registerTool("google_calendar_update_event", {
209
+ title: "Update calendar event",
210
+ description: "Update fields of an existing event (partial update).",
211
+ inputSchema: {
212
+ eventId: z.string().describe("Event ID."),
213
+ summary: z.string().optional(),
214
+ description: z.string().optional(),
215
+ location: z.string().optional(),
216
+ start: z.string().optional().describe("New start RFC3339 datetime."),
217
+ end: z.string().optional().describe("New end RFC3339 datetime."),
218
+ attendees: z.array(z.string().email()).optional().describe("Full attendee list."),
219
+ calendarId: z.string().optional().describe("Calendar ID (default primary)."),
220
+ account: z.string().optional().describe("Account nickname to use."),
221
+ },
222
+ }, async ({ eventId, summary, description, location, start, end, attendees, calendarId, account }) => withClient(account, (client) => updateEvent(client, { eventId, summary, description, location, start, end, attendees, calendarId })));
223
+ server.registerTool("google_calendar_delete_event", {
224
+ title: "Delete calendar event",
225
+ description: "Delete an event by ID.",
226
+ inputSchema: {
227
+ eventId: z.string().describe("Event ID."),
228
+ calendarId: z.string().optional().describe("Calendar ID (default primary)."),
229
+ account: z.string().optional().describe("Account nickname to use."),
230
+ },
231
+ }, async ({ eventId, calendarId, account }) => {
232
+ try {
233
+ const client = await authManager.getClient(account);
234
+ await deleteEvent(client, { eventId, calendarId });
235
+ return ok({ status: "deleted", eventId });
236
+ }
237
+ catch (error) {
238
+ return err(error);
239
+ }
240
+ });
241
+ // ---- Drive --------------------------------------------------------------
242
+ server.registerTool("google_drive_list", {
243
+ title: "List Drive files",
244
+ description: "List files in Drive, newest first, with an optional query.",
245
+ inputSchema: {
246
+ query: z.string().optional().describe("Drive query (e.g. 'name contains \"report\"')."),
247
+ pageSize: z.number().min(1).max(100).optional().describe("Max files (default 25)."),
248
+ account: z.string().optional().describe("Account nickname to use."),
249
+ },
250
+ }, async ({ query, pageSize, account }) => withClient(account, (client) => listDriveFiles(client, { query, pageSize })));
251
+ server.registerTool("google_drive_get", {
252
+ title: "Get Drive file",
253
+ description: "Get metadata for a single file by ID.",
254
+ inputSchema: {
255
+ fileId: z.string().describe("Drive file ID."),
256
+ account: z.string().optional().describe("Account nickname to use."),
257
+ },
258
+ }, async ({ fileId, account }) => withClient(account, (client) => getDriveFile(client, { fileId })));
259
+ server.registerTool("google_drive_upload", {
260
+ title: "Create/upload Drive file",
261
+ description: "Create a file in Drive, optionally with text content (blank Google-native file if omitted).",
262
+ inputSchema: {
263
+ name: z.string().describe("File name."),
264
+ mimeType: z.string().describe("MIME type (e.g. text/plain, application/vnd.google-apps.document)."),
265
+ content: z.string().optional().describe("Text content to upload."),
266
+ parentFolderId: z.string().optional().describe("Parent folder ID."),
267
+ account: z.string().optional().describe("Account nickname to use."),
268
+ },
269
+ }, async ({ name, mimeType, content, parentFolderId, account }) => withClient(account, (client) => uploadDriveFile(client, { name, mimeType, content, parentFolderId })));
270
+ server.registerTool("google_drive_update", {
271
+ title: "Update Drive file",
272
+ description: "Rename a file and/or replace its content.",
273
+ inputSchema: {
274
+ fileId: z.string().describe("Drive file ID."),
275
+ name: z.string().optional().describe("New name."),
276
+ mimeType: z.string().optional(),
277
+ content: z.string().optional().describe("New content."),
278
+ account: z.string().optional().describe("Account nickname to use."),
279
+ },
280
+ }, async ({ fileId, name, mimeType, content, account }) => withClient(account, (client) => updateDriveFile(client, { fileId, name, mimeType, content })));
281
+ server.registerTool("google_drive_delete", {
282
+ title: "Delete Drive file",
283
+ description: "Permanently delete a file from Drive.",
284
+ inputSchema: {
285
+ fileId: z.string().describe("Drive file ID."),
286
+ account: z.string().optional().describe("Account nickname to use."),
287
+ },
288
+ }, async ({ fileId, account }) => {
289
+ try {
290
+ const client = await authManager.getClient(account);
291
+ await deleteDriveFile(client, { fileId });
292
+ return ok({ status: "deleted", fileId });
293
+ }
294
+ catch (error) {
295
+ return err(error);
296
+ }
297
+ });
298
+ server.registerTool("google_drive_share", {
299
+ title: "Share Drive file",
300
+ description: "Share a file with a user by email and role.",
301
+ inputSchema: {
302
+ fileId: z.string().describe("Drive file ID."),
303
+ email: z.string().email().describe("Recipient email."),
304
+ role: z.enum(["reader", "writer", "commenter"]).describe("Access role."),
305
+ sendNotificationEmail: z.boolean().optional().describe("Email the recipient (default true)."),
306
+ account: z.string().optional().describe("Account nickname to use."),
307
+ },
308
+ }, async ({ fileId, email, role, sendNotificationEmail, account }) => withClient(account, (client) => shareDriveFile(client, { fileId, email, role, sendNotificationEmail })));
309
+ // ---- Contacts -----------------------------------------------------------
310
+ server.registerTool("google_contacts_list", {
311
+ title: "List contacts",
312
+ description: "List the account's contacts with names, emails and phones.",
313
+ inputSchema: {
314
+ pageSize: z.number().min(1).max(100).optional().describe("Max contacts (default 100)."),
315
+ account: z.string().optional().describe("Account nickname to use."),
316
+ },
317
+ }, async ({ pageSize, account }) => withClient(account, (client) => listContacts(client, { pageSize })));
318
+ server.registerTool("google_contacts_search", {
319
+ title: "Search contacts",
320
+ description: "Search contacts (including non-connected) by name, email or phone.",
321
+ inputSchema: {
322
+ query: z.string().describe("Search text."),
323
+ account: z.string().optional().describe("Account nickname to use."),
324
+ },
325
+ }, async ({ query, account }) => withClient(account, (client) => searchContacts(client, { query })));
326
+ server.registerTool("google_contacts_create", {
327
+ title: "Create contact",
328
+ description: "Create a new contact with a name and optional email/phone.",
329
+ inputSchema: {
330
+ name: z.string().describe("Contact full name."),
331
+ email: z.string().email().optional(),
332
+ phone: z.string().optional(),
333
+ account: z.string().optional().describe("Account nickname to use."),
334
+ },
335
+ }, async ({ name, email, phone, account }) => withClient(account, (client) => createContact(client, { name, email, phone })));
336
+ // ---- Tasks --------------------------------------------------------------
337
+ server.registerTool("google_tasks_list_lists", {
338
+ title: "List task lists",
339
+ description: "List the account's Google Tasks lists.",
340
+ inputSchema: {
341
+ account: z.string().optional().describe("Account nickname to use."),
342
+ },
343
+ }, async ({ account }) => withClient(account, (client) => listTaskLists(client)));
344
+ server.registerTool("google_tasks_list", {
345
+ title: "List tasks",
346
+ description: "List tasks in a task list (default list if not specified).",
347
+ inputSchema: {
348
+ tasklistId: z.string().optional().describe("Task list ID (default @default)."),
349
+ account: z.string().optional().describe("Account nickname to use."),
350
+ },
351
+ }, async ({ tasklistId, account }) => withClient(account, (client) => listTasks(client, { tasklistId })));
352
+ server.registerTool("google_tasks_create", {
353
+ title: "Create task",
354
+ description: "Create a task, optionally with notes and due date.",
355
+ inputSchema: {
356
+ title: z.string().describe("Task title."),
357
+ notes: z.string().optional(),
358
+ due: z.string().optional().describe("Due date (RFC3339, e.g. 2026-08-15T17:00:00Z)."),
359
+ tasklistId: z.string().optional().describe("Task list ID (default @default)."),
360
+ account: z.string().optional().describe("Account nickname to use."),
361
+ },
362
+ }, async ({ title, notes, due, tasklistId, account }) => withClient(account, (client) => createTask(client, { title, notes, due, tasklistId })));
363
+ server.registerTool("google_tasks_complete", {
364
+ title: "Complete task",
365
+ description: "Mark a task as completed.",
366
+ inputSchema: {
367
+ taskId: z.string().describe("Task ID."),
368
+ tasklistId: z.string().optional().describe("Task list ID (default @default)."),
369
+ account: z.string().optional().describe("Account nickname to use."),
370
+ },
371
+ }, async ({ taskId, tasklistId, account }) => withClient(account, (client) => completeTask(client, { taskId, tasklistId })));
372
+ server.registerTool("google_tasks_delete", {
373
+ title: "Delete task",
374
+ description: "Delete a task.",
375
+ inputSchema: {
376
+ taskId: z.string().describe("Task ID."),
377
+ tasklistId: z.string().optional().describe("Task list ID (default @default)."),
378
+ account: z.string().optional().describe("Account nickname to use."),
379
+ },
380
+ }, async ({ taskId, tasklistId, account }) => {
381
+ try {
382
+ const client = await authManager.getClient(account);
383
+ await deleteTask(client, { taskId, tasklistId });
384
+ return ok({ status: "deleted", taskId });
385
+ }
386
+ catch (error) {
387
+ return err(error);
388
+ }
389
+ });
390
+ // ---- Sheets --------------------------------------------------------------
391
+ server.registerTool("google_sheets_get", {
392
+ title: "Get spreadsheet",
393
+ description: "Get spreadsheet metadata and optionally cell values from a range.",
394
+ inputSchema: {
395
+ spreadsheetId: z.string().describe("Spreadsheet ID (from the URL)."),
396
+ range: z.string().optional().describe("A1 range to also read values from, e.g. Sheet1!A1:B5."),
397
+ account: z.string().optional().describe("Account nickname to use."),
398
+ },
399
+ }, async ({ spreadsheetId, range, account }) => withClient(account, (client) => getSpreadsheet(client, { spreadsheetId, range })));
400
+ server.registerTool("google_sheets_read", {
401
+ title: "Read spreadsheet range",
402
+ description: "Read cell values from a range as rows of strings.",
403
+ inputSchema: {
404
+ spreadsheetId: z.string().describe("Spreadsheet ID."),
405
+ range: z.string().describe("A1 notation, e.g. Sheet1!A1:C10."),
406
+ majorDimension: z.enum(["ROWS", "COLUMNS"]).optional().describe("Read direction (default ROWS)."),
407
+ account: z.string().optional().describe("Account nickname to use."),
408
+ },
409
+ }, async ({ spreadsheetId, range, majorDimension, account }) => withClient(account, (client) => readSheetRange(client, { spreadsheetId, range, majorDimension })));
410
+ server.registerTool("google_sheets_write", {
411
+ title: "Write to spreadsheet",
412
+ description: "Write rows of values starting at a range top-left cell (overwrites in place).",
413
+ inputSchema: {
414
+ spreadsheetId: z.string().describe("Spreadsheet ID."),
415
+ range: z.string().describe("A1 notation of the top-left cell, e.g. Sheet1!A1."),
416
+ values: z.array(z.array(z.string())).describe("Rows of values to write."),
417
+ valueInputOption: z.enum(["RAW", "USER_ENTERED"]).optional().describe("How to interpret values (default USER_ENTERED)."),
418
+ account: z.string().optional().describe("Account nickname to use."),
419
+ },
420
+ }, async ({ spreadsheetId, range, values, valueInputOption, account }) => withClient(account, (client) => writeSheetRange(client, { spreadsheetId, range, values, valueInputOption })));
421
+ server.registerTool("google_sheets_append", {
422
+ title: "Append to spreadsheet",
423
+ description: "Append rows below the existing data in a sheet.",
424
+ inputSchema: {
425
+ spreadsheetId: z.string().describe("Spreadsheet ID."),
426
+ range: z.string().describe("A1 range of the table to append to, e.g. Sheet1!A1."),
427
+ values: z.array(z.array(z.string())).describe("Rows of values to append."),
428
+ valueInputOption: z.enum(["RAW", "USER_ENTERED"]).optional().describe("How to interpret values (default USER_ENTERED)."),
429
+ account: z.string().optional().describe("Account nickname to use."),
430
+ },
431
+ }, async ({ spreadsheetId, range, values, valueInputOption, account }) => withClient(account, (client) => appendSheetRange(client, { spreadsheetId, range, values, valueInputOption })));
432
+ server.registerTool("google_sheets_create", {
433
+ title: "Create spreadsheet",
434
+ description: "Create a new spreadsheet, optionally with pre-made sheet tabs.",
435
+ inputSchema: {
436
+ title: z.string().describe("Spreadsheet title."),
437
+ sheets: z.array(z.string()).optional().describe("Sheet tab names to create."),
438
+ account: z.string().optional().describe("Account nickname to use."),
439
+ },
440
+ }, async ({ title, sheets, account }) => withClient(account, (client) => createSpreadsheet(client, { title, sheets })));
441
+ server.registerTool("google_sheets_batch_update", {
442
+ title: "Batch update spreadsheet",
443
+ description: "Send raw Sheets batchUpdate requests (add/delete sheets, formatting, etc.).",
444
+ inputSchema: {
445
+ spreadsheetId: z.string().describe("Spreadsheet ID."),
446
+ requests: z.array(z.record(z.any())).describe("Sheets API batchUpdate requests."),
447
+ account: z.string().optional().describe("Account nickname to use."),
448
+ },
449
+ }, async ({ spreadsheetId, requests, account }) => withClient(account, (client) => batchUpdateSheet(client, { spreadsheetId, requests })));
450
+ // ---- Docs ---------------------------------------------------------------
451
+ server.registerTool("google_docs_get", {
452
+ title: "Get document",
453
+ description: "Get the full Google Docs document (structural JSON).",
454
+ inputSchema: {
455
+ documentId: z.string().describe("Document ID."),
456
+ account: z.string().optional().describe("Account nickname to use."),
457
+ },
458
+ }, async ({ documentId, account }) => withClient(account, (client) => getDocument(client, { documentId })));
459
+ server.registerTool("google_docs_read", {
460
+ title: "Read document text",
461
+ description: "Read a Google Docs document as plain text.",
462
+ inputSchema: {
463
+ documentId: z.string().describe("Document ID."),
464
+ account: z.string().optional().describe("Account nickname to use."),
465
+ },
466
+ }, async ({ documentId, account }) => withClient(account, (client) => getDocumentText(client, { documentId })));
467
+ server.registerTool("google_docs_create", {
468
+ title: "Create document",
469
+ description: "Create a new Google Docs document with a title.",
470
+ inputSchema: {
471
+ title: z.string().describe("Document title."),
472
+ account: z.string().optional().describe("Account nickname to use."),
473
+ },
474
+ }, async ({ title, account }) => withClient(account, (client) => createDocument(client, { title })));
475
+ server.registerTool("google_docs_insert_text", {
476
+ title: "Insert text in document",
477
+ description: "Insert text into a document at an index or at the end.",
478
+ inputSchema: {
479
+ documentId: z.string().describe("Document ID."),
480
+ text: z.string().describe("Text to insert."),
481
+ index: z.number().int().min(0).optional().describe("Character index to insert at (default end of document)."),
482
+ account: z.string().optional().describe("Account nickname to use."),
483
+ },
484
+ }, async ({ documentId, text, index, account }) => withClient(account, (client) => insertText(client, { documentId, text, index })));
485
+ server.registerTool("google_docs_replace_text", {
486
+ title: "Replace text in document",
487
+ description: "Replace all occurrences of a string in a document (template filling).",
488
+ inputSchema: {
489
+ documentId: z.string().describe("Document ID."),
490
+ find: z.string().describe("Text to find (e.g. {{name}})."),
491
+ replace: z.string().describe("Replacement text."),
492
+ matchCase: z.boolean().optional().describe("Match case (default true)."),
493
+ account: z.string().optional().describe("Account nickname to use."),
494
+ },
495
+ }, async ({ documentId, find, replace, matchCase, account }) => withClient(account, (client) => replaceAllText(client, { documentId, find, replace, matchCase })));
496
+ server.registerTool("google_docs_batch_update", {
497
+ title: "Batch update document",
498
+ description: "Send raw Docs batchUpdate requests (styles, tables, headers, etc.).",
499
+ inputSchema: {
500
+ documentId: z.string().describe("Document ID."),
501
+ requests: z.array(z.record(z.any())).describe("Docs API batchUpdate requests."),
502
+ account: z.string().optional().describe("Account nickname to use."),
503
+ },
504
+ }, async ({ documentId, requests, account }) => withClient(account, (client) => batchUpdateDocument(client, { documentId, requests })));
505
+ // ---- Slides -------------------------------------------------------------
506
+ server.registerTool("google_slides_get", {
507
+ title: "Get presentation",
508
+ description: "Get a Google Slides presentation (structural JSON).",
509
+ inputSchema: {
510
+ presentationId: z.string().describe("Presentation ID."),
511
+ account: z.string().optional().describe("Account nickname to use."),
512
+ },
513
+ }, async ({ presentationId, account }) => withClient(account, (client) => getPresentation(client, { presentationId })));
514
+ server.registerTool("google_slides_create", {
515
+ title: "Create presentation",
516
+ description: "Create a new Google Slides presentation with a title.",
517
+ inputSchema: {
518
+ title: z.string().describe("Presentation title."),
519
+ account: z.string().optional().describe("Account nickname to use."),
520
+ },
521
+ }, async ({ title, account }) => withClient(account, (client) => createPresentation(client, { title })));
522
+ server.registerTool("google_slides_replace_text", {
523
+ title: "Replace text in presentation",
524
+ description: "Replace all occurrences of a string across a presentation (template filling).",
525
+ inputSchema: {
526
+ presentationId: z.string().describe("Presentation ID."),
527
+ find: z.string().describe("Text to find (e.g. {{name}})."),
528
+ replace: z.string().describe("Replacement text."),
529
+ matchCase: z.boolean().optional().describe("Match case (default true)."),
530
+ account: z.string().optional().describe("Account nickname to use."),
531
+ },
532
+ }, async ({ presentationId, find, replace, matchCase, account }) => withClient(account, (client) => replaceSlidesText(client, { presentationId, find, replace, matchCase })));
533
+ server.registerTool("google_slides_add_slide", {
534
+ title: "Add slide",
535
+ description: "Add a blank slide to a presentation.",
536
+ inputSchema: {
537
+ presentationId: z.string().describe("Presentation ID."),
538
+ account: z.string().optional().describe("Account nickname to use."),
539
+ },
540
+ }, async ({ presentationId, account }) => withClient(account, (client) => createSlide(client, { presentationId })));
541
+ server.registerTool("google_slides_delete_slide", {
542
+ title: "Delete slide",
543
+ description: "Delete a slide by object ID.",
544
+ inputSchema: {
545
+ presentationId: z.string().describe("Presentation ID."),
546
+ slideObjectId: z.string().describe("Slide object ID to delete."),
547
+ account: z.string().optional().describe("Account nickname to use."),
548
+ },
549
+ }, async ({ presentationId, slideObjectId, account }) => withClient(account, (client) => deleteSlide(client, { presentationId, slideObjectId })));
550
+ // ---- YouTube ------------------------------------------------------------
551
+ server.registerTool("google_youtube_search", {
552
+ title: "Search YouTube videos",
553
+ description: "Search YouTube for videos and return titles, IDs and channels.",
554
+ inputSchema: {
555
+ query: z.string().describe("Search query."),
556
+ maxResults: z.number().min(1).max(50).optional().describe("Max results (default 10)."),
557
+ account: z.string().optional().describe("Account nickname to use."),
558
+ },
559
+ }, async ({ query, maxResults, account }) => withClient(account, (client) => searchVideos(client, { query, maxResults })));
560
+ server.registerTool("google_youtube_get_video", {
561
+ title: "Get YouTube video details",
562
+ description: "Get details, statistics and content details for a video.",
563
+ inputSchema: {
564
+ videoId: z.string().describe("YouTube video ID."),
565
+ account: z.string().optional().describe("Account nickname to use."),
566
+ },
567
+ }, async ({ videoId, account }) => withClient(account, (client) => getVideo(client, { videoId })));
568
+ server.registerTool("google_youtube_my_videos", {
569
+ title: "List my YouTube videos",
570
+ description: "List the user's uploaded videos.",
571
+ inputSchema: {
572
+ maxResults: z.number().min(1).max(50).optional().describe("Max videos (default 25)."),
573
+ account: z.string().optional().describe("Account nickname to use."),
574
+ },
575
+ }, async ({ maxResults, account }) => withClient(account, (client) => getMyVideos(client, { maxResults })));
576
+ server.registerTool("google_youtube_list_playlists", {
577
+ title: "List my playlists",
578
+ description: "List the user's YouTube playlists.",
579
+ inputSchema: {
580
+ maxResults: z.number().min(1).max(50).optional().describe("Max playlists (default 25)."),
581
+ account: z.string().optional().describe("Account nickname to use."),
582
+ },
583
+ }, async ({ maxResults, account }) => withClient(account, (client) => listPlaylists(client, { maxResults })));
584
+ server.registerTool("google_youtube_create_playlist", {
585
+ title: "Create YouTube playlist",
586
+ description: "Create a private playlist for the user.",
587
+ inputSchema: {
588
+ title: z.string().describe("Playlist title."),
589
+ description: z.string().optional().describe("Playlist description."),
590
+ privacyStatus: z.enum(["private", "public", "unlisted"]).optional().describe("Privacy (default private)."),
591
+ account: z.string().optional().describe("Account nickname to use."),
592
+ },
593
+ }, async ({ title, description, privacyStatus, account }) => withClient(account, (client) => createPlaylist(client, { title, description, privacyStatus })));
594
+ server.registerTool("google_youtube_delete_playlist", {
595
+ title: "Delete YouTube playlist",
596
+ description: "Delete a playlist by ID.",
597
+ inputSchema: {
598
+ playlistId: z.string().describe("Playlist ID."),
599
+ account: z.string().optional().describe("Account nickname to use."),
600
+ },
601
+ }, async ({ playlistId, account }) => withClient(account, (client) => deletePlaylist(client, { playlistId })));
602
+ server.registerTool("google_youtube_add_to_playlist", {
603
+ title: "Add video to playlist",
604
+ description: "Add a video to a playlist.",
605
+ inputSchema: {
606
+ playlistId: z.string().describe("Playlist ID."),
607
+ videoId: z.string().describe("Video ID to add."),
608
+ account: z.string().optional().describe("Account nickname to use."),
609
+ },
610
+ }, async ({ playlistId, videoId, account }) => withClient(account, (client) => addVideoToPlaylist(client, { playlistId, videoId })));
611
+ server.registerTool("google_youtube_subscriptions", {
612
+ title: "List channel subscriptions",
613
+ description: "List the channels the user subscribes to.",
614
+ inputSchema: {
615
+ maxResults: z.number().min(1).max(50).optional().describe("Max results (default 50)."),
616
+ account: z.string().optional().describe("Account nickname to use."),
617
+ },
618
+ }, async ({ maxResults, account }) => withClient(account, (client) => listSubscriptions(client, { maxResults })));
619
+ // ---- Forms --------------------------------------------------------------
620
+ server.registerTool("google_forms_get", {
621
+ title: "Get form",
622
+ description: "Get a Google Form's structure and questions.",
623
+ inputSchema: {
624
+ formId: z.string().describe("Form ID (from the URL)."),
625
+ account: z.string().optional().describe("Account nickname to use."),
626
+ },
627
+ }, async ({ formId, account }) => withClient(account, (client) => getForm(client, { formId })));
628
+ server.registerTool("google_forms_responses", {
629
+ title: "Get form responses",
630
+ description: "List responses submitted to a form.",
631
+ inputSchema: {
632
+ formId: z.string().describe("Form ID."),
633
+ pageSize: z.number().min(1).max(100).optional().describe("Max responses (default 100)."),
634
+ account: z.string().optional().describe("Account nickname to use."),
635
+ },
636
+ }, async ({ formId, pageSize, account }) => withClient(account, (client) => getFormResponses(client, { formId, pageSize })));
637
+ server.registerTool("google_forms_create", {
638
+ title: "Create form",
639
+ description: "Create a new Google Form with a title.",
640
+ inputSchema: {
641
+ title: z.string().describe("Form title."),
642
+ account: z.string().optional().describe("Account nickname to use."),
643
+ },
644
+ }, async ({ title, account }) => withClient(account, (client) => createForm(client, { title })));
645
+ server.registerTool("google_forms_add_question", {
646
+ title: "Add form question",
647
+ description: "Add a text or multiple-choice question to a form.",
648
+ inputSchema: {
649
+ formId: z.string().describe("Form ID."),
650
+ title: z.string().describe("Question text."),
651
+ description: z.string().optional().describe("Optional help text."),
652
+ type: z.enum(["text", "multiple_choice"]).optional().describe("Question type (default text)."),
653
+ options: z.array(z.string()).optional().describe("Choices for multiple_choice."),
654
+ required: z.boolean().optional().describe("Whether the question is required (default false)."),
655
+ account: z.string().optional().describe("Account nickname to use."),
656
+ },
657
+ }, async ({ formId, title, description, type, options, required, account }) => withClient(account, (client) => addQuestion(client, { formId, title, description, type, options, required })));
658
+ }
659
+ //# sourceMappingURL=index.js.map