mcp-gsheets 1.9.0 → 1.10.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.
- package/README.md +56 -0
- package/dist/index.js +158 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -312,6 +312,62 @@ cp .env.example .env
|
|
|
312
312
|
npm run dev # Watch mode with auto-reload
|
|
313
313
|
```
|
|
314
314
|
|
|
315
|
+
## 🎚️ Reducing context cost with toolsets
|
|
316
|
+
|
|
317
|
+
All 44 tools together cost about **9,900 tokens of context in every session**,
|
|
318
|
+
before the model does anything. Most workflows need a fraction of that.
|
|
319
|
+
`GSHEETS_TOOLSETS` limits which tools the server exposes:
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{
|
|
323
|
+
"mcpServers": {
|
|
324
|
+
"gsheets": {
|
|
325
|
+
"command": "npx",
|
|
326
|
+
"args": ["mcp-gsheets"],
|
|
327
|
+
"env": {
|
|
328
|
+
"GOOGLE_PROJECT_ID": "your-project-id",
|
|
329
|
+
"GOOGLE_APPLICATION_CREDENTIALS": "/path/to/key.json",
|
|
330
|
+
"GSHEETS_TOOLSETS": "core,charts"
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
| Toolset | Tools | What it covers |
|
|
338
|
+
|---|---|---|
|
|
339
|
+
| `core` | 11 | Read/write values, metadata, sheet structure, create spreadsheet |
|
|
340
|
+
| `sheets` | 9 | Sheet lifecycle, rows and columns |
|
|
341
|
+
| `formatting` | 15 | Colours, borders, merges, conditional rules, links, dates |
|
|
342
|
+
| `charts` | 3 | Create, update, delete charts |
|
|
343
|
+
| `tables` | 4 | Native tables |
|
|
344
|
+
| `analysis` | 2 | Full-sheet snapshot, range comparison |
|
|
345
|
+
|
|
346
|
+
Measured `tools/list` cost:
|
|
347
|
+
|
|
348
|
+
| Configuration | Tools | ≈ Tokens |
|
|
349
|
+
|---|---|---|
|
|
350
|
+
| _unset_ (default, all toolsets) | 44 | 9,875 |
|
|
351
|
+
| `GSHEETS_TOOLSETS=core` | 11 | 1,986 |
|
|
352
|
+
| `GSHEETS_TOOLSETS=core,sheets` | 20 | 3,548 |
|
|
353
|
+
| `GSHEETS_READ_ONLY=true` | 16 | 3,599 |
|
|
354
|
+
| `GSHEETS_TOOLSETS=core` + read-only | 6 | 912 |
|
|
355
|
+
|
|
356
|
+
Notes:
|
|
357
|
+
|
|
358
|
+
- **The default is unchanged** — leave `GSHEETS_TOOLSETS` unset and you get
|
|
359
|
+
every tool, exactly as before.
|
|
360
|
+
- **`core` is always included.** `GSHEETS_TOOLSETS=charts` means "charts as
|
|
361
|
+
well as core", not "charts only" — without core the server cannot read a cell.
|
|
362
|
+
- **A typo is a startup error**, not a silently smaller tool list.
|
|
363
|
+
- `GSHEETS_READ_ONLY=true` drops every writing tool and can be combined with
|
|
364
|
+
`GSHEETS_TOOLSETS`. It is enforced when a tool is called, not just when the
|
|
365
|
+
list is built, so a client cannot write by naming a hidden tool.
|
|
366
|
+
|
|
367
|
+
All tools also carry MCP annotations (`readOnlyHint`, `destructiveHint`,
|
|
368
|
+
`idempotentHint`), so clients can skip confirmation prompts on reads and warn
|
|
369
|
+
before destructive operations.
|
|
370
|
+
|
|
315
371
|
## 📋 Available Tools
|
|
316
372
|
|
|
317
373
|
### Reading Data
|
package/dist/index.js
CHANGED
|
@@ -18036,6 +18036,141 @@ function validateAuth() {
|
|
|
18036
18036
|
}
|
|
18037
18037
|
}
|
|
18038
18038
|
|
|
18039
|
+
// src/config/toolsets.ts
|
|
18040
|
+
var TOOLSET_NAMES = [
|
|
18041
|
+
"core",
|
|
18042
|
+
"sheets",
|
|
18043
|
+
"formatting",
|
|
18044
|
+
"charts",
|
|
18045
|
+
"tables",
|
|
18046
|
+
"analysis"
|
|
18047
|
+
];
|
|
18048
|
+
var TOOLSETS = {
|
|
18049
|
+
/** Reading and writing cells, plus the metadata needed to do it safely. */
|
|
18050
|
+
core: [
|
|
18051
|
+
"sheets_check_access",
|
|
18052
|
+
"sheets_get_metadata",
|
|
18053
|
+
"sheets_get_sheet_structure",
|
|
18054
|
+
"sheets_get_sheet_dimensions",
|
|
18055
|
+
"sheets_get_values",
|
|
18056
|
+
"sheets_batch_get_values",
|
|
18057
|
+
"sheets_update_values",
|
|
18058
|
+
"sheets_batch_update_values",
|
|
18059
|
+
"sheets_append_values",
|
|
18060
|
+
"sheets_clear_values",
|
|
18061
|
+
"sheets_create_spreadsheet"
|
|
18062
|
+
],
|
|
18063
|
+
/** Sheet lifecycle and row/column structure. */
|
|
18064
|
+
sheets: [
|
|
18065
|
+
"sheets_insert_sheet",
|
|
18066
|
+
"sheets_delete_sheet",
|
|
18067
|
+
"sheets_duplicate_sheet",
|
|
18068
|
+
"sheets_copy_to",
|
|
18069
|
+
"sheets_update_sheet_properties",
|
|
18070
|
+
"sheets_batch_delete_sheets",
|
|
18071
|
+
"sheets_insert_rows",
|
|
18072
|
+
"sheets_delete_rows",
|
|
18073
|
+
"sheets_delete_columns"
|
|
18074
|
+
],
|
|
18075
|
+
/** Cell appearance: colours, borders, merges, conditional rules, links. */
|
|
18076
|
+
formatting: [
|
|
18077
|
+
"sheets_format_cells",
|
|
18078
|
+
"sheets_batch_format_cells",
|
|
18079
|
+
"sheets_update_borders",
|
|
18080
|
+
"sheets_get_border_map",
|
|
18081
|
+
"sheets_merge_cells",
|
|
18082
|
+
"sheets_unmerge_cells",
|
|
18083
|
+
"sheets_get_merged_cells",
|
|
18084
|
+
"sheets_get_sheet_formatting",
|
|
18085
|
+
"sheets_get_formatting_compact",
|
|
18086
|
+
"sheets_add_conditional_formatting",
|
|
18087
|
+
"sheets_get_conditional_formatting",
|
|
18088
|
+
"sheets_get_data_validation",
|
|
18089
|
+
"sheets_get_basic_filter",
|
|
18090
|
+
"sheets_insert_link",
|
|
18091
|
+
"sheets_insert_date"
|
|
18092
|
+
],
|
|
18093
|
+
charts: ["sheets_create_chart", "sheets_update_chart", "sheets_delete_chart"],
|
|
18094
|
+
tables: ["sheets_add_table", "sheets_update_table", "sheets_delete_table", "sheets_get_tables"],
|
|
18095
|
+
/** Whole-sheet reads and diffing — powerful, but the heaviest schemas. */
|
|
18096
|
+
analysis: ["sheets_get_full_sheet_snapshot", "sheets_compare_ranges"]
|
|
18097
|
+
};
|
|
18098
|
+
var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
18099
|
+
"sheets_check_access",
|
|
18100
|
+
"sheets_get_metadata",
|
|
18101
|
+
"sheets_get_sheet_structure",
|
|
18102
|
+
"sheets_get_sheet_dimensions",
|
|
18103
|
+
"sheets_get_values",
|
|
18104
|
+
"sheets_batch_get_values",
|
|
18105
|
+
"sheets_get_border_map",
|
|
18106
|
+
"sheets_get_merged_cells",
|
|
18107
|
+
"sheets_get_sheet_formatting",
|
|
18108
|
+
"sheets_get_formatting_compact",
|
|
18109
|
+
"sheets_get_conditional_formatting",
|
|
18110
|
+
"sheets_get_data_validation",
|
|
18111
|
+
"sheets_get_basic_filter",
|
|
18112
|
+
"sheets_get_tables",
|
|
18113
|
+
"sheets_get_full_sheet_snapshot",
|
|
18114
|
+
"sheets_compare_ranges"
|
|
18115
|
+
]);
|
|
18116
|
+
var DESTRUCTIVE_TOOLS = /* @__PURE__ */ new Set([
|
|
18117
|
+
"sheets_clear_values",
|
|
18118
|
+
"sheets_delete_sheet",
|
|
18119
|
+
"sheets_batch_delete_sheets",
|
|
18120
|
+
"sheets_delete_rows",
|
|
18121
|
+
"sheets_delete_columns",
|
|
18122
|
+
"sheets_delete_chart",
|
|
18123
|
+
"sheets_delete_table",
|
|
18124
|
+
"sheets_unmerge_cells"
|
|
18125
|
+
]);
|
|
18126
|
+
var ToolsetConfigError = class extends Error {
|
|
18127
|
+
};
|
|
18128
|
+
function parseList(raw) {
|
|
18129
|
+
return raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
18130
|
+
}
|
|
18131
|
+
function resolveToolsets(env = process.env) {
|
|
18132
|
+
const raw = env.GSHEETS_TOOLSETS?.trim();
|
|
18133
|
+
const readOnly = env.GSHEETS_READ_ONLY?.trim().toLowerCase() === "true";
|
|
18134
|
+
let enabled;
|
|
18135
|
+
if (!raw || raw.toLowerCase() === "all") {
|
|
18136
|
+
enabled = [...TOOLSET_NAMES];
|
|
18137
|
+
} else {
|
|
18138
|
+
const requested = parseList(raw);
|
|
18139
|
+
const unknown2 = requested.filter((n) => !TOOLSET_NAMES.includes(n));
|
|
18140
|
+
if (unknown2.length > 0) {
|
|
18141
|
+
throw new ToolsetConfigError(
|
|
18142
|
+
`Unknown toolset${unknown2.length > 1 ? "s" : ""}: ${unknown2.join(", ")}. Valid toolsets: ${TOOLSET_NAMES.join(", ")}, all.`
|
|
18143
|
+
);
|
|
18144
|
+
}
|
|
18145
|
+
const set = new Set(requested);
|
|
18146
|
+
set.add("core");
|
|
18147
|
+
enabled = TOOLSET_NAMES.filter((n) => set.has(n));
|
|
18148
|
+
}
|
|
18149
|
+
const allowed = /* @__PURE__ */ new Set();
|
|
18150
|
+
for (const name of enabled) {
|
|
18151
|
+
for (const tool of TOOLSETS[name]) {
|
|
18152
|
+
if (readOnly && !READ_ONLY_TOOLS.has(tool)) {
|
|
18153
|
+
continue;
|
|
18154
|
+
}
|
|
18155
|
+
allowed.add(tool);
|
|
18156
|
+
}
|
|
18157
|
+
}
|
|
18158
|
+
return { enabled, readOnly, allowed };
|
|
18159
|
+
}
|
|
18160
|
+
function annotationsFor(toolName) {
|
|
18161
|
+
if (READ_ONLY_TOOLS.has(toolName)) {
|
|
18162
|
+
return { readOnlyHint: true, idempotentHint: true };
|
|
18163
|
+
}
|
|
18164
|
+
const annotations = {};
|
|
18165
|
+
if (!DESTRUCTIVE_TOOLS.has(toolName)) {
|
|
18166
|
+
annotations.destructiveHint = false;
|
|
18167
|
+
}
|
|
18168
|
+
if (toolName !== "sheets_append_values") {
|
|
18169
|
+
annotations.idempotentHint = true;
|
|
18170
|
+
}
|
|
18171
|
+
return annotations;
|
|
18172
|
+
}
|
|
18173
|
+
|
|
18039
18174
|
// src/utils/error-handler.ts
|
|
18040
18175
|
function handleError(error2) {
|
|
18041
18176
|
console.error("Error in Google Sheets operation:", error2);
|
|
@@ -23925,6 +24060,23 @@ async function main() {
|
|
|
23925
24060
|
console.error("Authentication Error:", error2.message);
|
|
23926
24061
|
process.exit(1);
|
|
23927
24062
|
}
|
|
24063
|
+
let toolsetConfig;
|
|
24064
|
+
try {
|
|
24065
|
+
toolsetConfig = resolveToolsets();
|
|
24066
|
+
} catch (error2) {
|
|
24067
|
+
if (error2 instanceof ToolsetConfigError) {
|
|
24068
|
+
console.error(`Configuration Error: ${error2.message}`);
|
|
24069
|
+
process.exit(1);
|
|
24070
|
+
}
|
|
24071
|
+
throw error2;
|
|
24072
|
+
}
|
|
24073
|
+
const { enabled, readOnly, allowed } = toolsetConfig;
|
|
24074
|
+
const exposedTools = allTools.filter((tool) => allowed.has(tool.name)).map((tool) => ({ ...tool, annotations: annotationsFor(tool.name) }));
|
|
24075
|
+
if (enabled.length < Object.keys(TOOLSETS).length || readOnly) {
|
|
24076
|
+
console.error(
|
|
24077
|
+
`Toolsets: ${enabled.join(", ")}${readOnly ? " (read-only)" : ""} \u2014 ${exposedTools.length}/${allTools.length} tools`
|
|
24078
|
+
);
|
|
24079
|
+
}
|
|
23928
24080
|
const server = new Server(
|
|
23929
24081
|
{
|
|
23930
24082
|
name: "spreadsheet",
|
|
@@ -23940,11 +24092,16 @@ async function main() {
|
|
|
23940
24092
|
);
|
|
23941
24093
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
23942
24094
|
return {
|
|
23943
|
-
tools:
|
|
24095
|
+
tools: exposedTools
|
|
23944
24096
|
};
|
|
23945
24097
|
});
|
|
23946
24098
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
23947
24099
|
const { name, arguments: args } = request.params;
|
|
24100
|
+
if (!allowed.has(name)) {
|
|
24101
|
+
throw new Error(
|
|
24102
|
+
toolHandlers.has(name) ? `Tool ${name} is disabled by the current GSHEETS_TOOLSETS/GSHEETS_READ_ONLY configuration` : `Unknown tool: ${name}`
|
|
24103
|
+
);
|
|
24104
|
+
}
|
|
23948
24105
|
const handler = toolHandlers.get(name);
|
|
23949
24106
|
if (!handler) {
|
|
23950
24107
|
throw new Error(`Unknown tool: ${name}`);
|