@dguido/google-workspace-mcp 3.0.2 → 3.0.3

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.
package/dist/index.js CHANGED
@@ -5025,7 +5025,7 @@ var calendarTools = [
5025
5025
  outputSchema: {
5026
5026
  type: "object",
5027
5027
  properties: {
5028
- deleted: { type: "boolean", description: "Whether deletion succeeded" },
5028
+ deleted: { type: "number", description: "Number of events deleted" },
5029
5029
  eventId: { type: "string", description: "Deleted event ID" }
5030
5030
  }
5031
5031
  }
@@ -5316,9 +5316,13 @@ var gmailTools = [
5316
5316
  outputSchema: {
5317
5317
  type: "object",
5318
5318
  properties: {
5319
- id: { type: "string", description: "Thread ID" },
5320
- messageCount: { type: "number", description: "Number of messages in thread" },
5321
- labelIds: { type: "array", items: { type: "string" }, description: "Current labels" }
5319
+ id: { type: "string", description: "First modified thread ID (for batch: first in list)" },
5320
+ messageCount: { type: "number", description: "Number of threads modified" },
5321
+ labelIds: {
5322
+ type: "array",
5323
+ items: { type: "string" },
5324
+ description: "Labels that were added"
5325
+ }
5322
5326
  }
5323
5327
  }
5324
5328
  },
@@ -5389,7 +5393,7 @@ var gmailTools = [
5389
5393
  outputSchema: {
5390
5394
  type: "object",
5391
5395
  properties: {
5392
- deleted: { type: "boolean", description: "Whether the deletion succeeded" },
5396
+ deleted: { type: "number", description: "Number of labels deleted" },
5393
5397
  labelId: { type: "string", description: "Deleted label ID" }
5394
5398
  }
5395
5399
  }
@@ -5549,7 +5553,7 @@ var gmailTools = [
5549
5553
  outputSchema: {
5550
5554
  type: "object",
5551
5555
  properties: {
5552
- deleted: { type: "boolean", description: "Whether the deletion succeeded" },
5556
+ deleted: { type: "number", description: "Number of filters deleted" },
5553
5557
  filterId: { type: "string", description: "Deleted filter ID" }
5554
5558
  }
5555
5559
  }
@@ -7630,10 +7634,11 @@ ${toToon({ files })}`;
7630
7634
 
7631
7635
  More results available. Use pageToken: ${res.data.nextPageToken}`;
7632
7636
  }
7633
- return structuredResponse(textResponse, {
7634
- files,
7635
- nextPageToken: res.data.nextPageToken || null
7636
- });
7637
+ const responseData = { files };
7638
+ if (res.data.nextPageToken) {
7639
+ responseData.nextPageToken = res.data.nextPageToken;
7640
+ }
7641
+ return structuredResponse(textResponse, responseData);
7637
7642
  }
7638
7643
  async function handleCreateTextFile(drive2, args) {
7639
7644
  const validation = validateArgs(CreateTextFileSchema, args);
@@ -7751,19 +7756,32 @@ async function handleListFolder(drive2, args) {
7751
7756
  supportsAllDrives: true
7752
7757
  });
7753
7758
  const files = res.data.files || [];
7754
- const formattedFiles = files.map((file) => {
7759
+ const items = [];
7760
+ const formattedLines = [];
7761
+ for (const file of files) {
7762
+ items.push({
7763
+ id: file.id,
7764
+ name: file.name,
7765
+ mimeType: file.mimeType,
7766
+ modifiedTime: file.modifiedTime,
7767
+ size: file.size
7768
+ });
7755
7769
  const isFolder = file.mimeType === FOLDER_MIME_TYPE;
7756
- return `${isFolder ? "\u{1F4C1}" : "\u{1F4C4}"} ${file.name} (ID: ${file.id})`;
7757
- }).join("\n");
7758
- let response = `Contents of folder:
7770
+ formattedLines.push(`${isFolder ? "\u{1F4C1}" : "\u{1F4C4}"} ${file.name} (ID: ${file.id})`);
7771
+ }
7772
+ let textResponse = `Contents of folder:
7759
7773
 
7760
- ${formattedFiles}`;
7774
+ ${formattedLines.join("\n")}`;
7761
7775
  if (res.data.nextPageToken) {
7762
- response += `
7776
+ textResponse += `
7763
7777
 
7764
7778
  More items available. Use pageToken: ${res.data.nextPageToken}`;
7765
7779
  }
7766
- return successResponse(response);
7780
+ const responseData = { items };
7781
+ if (res.data.nextPageToken) {
7782
+ responseData.nextPageToken = res.data.nextPageToken;
7783
+ }
7784
+ return structuredResponse(textResponse, responseData);
7767
7785
  } catch (error) {
7768
7786
  if (error instanceof Error && error.message.includes("not found")) {
7769
7787
  return errorResponse(`Folder not found: ${targetFolderId}`, { code: "NOT_FOUND" });
@@ -8779,8 +8797,7 @@ async function handleListTrash(drive2, args) {
8779
8797
  const files = response.data.files || [];
8780
8798
  if (files.length === 0) {
8781
8799
  return structuredResponse("Trash is empty", {
8782
- files: [],
8783
- nextPageToken: null
8800
+ files: []
8784
8801
  });
8785
8802
  }
8786
8803
  const fileData = files.map((f) => ({
@@ -8793,10 +8810,11 @@ async function handleListTrash(drive2, args) {
8793
8810
  const textResponse = `Trash contents (${files.length} items):
8794
8811
 
8795
8812
  ${toToon({ files: fileData })}` + (response.data.nextPageToken ? "\n\n(More items available - use nextPageToken to continue)" : "");
8796
- return structuredResponse(textResponse, {
8797
- files: fileData,
8798
- nextPageToken: response.data.nextPageToken || null
8799
- });
8813
+ const responseData = { files: fileData };
8814
+ if (response.data.nextPageToken) {
8815
+ responseData.nextPageToken = response.data.nextPageToken;
8816
+ }
8817
+ return structuredResponse(textResponse, responseData);
8800
8818
  }
8801
8819
  async function handleRestoreFromTrash(drive2, args) {
8802
8820
  const validation = validateArgs(RestoreFromTrashSchema, args);
@@ -9098,10 +9116,15 @@ async function handleCreateGoogleDoc(drive2, docs, args) {
9098
9116
  ]
9099
9117
  }
9100
9118
  });
9101
- return successResponse(
9119
+ return structuredResponse(
9102
9120
  `Created Google Doc: ${doc.name}
9103
9121
  ID: ${doc.id}
9104
- Link: ${doc.webViewLink}`
9122
+ Link: ${doc.webViewLink}`,
9123
+ {
9124
+ id: doc.id,
9125
+ name: doc.name,
9126
+ webViewLink: doc.webViewLink
9127
+ }
9105
9128
  );
9106
9129
  }
9107
9130
  async function handleUpdateGoogleDoc(docs, args) {
@@ -9148,7 +9171,10 @@ async function handleUpdateGoogleDoc(docs, args) {
9148
9171
  ]
9149
9172
  }
9150
9173
  });
9151
- return successResponse(`Updated Google Doc: ${document.data.title}`);
9174
+ return structuredResponse(`Updated Google Doc: ${document.data.title}`, {
9175
+ title: document.data.title,
9176
+ updated: true
9177
+ });
9152
9178
  }
9153
9179
  async function handleGetGoogleDocContent(drive2, docs, args) {
9154
9180
  const validation = validateArgs(GetGoogleDocContentSchema, args);
@@ -9239,8 +9265,12 @@ ${data.text}` : data.text;
9239
9265
  documentId: data.documentId,
9240
9266
  textLength: data.text.length
9241
9267
  });
9242
- return successResponse(
9243
- `Appended ${data.text.length} characters to document "${document.data.title}"`
9268
+ return structuredResponse(
9269
+ `Appended ${data.text.length} characters to document "${document.data.title}"`,
9270
+ {
9271
+ title: document.data.title,
9272
+ charactersAdded: data.text.length
9273
+ }
9244
9274
  );
9245
9275
  }
9246
9276
  async function handleInsertTextInDoc(docs, args) {
@@ -9272,8 +9302,13 @@ async function handleInsertTextInDoc(docs, args) {
9272
9302
  index: data.index,
9273
9303
  textLength: data.text.length
9274
9304
  });
9275
- return successResponse(
9276
- `Inserted ${data.text.length} characters at index ${data.index} in "${document.data.title}"`
9305
+ return structuredResponse(
9306
+ `Inserted ${data.text.length} characters at index ${data.index} in "${document.data.title}"`,
9307
+ {
9308
+ title: document.data.title,
9309
+ index: data.index,
9310
+ charactersInserted: data.text.length
9311
+ }
9277
9312
  );
9278
9313
  }
9279
9314
  async function handleDeleteTextInDoc(docs, args) {
@@ -9308,8 +9343,14 @@ async function handleDeleteTextInDoc(docs, args) {
9308
9343
  startIndex: data.startIndex,
9309
9344
  endIndex: data.endIndex
9310
9345
  });
9311
- return successResponse(
9312
- `Deleted ${charsToDelete} characters (indices ${data.startIndex}-${data.endIndex}) from "${document.data.title}"`
9346
+ return structuredResponse(
9347
+ `Deleted ${charsToDelete} characters (indices ${data.startIndex}-${data.endIndex}) from "${document.data.title}"`,
9348
+ {
9349
+ title: document.data.title,
9350
+ startIndex: data.startIndex,
9351
+ endIndex: data.endIndex,
9352
+ charactersDeleted: charsToDelete
9353
+ }
9313
9354
  );
9314
9355
  }
9315
9356
  async function handleReplaceTextInDoc(docs, args) {
@@ -9339,12 +9380,20 @@ async function handleReplaceTextInDoc(docs, args) {
9339
9380
  occurrences: occurrencesChanged
9340
9381
  });
9341
9382
  if (occurrencesChanged === 0) {
9342
- return successResponse(
9343
- `No occurrences of "${data.searchText}" found in "${document.data.title}"`
9383
+ return structuredResponse(
9384
+ `No occurrences of "${data.searchText}" found in "${document.data.title}"`,
9385
+ {
9386
+ title: document.data.title,
9387
+ occurrencesChanged: 0
9388
+ }
9344
9389
  );
9345
9390
  }
9346
- return successResponse(
9347
- `Replaced ${occurrencesChanged} occurrence(s) of "${data.searchText}" with "${data.replaceText}" in "${document.data.title}"`
9391
+ return structuredResponse(
9392
+ `Replaced ${occurrencesChanged} occurrence(s) of "${data.searchText}" with "${data.replaceText}" in "${document.data.title}"`,
9393
+ {
9394
+ title: document.data.title,
9395
+ occurrencesChanged
9396
+ }
9348
9397
  );
9349
9398
  }
9350
9399
  function buildDocTextStyle(data) {
@@ -9452,8 +9501,13 @@ async function handleFormatGoogleDocRange(docs, args) {
9452
9501
  endIndex,
9453
9502
  formatsApplied
9454
9503
  });
9455
- return successResponse(
9456
- `Applied formatting to range ${startIndex}-${endIndex}: ${formatsApplied.join(", ")}`
9504
+ return structuredResponse(
9505
+ `Applied formatting to range ${startIndex}-${endIndex}: ${formatsApplied.join(", ")}`,
9506
+ {
9507
+ startIndex,
9508
+ endIndex,
9509
+ formatsApplied
9510
+ }
9457
9511
  );
9458
9512
  }
9459
9513
 
@@ -9563,9 +9617,13 @@ async function handleCreateGoogleSheet(drive2, sheets, args) {
9563
9617
  valueInputOption: data.valueInputOption || "RAW",
9564
9618
  requestBody: { values: data.data }
9565
9619
  });
9566
- return successResponse(
9620
+ return structuredResponse(
9567
9621
  `Created Google Sheet: ${data.name}
9568
- ID: ${spreadsheet.data.spreadsheetId}`
9622
+ ID: ${spreadsheet.data.spreadsheetId}`,
9623
+ {
9624
+ id: spreadsheet.data.spreadsheetId,
9625
+ name: data.name
9626
+ }
9569
9627
  );
9570
9628
  }
9571
9629
  async function handleUpdateGoogleSheet(sheets, args) {
@@ -9578,7 +9636,10 @@ async function handleUpdateGoogleSheet(sheets, args) {
9578
9636
  valueInputOption: data.valueInputOption || "RAW",
9579
9637
  requestBody: { values: data.data }
9580
9638
  });
9581
- return successResponse(`Updated Google Sheet range: ${data.range}`);
9639
+ return structuredResponse(`Updated Google Sheet range: ${data.range}`, {
9640
+ range: data.range,
9641
+ updated: true
9642
+ });
9582
9643
  }
9583
9644
  async function handleGetGoogleSheetContent(drive2, sheets, args) {
9584
9645
  const validation = validateArgs(GetGoogleSheetContentSchema, args);
@@ -9754,7 +9815,13 @@ async function handleFormatGoogleSheetCells(sheets, args) {
9754
9815
  spreadsheetId: data.spreadsheetId,
9755
9816
  requestBody: { requests }
9756
9817
  });
9757
- return successResponse(`Formatted cells in range ${data.range} (${appliedFormats.join(", ")})`);
9818
+ return structuredResponse(
9819
+ `Formatted cells in range ${data.range} (${appliedFormats.join(", ")})`,
9820
+ {
9821
+ range: data.range,
9822
+ applied: true
9823
+ }
9824
+ );
9758
9825
  }
9759
9826
  async function handleMergeGoogleSheetCells(sheets, args) {
9760
9827
  const validation = validateArgs(MergeGoogleSheetCellsSchema, args);
@@ -9779,7 +9846,10 @@ async function handleMergeGoogleSheetCells(sheets, args) {
9779
9846
  spreadsheetId: data.spreadsheetId,
9780
9847
  requestBody: { requests }
9781
9848
  });
9782
- return successResponse(`Merged cells in range ${data.range} with type ${data.mergeType}`);
9849
+ return structuredResponse(`Merged cells in range ${data.range} with type ${data.mergeType}`, {
9850
+ range: data.range,
9851
+ mergeType: data.mergeType
9852
+ });
9783
9853
  }
9784
9854
  async function handleAddGoogleSheetConditionalFormat(sheets, args) {
9785
9855
  const validation = validateArgs(AddGoogleSheetConditionalFormatSchema, args);
@@ -9829,7 +9899,10 @@ async function handleAddGoogleSheetConditionalFormat(sheets, args) {
9829
9899
  spreadsheetId: data.spreadsheetId,
9830
9900
  requestBody: { requests }
9831
9901
  });
9832
- return successResponse(`Added conditional formatting to range ${data.range}`);
9902
+ return structuredResponse(`Added conditional formatting to range ${data.range}`, {
9903
+ range: data.range,
9904
+ conditionType: data.condition.type
9905
+ });
9833
9906
  }
9834
9907
  async function getSheetIdByTitle(sheets, spreadsheetId, title) {
9835
9908
  const cached = getCachedSheetMetadata(spreadsheetId, title);
@@ -9907,7 +9980,11 @@ async function createSheetTab(sheets, spreadsheetId, title, index) {
9907
9980
  });
9908
9981
  clearSheetCache(spreadsheetId);
9909
9982
  const newSheetId = response.data.replies?.[0]?.addSheet?.properties?.sheetId;
9910
- return successResponse(`Created new sheet tab "${title}" (ID: ${newSheetId})`);
9983
+ return structuredResponse(`Created new sheet tab "${title}" (ID: ${newSheetId})`, {
9984
+ action: "create",
9985
+ sheetId: newSheetId,
9986
+ title
9987
+ });
9911
9988
  }
9912
9989
  async function deleteSheetTab(sheets, spreadsheetId, title) {
9913
9990
  const sheetId = await getSheetIdByTitle(sheets, spreadsheetId, title);
@@ -9929,7 +10006,11 @@ async function deleteSheetTab(sheets, spreadsheetId, title) {
9929
10006
  throw error;
9930
10007
  }
9931
10008
  clearSheetCache(spreadsheetId);
9932
- return successResponse(`Deleted sheet tab "${title}"`);
10009
+ return structuredResponse(`Deleted sheet tab "${title}"`, {
10010
+ action: "delete",
10011
+ sheetId,
10012
+ title
10013
+ });
9933
10014
  }
9934
10015
  async function renameSheetTab(sheets, spreadsheetId, currentTitle, newTitle) {
9935
10016
  const sheetId = await getSheetIdByTitle(sheets, spreadsheetId, currentTitle);
@@ -9958,7 +10039,11 @@ async function renameSheetTab(sheets, spreadsheetId, currentTitle, newTitle) {
9958
10039
  }
9959
10040
  });
9960
10041
  clearSheetCache(spreadsheetId);
9961
- return successResponse(`Renamed sheet tab "${currentTitle}" to "${newTitle}"`);
10042
+ return structuredResponse(`Renamed sheet tab "${currentTitle}" to "${newTitle}"`, {
10043
+ action: "rename",
10044
+ sheetId,
10045
+ title: newTitle
10046
+ });
9962
10047
  }
9963
10048
 
9964
10049
  // src/handlers/slides.ts
@@ -10034,10 +10119,15 @@ async function handleCreateGoogleSlides(drive2, slides, args) {
10034
10119
  requestBody: { requests: insertTextRequests }
10035
10120
  });
10036
10121
  }
10037
- return successResponse(
10122
+ return structuredResponse(
10038
10123
  `Created Google Slides presentation: ${data.name}
10039
10124
  ID: ${presentation.data.presentationId}
10040
- Link: https://docs.google.com/presentation/d/${presentation.data.presentationId}`
10125
+ Link: https://docs.google.com/presentation/d/${presentation.data.presentationId}`,
10126
+ {
10127
+ id: presentation.data.presentationId,
10128
+ name: data.name,
10129
+ webViewLink: `https://docs.google.com/presentation/d/${presentation.data.presentationId}`
10130
+ }
10041
10131
  );
10042
10132
  }
10043
10133
  async function handleUpdateGoogleSlides(slides, args) {
@@ -10148,9 +10238,13 @@ async function handleUpdateGoogleSlides(slides, args) {
10148
10238
  presentationId: data.presentationId,
10149
10239
  requestBody: { requests }
10150
10240
  });
10151
- return successResponse(
10241
+ return structuredResponse(
10152
10242
  `Updated Google Slides presentation with ${data.slides.length} slide(s)
10153
- Link: https://docs.google.com/presentation/d/${data.presentationId}`
10243
+ Link: https://docs.google.com/presentation/d/${data.presentationId}`,
10244
+ {
10245
+ slideCount: data.slides.length,
10246
+ webViewLink: `https://docs.google.com/presentation/d/${data.presentationId}`
10247
+ }
10154
10248
  );
10155
10249
  }
10156
10250
  async function handleGetGoogleSlidesContent(drive2, slides, args) {
@@ -10322,7 +10416,10 @@ async function handleCreateGoogleSlidesTextBox(slides, args) {
10322
10416
  presentationId: data.presentationId,
10323
10417
  requestBody: { requests }
10324
10418
  });
10325
- return successResponse(`Created text box with ID: ${elementId}`);
10419
+ return structuredResponse(`Created text box with ID: ${elementId}`, {
10420
+ objectId: elementId,
10421
+ pageObjectId: data.pageObjectId
10422
+ });
10326
10423
  }
10327
10424
  async function handleCreateGoogleSlidesShape(slides, args) {
10328
10425
  const validation = validateArgs(CreateGoogleSlidesShapeSchema, args);
@@ -10377,7 +10474,11 @@ async function handleCreateGoogleSlidesShape(slides, args) {
10377
10474
  presentationId: data.presentationId,
10378
10475
  requestBody: { requests }
10379
10476
  });
10380
- return successResponse(`Created ${data.shapeType} shape with ID: ${elementId}`);
10477
+ return structuredResponse(`Created ${data.shapeType} shape with ID: ${elementId}`, {
10478
+ objectId: elementId,
10479
+ pageObjectId: data.pageObjectId,
10480
+ shapeType: data.shapeType
10481
+ });
10381
10482
  }
10382
10483
  async function handleSlidesSpeakerNotes(slides, args) {
10383
10484
  const validation = validateArgs(SlidesSpeakerNotesSchema, args);
@@ -10395,24 +10496,39 @@ async function handleSlidesSpeakerNotes(slides, args) {
10395
10496
  const slide = presentation.data.slides[data.slideIndex];
10396
10497
  const notesObjectId = slide.slideProperties?.notesPage?.notesProperties?.speakerNotesObjectId;
10397
10498
  if (data.action === "get") {
10398
- return getSpeakerNotes(slide, notesObjectId);
10499
+ return getSpeakerNotes(slide, notesObjectId, data.slideIndex);
10399
10500
  } else {
10400
- return updateSpeakerNotes(slides, data.presentationId, slide, notesObjectId, data.notes);
10501
+ return updateSpeakerNotes(
10502
+ slides,
10503
+ data.presentationId,
10504
+ slide,
10505
+ notesObjectId,
10506
+ data.notes,
10507
+ data.slideIndex
10508
+ );
10401
10509
  }
10402
10510
  }
10403
- function getSpeakerNotes(slide, notesObjectId) {
10511
+ function emptyNotesResponse(slideIndex) {
10512
+ return structuredResponse("No speaker notes found for this slide", {
10513
+ action: "get",
10514
+ slideIndex,
10515
+ notes: "",
10516
+ updated: false
10517
+ });
10518
+ }
10519
+ function getSpeakerNotes(slide, notesObjectId, slideIndex) {
10404
10520
  if (!notesObjectId) {
10405
- return successResponse("No speaker notes found for this slide");
10521
+ return emptyNotesResponse(slideIndex);
10406
10522
  }
10407
10523
  const notesPage = slide.slideProperties?.notesPage;
10408
10524
  if (!notesPage || !notesPage.pageElements) {
10409
- return successResponse("No speaker notes found for this slide");
10525
+ return emptyNotesResponse(slideIndex);
10410
10526
  }
10411
10527
  const speakerNotesElement = notesPage.pageElements.find(
10412
10528
  (element) => element.objectId === notesObjectId
10413
10529
  );
10414
10530
  if (!speakerNotesElement || !speakerNotesElement.shape?.text) {
10415
- return successResponse("No speaker notes found for this slide");
10531
+ return emptyNotesResponse(slideIndex);
10416
10532
  }
10417
10533
  let notesText = "";
10418
10534
  const textElements = speakerNotesElement.shape.text.textElements || [];
@@ -10421,9 +10537,17 @@ function getSpeakerNotes(slide, notesObjectId) {
10421
10537
  notesText += textElement.textRun.content;
10422
10538
  }
10423
10539
  });
10424
- return successResponse(notesText.trim() || "No speaker notes found for this slide");
10540
+ if (!notesText.trim()) {
10541
+ return emptyNotesResponse(slideIndex);
10542
+ }
10543
+ return structuredResponse(notesText.trim(), {
10544
+ action: "get",
10545
+ slideIndex,
10546
+ notes: notesText.trim(),
10547
+ updated: false
10548
+ });
10425
10549
  }
10426
- async function updateSpeakerNotes(slidesApi, presentationId, slide, notesObjectId, notes) {
10550
+ async function updateSpeakerNotes(slidesApi, presentationId, slide, notesObjectId, notes, slideIndex) {
10427
10551
  if (!notesObjectId) {
10428
10552
  return errorResponse(
10429
10553
  "This slide does not have a speaker notes object. Speaker notes may need to be initialized manually in Google Slides first."
@@ -10456,7 +10580,12 @@ async function updateSpeakerNotes(slidesApi, presentationId, slide, notesObjectI
10456
10580
  presentationId,
10457
10581
  requestBody: { requests }
10458
10582
  });
10459
- return successResponse(`Successfully updated speaker notes for slide`);
10583
+ return structuredResponse(`Successfully updated speaker notes for slide`, {
10584
+ action: "update",
10585
+ slideIndex,
10586
+ notes,
10587
+ updated: true
10588
+ });
10460
10589
  }
10461
10590
  async function handleFormatSlidesText(slides, args) {
10462
10591
  const validation = validateArgs(FormatSlidesTextSchema, args);
@@ -10560,7 +10689,10 @@ async function handleFormatSlidesText(slides, args) {
10560
10689
  presentationId: data.presentationId,
10561
10690
  requestBody: { requests }
10562
10691
  });
10563
- return successResponse(`Formatted text ${data.objectId}: ${appliedFormats.join(", ")}`);
10692
+ return structuredResponse(`Formatted text ${data.objectId}: ${appliedFormats.join(", ")}`, {
10693
+ objectId: data.objectId,
10694
+ formatsApplied: appliedFormats
10695
+ });
10564
10696
  }
10565
10697
  async function handleFormatSlidesShape(slides, args) {
10566
10698
  const validation = validateArgs(FormatSlidesShapeSchema, args);
@@ -10618,7 +10750,10 @@ async function handleFormatSlidesShape(slides, args) {
10618
10750
  ]
10619
10751
  }
10620
10752
  });
10621
- return successResponse(`Formatted shape ${data.objectId}: ${appliedFormats.join(", ")}`);
10753
+ return structuredResponse(`Formatted shape ${data.objectId}: ${appliedFormats.join(", ")}`, {
10754
+ objectId: data.objectId,
10755
+ formatsApplied: appliedFormats
10756
+ });
10622
10757
  }
10623
10758
  async function handleFormatSlideBackground(slides, args) {
10624
10759
  const validation = validateArgs(FormatSlideBackgroundSchema, args);
@@ -10637,7 +10772,9 @@ async function handleFormatSlideBackground(slides, args) {
10637
10772
  presentationId: data.presentationId,
10638
10773
  requestBody: { requests }
10639
10774
  });
10640
- return successResponse(`Set background color for ${data.pageObjectIds.length} slide(s)`);
10775
+ return structuredResponse(`Set background color for ${data.pageObjectIds.length} slide(s)`, {
10776
+ slidesFormatted: data.pageObjectIds.length
10777
+ });
10641
10778
  }
10642
10779
  async function handleListSlidePages(slides, args) {
10643
10780
  const validation = validateArgs(ListSlidePagesSchema, args);
@@ -11136,10 +11273,7 @@ async function handleListEvents(calendar, args) {
11136
11273
  });
11137
11274
  const events = response.data.items || [];
11138
11275
  if (events.length === 0) {
11139
- return structuredResponse("No events found.", {
11140
- events: [],
11141
- nextPageToken: null
11142
- });
11276
+ return structuredResponse("No events found.", { events: [] });
11143
11277
  }
11144
11278
  const eventData = events.map((event) => ({
11145
11279
  id: event.id,
@@ -11170,10 +11304,11 @@ ${toToon({ events: eventData })}`;
11170
11304
  More events available. Use pageToken: ${response.data.nextPageToken}`;
11171
11305
  }
11172
11306
  log("Listed events", { calendarId, count: events.length });
11173
- return structuredResponse(textResponse, {
11174
- events: eventData,
11175
- nextPageToken: response.data.nextPageToken || null
11176
- });
11307
+ const responseData = { events: eventData };
11308
+ if (response.data.nextPageToken) {
11309
+ responseData.nextPageToken = response.data.nextPageToken;
11310
+ }
11311
+ return structuredResponse(textResponse, responseData);
11177
11312
  }
11178
11313
  async function handleGetEvent(calendar, args) {
11179
11314
  const validation = validateArgs(GetEventSchema, args);
@@ -11424,7 +11559,10 @@ async function handleDeleteEvent(calendar, args) {
11424
11559
  sendUpdates
11425
11560
  });
11426
11561
  log("Deleted event", { calendarId, eventId });
11427
- return successResponse(`Deleted event: ${eventSummary} (ID: ${eventId})`);
11562
+ return structuredResponse(`Deleted event: ${eventSummary} (ID: ${eventId})`, {
11563
+ deleted: 1,
11564
+ eventId
11565
+ });
11428
11566
  }
11429
11567
  async function handleFindFreeTime(calendar, args) {
11430
11568
  const validation = validateArgs(FindFreeTimeSchema, args);
@@ -11748,11 +11886,7 @@ async function handleSearchEmails(gmail, args) {
11748
11886
  });
11749
11887
  const messages = response.data.messages || [];
11750
11888
  if (messages.length === 0) {
11751
- return structuredResponse(`No emails found matching: ${query}`, {
11752
- messages: [],
11753
- nextPageToken: null,
11754
- resultSizeEstimate: 0
11755
- });
11889
+ return structuredResponse(`No emails found matching: ${query}`, { messages: [] });
11756
11890
  }
11757
11891
  const messageDetails = await Promise.all(
11758
11892
  messages.slice(0, 50).map(async (msg) => {
@@ -11784,11 +11918,14 @@ ${toToon({ messages: messageDetails })}`;
11784
11918
  More results available. Use pageToken: ${response.data.nextPageToken}`;
11785
11919
  }
11786
11920
  log("Searched emails", { query, count: messages.length });
11787
- return structuredResponse(textResponse, {
11788
- messages: messageDetails,
11789
- nextPageToken: response.data.nextPageToken || null,
11790
- resultSizeEstimate: response.data.resultSizeEstimate
11791
- });
11921
+ const responseData = { messages: messageDetails };
11922
+ if (response.data.nextPageToken) {
11923
+ responseData.nextPageToken = response.data.nextPageToken;
11924
+ }
11925
+ if (response.data.resultSizeEstimate !== void 0 && response.data.resultSizeEstimate !== null) {
11926
+ responseData.resultSizeEstimate = response.data.resultSizeEstimate;
11927
+ }
11928
+ return structuredResponse(textResponse, responseData);
11792
11929
  }
11793
11930
  async function handleDeleteEmail(gmail, args) {
11794
11931
  const validation = validateArgs(DeleteEmailSchema, args);
@@ -11801,7 +11938,10 @@ async function handleDeleteEmail(gmail, args) {
11801
11938
  id: messageIds[0]
11802
11939
  });
11803
11940
  log("Deleted email", { messageId: messageIds[0] });
11804
- return successResponse(`Email ${messageIds[0]} permanently deleted.`);
11941
+ return structuredResponse(`Email ${messageIds[0]} permanently deleted.`, {
11942
+ deleted: 1,
11943
+ messageIds: [messageIds[0]]
11944
+ });
11805
11945
  }
11806
11946
  try {
11807
11947
  await gmail.users.messages.batchDelete({
@@ -11828,7 +11968,10 @@ async function handleDeleteEmail(gmail, args) {
11828
11968
  }
11829
11969
  }
11830
11970
  log("Deleted emails (batch)", { count: messageIds.length });
11831
- return successResponse(`Successfully deleted ${messageIds.length} email(s).`);
11971
+ return structuredResponse(`Successfully deleted ${messageIds.length} email(s).`, {
11972
+ deleted: messageIds.length,
11973
+ messageIds
11974
+ });
11832
11975
  }
11833
11976
  async function handleModifyEmail(gmail, args) {
11834
11977
  const validation = validateArgs(ModifyEmailSchema, args);
@@ -11919,10 +12062,15 @@ ${categoryLines}`,
11919
12062
  { succeeded, failed: allFailures.length, total: ids.length, failuresByCategory }
11920
12063
  );
11921
12064
  }
11922
- return successResponse(
12065
+ return structuredResponse(
11923
12066
  `Successfully modified labels for ${ids.length} thread(s).` + (addLabelIds ? `
11924
12067
  Added labels: ${addLabelIds.join(", ")}` : "") + (removeLabelIds ? `
11925
- Removed labels: ${removeLabelIds.join(", ")}` : "")
12068
+ Removed labels: ${removeLabelIds.join(", ")}` : ""),
12069
+ {
12070
+ id: ids[0],
12071
+ messageCount: ids.length,
12072
+ labelIds: addLabelIds || []
12073
+ }
11926
12074
  );
11927
12075
  }
11928
12076
  async function handleDownloadAttachment(gmail, args) {
@@ -12021,7 +12169,10 @@ async function handleDeleteLabel(gmail, args) {
12021
12169
  id: labelId
12022
12170
  });
12023
12171
  log("Deleted label", { labelId });
12024
- return successResponse(`Label ${labelId} deleted successfully.`);
12172
+ return structuredResponse(`Label ${labelId} deleted successfully.`, {
12173
+ deleted: 1,
12174
+ labelId
12175
+ });
12025
12176
  }
12026
12177
  async function handleListLabels(gmail, args) {
12027
12178
  const validation = validateArgs(ListLabelsSchema, args);
@@ -12257,7 +12408,10 @@ async function handleDeleteFilter(gmail, args) {
12257
12408
  id: filterId
12258
12409
  });
12259
12410
  log("Deleted filter", { filterId });
12260
- return successResponse(`Filter ${filterId} deleted successfully.`);
12411
+ return structuredResponse(`Filter ${filterId} deleted successfully.`, {
12412
+ deleted: 1,
12413
+ filterId
12414
+ });
12261
12415
  }
12262
12416
 
12263
12417
  // src/handlers/contacts.ts
@@ -12322,7 +12476,7 @@ async function handleListContacts(people, args) {
12322
12476
  );
12323
12477
  const connections = response.data.connections || [];
12324
12478
  if (connections.length === 0) {
12325
- return structuredResponse("No contacts found.", { contacts: [], nextPageToken: null });
12479
+ return structuredResponse("No contacts found.", { contacts: [] });
12326
12480
  }
12327
12481
  const contacts = connections.map(extractContactData);
12328
12482
  let textResponse = `Found ${connections.length} contact(s):
@@ -12334,11 +12488,16 @@ ${toToon({ contacts })}`;
12334
12488
  More contacts available. Use pageToken: ${response.data.nextPageToken}`;
12335
12489
  }
12336
12490
  log("Listed contacts", { count: connections.length });
12337
- return structuredResponse(textResponse, {
12338
- contacts,
12339
- nextPageToken: response.data.nextPageToken || null,
12340
- totalPeople: response.data.totalPeople
12341
- });
12491
+ const responseData = {
12492
+ contacts
12493
+ };
12494
+ if (response.data.nextPageToken) {
12495
+ responseData.nextPageToken = response.data.nextPageToken;
12496
+ }
12497
+ if (response.data.totalPeople !== void 0 && response.data.totalPeople !== null) {
12498
+ responseData.totalPeople = response.data.totalPeople;
12499
+ }
12500
+ return structuredResponse(textResponse, responseData);
12342
12501
  }
12343
12502
  async function handleGetContact(people, args) {
12344
12503
  const validation = validateArgs(GetContactSchema, args);