google-tools-mcp 1.0.16 → 1.0.17

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 (44) hide show
  1. package/dist/tools/docs/addTab.js +1 -0
  2. package/dist/tools/docs/appendToGoogleDoc.js +2 -1
  3. package/dist/tools/docs/comments/addComment.js +2 -1
  4. package/dist/tools/docs/comments/deleteComment.js +2 -1
  5. package/dist/tools/docs/comments/replyToComment.js +2 -1
  6. package/dist/tools/docs/comments/resolveComment.js +3 -2
  7. package/dist/tools/docs/deleteRange.js +2 -1
  8. package/dist/tools/docs/findAndReplace.js +2 -1
  9. package/dist/tools/docs/formatting/applyParagraphStyle.js +2 -1
  10. package/dist/tools/docs/insertImage.js +4 -2
  11. package/dist/tools/docs/insertPageBreak.js +2 -1
  12. package/dist/tools/docs/insertTable.js +2 -1
  13. package/dist/tools/docs/insertTableWithData.js +2 -1
  14. package/dist/tools/docs/modifyText.js +2 -1
  15. package/dist/tools/docs/renameTab.js +2 -1
  16. package/dist/tools/drive/moveFile.js +3 -2
  17. package/dist/tools/forms/batchUpdateForm.js +1 -0
  18. package/dist/tools/forms/setPublishSettings.js +1 -0
  19. package/dist/tools/sheets/addConditionalFormatting.js +2 -1
  20. package/dist/tools/sheets/addSpreadsheetSheet.js +2 -1
  21. package/dist/tools/sheets/appendSpreadsheetRows.js +2 -1
  22. package/dist/tools/sheets/appendTableRows.js +1 -0
  23. package/dist/tools/sheets/autoResizeColumns.js +2 -1
  24. package/dist/tools/sheets/batchWrite.js +2 -1
  25. package/dist/tools/sheets/clearSpreadsheetRange.js +2 -1
  26. package/dist/tools/sheets/copyFormatting.js +2 -1
  27. package/dist/tools/sheets/createTable.js +1 -0
  28. package/dist/tools/sheets/deleteChart.js +2 -1
  29. package/dist/tools/sheets/deleteSheet.js +2 -1
  30. package/dist/tools/sheets/deleteTable.js +1 -0
  31. package/dist/tools/sheets/duplicateSheet.js +2 -1
  32. package/dist/tools/sheets/formatCells.js +2 -1
  33. package/dist/tools/sheets/freezeRowsAndColumns.js +2 -1
  34. package/dist/tools/sheets/groupRows.js +2 -1
  35. package/dist/tools/sheets/insertChart.js +2 -1
  36. package/dist/tools/sheets/renameSheet.js +2 -1
  37. package/dist/tools/sheets/setColumnWidths.js +2 -1
  38. package/dist/tools/sheets/setDropdownValidation.js +3 -2
  39. package/dist/tools/sheets/ungroupAllRows.js +2 -1
  40. package/dist/tools/sheets/updateTableRange.js +1 -0
  41. package/dist/tools/sheets/writeSpreadsheet.js +2 -1
  42. package/dist/tools/utils/appendMarkdownToGoogleDoc.js +2 -1
  43. package/dist/tools/utils/replaceDocumentWithMarkdown.js +2 -1
  44. package/package.json +1 -1
@@ -67,6 +67,7 @@ export function register(server) {
67
67
  const newTabProps = response.data.replies?.[0]?.addDocumentTab?.tabProperties;
68
68
  if (newTabProps) {
69
69
  return JSON.stringify({
70
+ url: `https://docs.google.com/document/d/${args.documentId}/edit`,
70
71
  message: `Successfully added new tab "${newTabProps.title || '(untitled)'}"`,
71
72
  tabId: newTabProps.tabId,
72
73
  title: newTabProps.title,
@@ -66,7 +66,8 @@ export function register(server) {
66
66
  };
67
67
  await GDocsHelpers.executeBatchUpdate(docs, args.documentId, [request]);
68
68
  log.info(`Successfully appended to doc: ${args.documentId}${args.tabId ? ` (tab: ${args.tabId})` : ''}`);
69
- return `Successfully appended text to ${args.tabId ? `tab ${args.tabId} in ` : ''}document ${args.documentId}.`;
69
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
70
+ return `${docUrl}\nSuccessfully appended text to ${args.tabId ? `tab ${args.tabId} in ` : ''}document ${args.documentId}.`;
70
71
  }
71
72
  catch (error) {
72
73
  log.error(`Error appending to doc ${args.documentId}: ${error.message || error}`);
@@ -72,7 +72,8 @@ export function register(server) {
72
72
  }),
73
73
  },
74
74
  });
75
- return `Comment added successfully. Comment ID: ${response.data.id}`;
75
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
76
+ return `${docUrl}\nComment added successfully. Comment ID: ${response.data.id}`;
76
77
  }
77
78
  catch (error) {
78
79
  log.error(`Error adding comment: ${error.message || error}`);
@@ -19,7 +19,8 @@ export function register(server) {
19
19
  fileId: args.documentId,
20
20
  commentId: args.commentId,
21
21
  });
22
- return `Comment ${args.commentId} has been deleted.`;
22
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
23
+ return `${docUrl}\nComment ${args.commentId} has been deleted.`;
23
24
  }
24
25
  catch (error) {
25
26
  log.error(`Error deleting comment: ${error.message || error}`);
@@ -24,7 +24,8 @@ export function register(server) {
24
24
  content: args.content,
25
25
  },
26
26
  });
27
- return `Reply added successfully. Reply ID: ${response.data.id}`;
27
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
28
+ return `${docUrl}\nReply added successfully. Reply ID: ${response.data.id}`;
28
29
  }
29
30
  catch (error) {
30
31
  log.error(`Error adding reply: ${error.message || error}`);
@@ -37,11 +37,12 @@ export function register(server) {
37
37
  commentId: args.commentId,
38
38
  fields: 'resolved',
39
39
  });
40
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
40
41
  if (verifyComment.data.resolved) {
41
- return `Comment ${args.commentId} has been marked as resolved.`;
42
+ return `${docUrl}\nComment ${args.commentId} has been marked as resolved.`;
42
43
  }
43
44
  else {
44
- return `Attempted to resolve comment ${args.commentId}, but the resolved status may not persist in the Google Docs UI due to API limitations. The comment can be resolved manually in the Google Docs interface.`;
45
+ return `${docUrl}\nAttempted to resolve comment ${args.commentId}, but the resolved status may not persist in the Google Docs UI due to API limitations. The comment can be resolved manually in the Google Docs interface.`;
45
46
  }
46
47
  }
47
48
  catch (error) {
@@ -59,7 +59,8 @@ export function register(server) {
59
59
  deleteContentRange: { range },
60
60
  };
61
61
  await GDocsHelpers.executeBatchUpdate(docs, args.documentId, [request]);
62
- return `Successfully deleted content in range ${args.startIndex}-${args.endIndex}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
62
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
63
+ return `${docUrl}\nSuccessfully deleted content in range ${args.startIndex}-${args.endIndex}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
63
64
  }
64
65
  catch (error) {
65
66
  log.error(`Error deleting range in doc ${args.documentId}: ${error.message || error}`);
@@ -41,7 +41,8 @@ export function register(server) {
41
41
  };
42
42
  const response = await GDocsHelpers.executeBatchUpdate(docs, args.documentId, [request]);
43
43
  const changed = response.replies?.[0]?.replaceAllText?.occurrencesChanged ?? 0;
44
- return `Replaced ${changed} occurrence(s) of "${args.findText}" with "${args.replaceText}".`;
44
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
45
+ return `${docUrl}\nReplaced ${changed} occurrence(s) of "${args.findText}" with "${args.replaceText}".`;
45
46
  }
46
47
  catch (error) {
47
48
  log.error(`Error in findAndReplace for doc ${args.documentId}: ${error.message || error}`);
@@ -65,7 +65,8 @@ export function register(server) {
65
65
  }
66
66
  log.info(`Applying styles: ${requestInfo.fields.join(', ')}`);
67
67
  await GDocsHelpers.executeBatchUpdate(docs, args.documentId, [requestInfo.request]);
68
- return `Successfully applied paragraph styles (${requestInfo.fields.join(', ')}) to the paragraph${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
68
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
69
+ return `${docUrl}\nSuccessfully applied paragraph styles (${requestInfo.fields.join(', ')}) to the paragraph${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
69
70
  }
70
71
  catch (error) {
71
72
  // Detailed error logging
@@ -76,7 +76,8 @@ export function register(server) {
76
76
  );
77
77
  log.info(`[AppsScript] Inserting image via marker at index ${args.index} (fileId: ${driveFileId})`);
78
78
  await GDocsHelpers.insertImageViaAppsScript(docs, scriptClient, appsScriptDeploymentId, args.documentId, driveFileId, args.index, args.tabId);
79
- return `Successfully inserted local image at index ${args.index} via Apps Script${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
79
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
80
+ return `${docUrl}\nSuccessfully inserted local image at index ${args.index} via Apps Script${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
80
81
  }
81
82
  // --- Standard path: public URL insertion via Docs API ---
82
83
  let resolvedUrl;
@@ -109,7 +110,8 @@ export function register(server) {
109
110
  if (args.width && args.height) {
110
111
  sizeInfo = ` with size ${args.width}x${args.height}pt`;
111
112
  }
112
- return `Successfully inserted image at index ${args.index}${sizeInfo}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
113
+ const docUrl2 = `https://docs.google.com/document/d/${args.documentId}/edit`;
114
+ return `${docUrl2}\nSuccessfully inserted image at index ${args.index}${sizeInfo}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
113
115
  }
114
116
  catch (error) {
115
117
  log.error(`Error inserting image in doc ${args.documentId}: ${error.message || error}`);
@@ -45,7 +45,8 @@ export function register(server) {
45
45
  insertPageBreak: { location },
46
46
  };
47
47
  await GDocsHelpers.executeBatchUpdate(docs, args.documentId, [request]);
48
- return `Successfully inserted page break at index ${args.index}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
48
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
49
+ return `${docUrl}\nSuccessfully inserted page break at index ${args.index}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
49
50
  }
50
51
  catch (error) {
51
52
  log.error(`Error inserting page break in doc ${args.documentId}: ${error.message || error}`);
@@ -40,7 +40,8 @@ export function register(server) {
40
40
  }
41
41
  }
42
42
  await GDocsHelpers.createTable(docs, args.documentId, args.rows, args.columns, args.index, args.tabId);
43
- return `Successfully inserted a ${args.rows}x${args.columns} table at index ${args.index}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
43
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
44
+ return `${docUrl}\nSuccessfully inserted a ${args.rows}x${args.columns} table at index ${args.index}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
44
45
  }
45
46
  catch (error) {
46
47
  log.error(`Error inserting table in doc ${args.documentId}: ${error.message || error}`);
@@ -119,7 +119,8 @@ export function register(server) {
119
119
  }
120
120
  const requests = buildInsertTableWithDataRequests(args.data, args.index, args.hasHeaderRow ?? false, args.tabId);
121
121
  const metadata = await GDocsHelpers.executeBatchUpdateWithSplitting(docs, args.documentId, requests, log);
122
- return (`Successfully inserted a ${numRows}x${numCols} table with data at index ${args.index}` +
122
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
123
+ return (`${docUrl}\nSuccessfully inserted a ${numRows}x${numCols} table with data at index ${args.index}` +
123
124
  `${args.tabId ? ` in tab ${args.tabId}` : ''}. ` +
124
125
  `${args.hasHeaderRow ? 'Header row bolded. ' : ''}` +
125
126
  `(${metadata.totalRequests} requests in ${metadata.totalApiCalls} API calls, ${metadata.totalElapsedMs}ms)`);
@@ -165,7 +165,8 @@ export function register(server) {
165
165
  actions.push('applied text formatting');
166
166
  if (args.paragraphStyle)
167
167
  actions.push('applied paragraph formatting');
168
- return `Successfully ${actions.join(' and ')} at range ${startIndex}-${endIndex ?? startIndex + (args.text?.length ?? 0)}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
168
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
169
+ return `${docUrl}\nSuccessfully ${actions.join(' and ')} at range ${startIndex}-${endIndex ?? startIndex + (args.text?.length ?? 0)}${args.tabId ? ` in tab ${args.tabId}` : ''}.`;
169
170
  }
170
171
  catch (error) {
171
172
  log.error(`Error in modifyText for doc ${args.documentId}: ${error.message || error}`);
@@ -44,7 +44,8 @@ export function register(server) {
44
44
  ],
45
45
  },
46
46
  });
47
- return `Successfully renamed tab from "${oldTitle}" to "${args.newTitle}".`;
47
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
48
+ return `${docUrl}\nSuccessfully renamed tab from "${oldTitle}" to "${args.newTitle}".`;
48
49
  }
49
50
  catch (error) {
50
51
  log.error(`Error renaming tab ${args.tabId} in doc ${args.documentId}: ${error.message || error}`);
@@ -31,7 +31,7 @@ export function register(server) {
31
31
  let updateParams = {
32
32
  fileId: args.fileId,
33
33
  addParents: args.newParentId,
34
- fields: 'id,name,parents',
34
+ fields: 'id,name,parents,webViewLink',
35
35
  supportsAllDrives: true,
36
36
  };
37
37
  if (args.removeFromAllParents && currentParents.length > 0) {
@@ -39,7 +39,8 @@ export function register(server) {
39
39
  }
40
40
  const response = await drive.files.update(updateParams);
41
41
  const action = args.removeFromAllParents ? 'moved' : 'copied';
42
- return `Successfully ${action} "${fileName}" to new location.\nFile ID: ${response.data.id}`;
42
+ const fileUrl = response.data.webViewLink || `https://drive.google.com/file/d/${response.data.id}/view`;
43
+ return `${fileUrl}\nSuccessfully ${action} "${fileName}" to new location.\nFile ID: ${response.data.id}`;
43
44
  }
44
45
  catch (error) {
45
46
  log.error(`Error moving file: ${error.message || error}`);
@@ -49,6 +49,7 @@ export function register(server) {
49
49
  const replies = data.replies || [];
50
50
 
51
51
  const result = {
52
+ url: `https://docs.google.com/forms/d/${args.formId}/edit`,
52
53
  requestsApplied: args.requests.length,
53
54
  repliesReceived: replies.length,
54
55
  };
@@ -41,6 +41,7 @@ export function register(server) {
41
41
  });
42
42
 
43
43
  return JSON.stringify({
44
+ url: `https://docs.google.com/forms/d/${args.formId}/edit`,
44
45
  success: true,
45
46
  formId: args.formId,
46
47
  message: 'Publish settings updated successfully.',
@@ -130,7 +130,8 @@ export function register(server) {
130
130
  format.textFormat = textFormat;
131
131
  }
132
132
  await SheetsHelpers.addConditionalFormatRule(sheets, args.spreadsheetId, gridRanges, args.conditionType, conditionValues, format);
133
- return `Successfully added conditional formatting rule to ${args.ranges.join(', ')}.`;
133
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
134
+ return `${sheetUrl}\nSuccessfully added conditional formatting rule to ${args.ranges.join(', ')}.`;
134
135
  }
135
136
  catch (error) {
136
137
  log.error(`Error adding conditional format rule: ${error.message || error}`);
@@ -21,7 +21,8 @@ export function register(server) {
21
21
  if (!addedSheet) {
22
22
  throw new UserError('Failed to add sheet - no sheet properties returned.');
23
23
  }
24
- return `Successfully added sheet "${addedSheet.title}" (Sheet ID: ${addedSheet.sheetId}) to spreadsheet.`;
24
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
25
+ return `${sheetUrl}\nSuccessfully added sheet "${addedSheet.title}" (Sheet ID: ${addedSheet.sheetId}) to spreadsheet.`;
25
26
  }
26
27
  catch (error) {
27
28
  log.error(`Error adding sheet to spreadsheet ${args.spreadsheetId}: ${error.message || error}`);
@@ -30,7 +30,8 @@ export function register(server) {
30
30
  const updatedCells = response.updates?.updatedCells || 0;
31
31
  const updatedRows = response.updates?.updatedRows || 0;
32
32
  const updatedRange = response.updates?.updatedRange || args.range;
33
- return `Successfully appended ${updatedRows} row(s) (${updatedCells} cells) to spreadsheet. Updated range: ${updatedRange}`;
33
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
34
+ return `${sheetUrl}\nSuccessfully appended ${updatedRows} row(s) (${updatedCells} cells) to spreadsheet. Updated range: ${updatedRange}`;
34
35
  }
35
36
  catch (error) {
36
37
  log.error(`Error appending to spreadsheet ${args.spreadsheetId}: ${error.message || error}`);
@@ -32,6 +32,7 @@ export function register(server) {
32
32
  // Append rows to the table
33
33
  const result = await SheetsHelpers.appendToTableHelper(sheets, args.spreadsheetId, table.tableId || '', args.values);
34
34
  return JSON.stringify({
35
+ url: `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`,
35
36
  tableId: table.tableId,
36
37
  name: table.name,
37
38
  rowsAppended: result.rowsAppended,
@@ -54,7 +54,8 @@ export function register(server) {
54
54
  },
55
55
  });
56
56
  const rangeDesc = args.columns ? `columns ${args.columns}` : 'all columns';
57
- return `Successfully auto-resized ${rangeDesc} to fit content.`;
57
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
58
+ return `${sheetUrl}\nSuccessfully auto-resized ${rangeDesc} to fit content.`;
58
59
  }
59
60
  catch (error) {
60
61
  log.error(`Error auto-resizing columns: ${error.message || error}`);
@@ -40,7 +40,8 @@ export function register(server) {
40
40
  const totalRows = response.data.totalUpdatedRows || 0;
41
41
  const totalColumns = response.data.totalUpdatedColumns || 0;
42
42
  const totalSheets = response.data.totalUpdatedSheets || 0;
43
- return `Successfully batch-wrote ${totalCells} cells (${totalRows} rows, ${totalColumns} columns) across ${totalSheets} sheet(s) in ${args.data.length} range(s).`;
43
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
44
+ return `${sheetUrl}\nSuccessfully batch-wrote ${totalCells} cells (${totalRows} rows, ${totalColumns} columns) across ${totalSheets} sheet(s) in ${args.data.length} range(s).`;
44
45
  }
45
46
  catch (error) {
46
47
  log.error(`Error batch writing to spreadsheet ${args.spreadsheetId}: ${error.message || error}`);
@@ -18,7 +18,8 @@ export function register(server) {
18
18
  try {
19
19
  const response = await SheetsHelpers.clearRange(sheets, args.spreadsheetId, args.range);
20
20
  const clearedRange = response.clearedRange || args.range;
21
- return `Successfully cleared range ${clearedRange}.`;
21
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
22
+ return `${sheetUrl}\nSuccessfully cleared range ${clearedRange}.`;
22
23
  }
23
24
  catch (error) {
24
25
  log.error(`Error clearing range in spreadsheet ${args.spreadsheetId}: ${error.message || error}`);
@@ -46,7 +46,8 @@ export function register(server) {
46
46
  ],
47
47
  },
48
48
  });
49
- return `Successfully copied formatting from ${args.sourceSheetName}!${args.sourceRange} to ${args.destinationSheetName}!${args.destinationRange}.`;
49
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
50
+ return `${sheetUrl}\nSuccessfully copied formatting from ${args.sourceSheetName}!${args.sourceRange} to ${args.destinationSheetName}!${args.destinationRange}.`;
50
51
  }
51
52
  catch (error) {
52
53
  log.error(`Error copying formatting in spreadsheet ${args.spreadsheetId}: ${error.message || error}`);
@@ -102,6 +102,7 @@ export function register(server) {
102
102
  columnProperties,
103
103
  });
104
104
  return JSON.stringify({
105
+ url: `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`,
105
106
  tableId: table.tableId,
106
107
  name: table.name,
107
108
  range: args.range,
@@ -28,7 +28,8 @@ export function register(server) {
28
28
  ],
29
29
  },
30
30
  });
31
- return `Chart ${args.chartId} deleted successfully.`;
31
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
32
+ return `${sheetUrl}\nChart ${args.chartId} deleted successfully.`;
32
33
  }
33
34
  catch (error) {
34
35
  log.error(`Error deleting chart: ${error.message || error}`);
@@ -30,7 +30,8 @@ export function register(server) {
30
30
  ],
31
31
  },
32
32
  });
33
- return `Successfully deleted sheet (ID: ${args.sheetId}) from spreadsheet.`;
33
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
34
+ return `${sheetUrl}\nSuccessfully deleted sheet (ID: ${args.sheetId}) from spreadsheet.`;
34
35
  }
35
36
  catch (error) {
36
37
  log.error(`Error deleting sheet in spreadsheet ${args.spreadsheetId}: ${error.message || error}`);
@@ -35,6 +35,7 @@ export function register(server) {
35
35
  clearedRange = range;
36
36
  }
37
37
  return JSON.stringify({
38
+ url: `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`,
38
39
  tableId: table.tableId,
39
40
  name: table.name,
40
41
  deleted: true,
@@ -40,7 +40,8 @@ export function register(server) {
40
40
  if (!duplicatedSheet) {
41
41
  throw new UserError('Failed to duplicate sheet - no sheet properties returned.');
42
42
  }
43
- return `Successfully duplicated sheet as "${duplicatedSheet.title}" (Sheet ID: ${duplicatedSheet.sheetId}).`;
43
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
44
+ return `${sheetUrl}\nSuccessfully duplicated sheet as "${duplicatedSheet.title}" (Sheet ID: ${duplicatedSheet.sheetId}).`;
44
45
  }
45
46
  catch (error) {
46
47
  log.error(`Error duplicating sheet in spreadsheet ${args.spreadsheetId}: ${error.message || error}`);
@@ -93,7 +93,8 @@ export function register(server) {
93
93
  format.numberFormat = args.numberFormat;
94
94
  }
95
95
  await SheetsHelpers.formatCells(sheets, args.spreadsheetId, args.range, format);
96
- return `Successfully applied formatting to range "${args.range}".`;
96
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
97
+ return `${sheetUrl}\nSuccessfully applied formatting to range "${args.range}".`;
97
98
  }
98
99
  catch (error) {
99
100
  log.error(`Error formatting cells: ${error.message || error}`);
@@ -45,7 +45,8 @@ export function register(server) {
45
45
  ? 'unfroze columns'
46
46
  : `froze left ${args.frozenColumns} column(s)`);
47
47
  }
48
- return `Successfully ${parts.join(' and ')}.`;
48
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
49
+ return `${sheetUrl}\nSuccessfully ${parts.join(' and ')}.`;
49
50
  }
50
51
  catch (error) {
51
52
  log.error(`Error freezing rows/columns: ${error.message || error}`);
@@ -49,7 +49,8 @@ export function register(server) {
49
49
  spreadsheetId: args.spreadsheetId,
50
50
  requestBody: { requests },
51
51
  });
52
- return `Successfully created ${args.groups.length} row group(s).`;
52
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
53
+ return `${sheetUrl}\nSuccessfully created ${args.groups.length} row group(s).`;
53
54
  }
54
55
  catch (error) {
55
56
  log.error(`Error grouping rows: ${error.message || error}`);
@@ -212,7 +212,8 @@ export function register(server) {
212
212
  },
213
213
  });
214
214
  const chartId = response.data.replies?.[0]?.addChart?.chart?.chartId;
215
- return `Chart created successfully${chartId ? ` (Chart ID: ${chartId})` : ''}.`;
215
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
216
+ return `${sheetUrl}\nChart created successfully${chartId ? ` (Chart ID: ${chartId})` : ''}.`;
216
217
  }
217
218
  catch (error) {
218
219
  log.error(`Error inserting chart: ${error.message || error}`);
@@ -35,7 +35,8 @@ export function register(server) {
35
35
  ],
36
36
  },
37
37
  });
38
- return `Successfully renamed sheet (ID: ${args.sheetId}) to "${args.newName}".`;
38
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
39
+ return `${sheetUrl}\nSuccessfully renamed sheet (ID: ${args.sheetId}) to "${args.newName}".`;
39
40
  }
40
41
  catch (error) {
41
42
  log.error(`Error renaming sheet in spreadsheet ${args.spreadsheetId}: ${error.message || error}`);
@@ -30,7 +30,8 @@ export function register(server) {
30
30
  try {
31
31
  await SheetsHelpers.setColumnWidths(sheets, args.spreadsheetId, args.sheetName, args.columnWidths);
32
32
  const summary = args.columnWidths.map((cw) => `${cw.column}=${cw.width}px`).join(', ');
33
- return `Successfully set column widths: ${summary}.`;
33
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
34
+ return `${sheetUrl}\nSuccessfully set column widths: ${summary}.`;
34
35
  }
35
36
  catch (error) {
36
37
  log.error(`Error setting column widths: ${error.message || error}`);
@@ -35,10 +35,11 @@ export function register(server) {
35
35
  : `Setting dropdown validation on "${args.range}" with ${args.values.length} options in spreadsheet ${args.spreadsheetId}`);
36
36
  try {
37
37
  await SheetsHelpers.setDropdownValidation(sheets, args.spreadsheetId, args.range, args.values, args.strict, args.inputMessage);
38
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
38
39
  if (isClearing) {
39
- return `Successfully removed dropdown validation from range "${args.range}".`;
40
+ return `${sheetUrl}\nSuccessfully removed dropdown validation from range "${args.range}".`;
40
41
  }
41
- return `Successfully added dropdown validation to range "${args.range}" with ${args.values.length} options: ${args.values.join(', ')}.`;
42
+ return `${sheetUrl}\nSuccessfully added dropdown validation to range "${args.range}" with ${args.values.length} options: ${args.values.join(', ')}.`;
42
43
  }
43
44
  catch (error) {
44
45
  log.error(`Error setting dropdown validation: ${error.message || error}`);
@@ -53,7 +53,8 @@ export function register(server) {
53
53
  break;
54
54
  }
55
55
  }
56
- return `Successfully removed all row groups (${removed} level(s) cleared).`;
56
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
57
+ return `${sheetUrl}\nSuccessfully removed all row groups (${removed} level(s) cleared).`;
57
58
  }
58
59
  catch (error) {
59
60
  log.error(`Error removing row groups: ${error.message || error}`);
@@ -30,6 +30,7 @@ export function register(server) {
30
30
  // Update the table range
31
31
  const updatedTable = await SheetsHelpers.updateTableRangeHelper(sheets, args.spreadsheetId, table.tableId || '', newRange);
32
32
  return JSON.stringify({
33
+ url: `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`,
33
34
  tableId: updatedTable.tableId,
34
35
  name: updatedTable.name,
35
36
  oldRange: table.range
@@ -30,7 +30,8 @@ export function register(server) {
30
30
  const updatedCells = response.updatedCells || 0;
31
31
  const updatedRows = response.updatedRows || 0;
32
32
  const updatedColumns = response.updatedColumns || 0;
33
- return `Successfully wrote ${updatedCells} cells (${updatedRows} rows, ${updatedColumns} columns) to range ${args.range}.`;
33
+ const sheetUrl = `https://docs.google.com/spreadsheets/d/${args.spreadsheetId}/edit`;
34
+ return `${sheetUrl}\nSuccessfully wrote ${updatedCells} cells (${updatedRows} rows, ${updatedColumns} columns) to range ${args.range}.`;
34
35
  }
35
36
  catch (error) {
36
37
  log.error(`Error writing to spreadsheet ${args.spreadsheetId}: ${error.message || error}`);
@@ -79,7 +79,8 @@ export function register(server) {
79
79
  });
80
80
  const debugSummary = formatInsertResult(result);
81
81
  log.info(debugSummary);
82
- return `Successfully appended ${args.markdown.length} characters of markdown.\n\n${debugSummary}`;
82
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
83
+ return `${docUrl}\nSuccessfully appended ${args.markdown.length} characters of markdown.\n\n${debugSummary}`;
83
84
  }
84
85
  catch (error) {
85
86
  log.error(`Error appending markdown: ${error.message}`);
@@ -140,7 +140,8 @@ export function register(server) {
140
140
  });
141
141
  const debugSummary = formatInsertResult(result);
142
142
  log.info(debugSummary);
143
- return `Successfully replaced document content with ${args.markdown.length} characters of markdown.\n\n${debugSummary}`;
143
+ const docUrl = `https://docs.google.com/document/d/${args.documentId}/edit`;
144
+ return `${docUrl}\nSuccessfully replaced document content with ${args.markdown.length} characters of markdown.\n\n${debugSummary}`;
144
145
  }
145
146
  catch (error) {
146
147
  log.error(`Error replacing document with markdown: ${error.message}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "google-tools-mcp",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "Combined Google Workspace MCP server (Drive, Docs, Sheets, Gmail) with lazy-loaded tool categories",
5
5
  "type": "module",
6
6
  "bin": {