google-tools-mcp 1.0.1 → 1.0.2

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 CHANGED
@@ -1,18 +1,16 @@
1
1
  # google-tools-mcp
2
2
 
3
- A unified MCP server for Google Workspace — Drive, Docs, Sheets, Gmail, and Calendar — with **lazy-loaded tool categories** to keep your context window lean.
3
+ A unified MCP server for Google Workspace — Drive, Docs, Sheets, Gmail, and Calendar — with **146 tools** across 8 categories.
4
4
 
5
- Only 2 tools are exposed at startup. When the AI agent needs a Google service, it calls `load_google_tools` to load just the relevant category. No bloat, no wasted context.
5
+ All tools are loaded at startup so they're immediately available to your AI agent. No discovery step needed.
6
6
 
7
7
  ## Why This Exists
8
8
 
9
- Most Google MCP servers dump 70+ tool definitions into your context on startup. If you need both Drive and Gmail, that's 140+ tools competing for attention before a single useful thing happens.
10
-
11
- This server starts with **2 tools** and loads categories on demand — so you only pay the context cost for what you actually use.
9
+ Most Google MCP servers split functionality across separate packages. This server combines everything into one single auth token, single process, single config.
12
10
 
13
11
  ## Features
14
12
 
15
- - **Lazy-loaded tools** — 146 tools across 8 categories, loaded only when needed
13
+ - **146 tools** across 8 categories, all available immediately
16
14
  - **Single auth token** — one OAuth flow covers Drive, Docs, Sheets, Gmail, and Calendar
17
15
  - **Lazy-loading auth** — no browser popup until your first tool call
18
16
  - **Multi-profile support** — separate tokens per Google account
@@ -169,8 +167,6 @@ This stores tokens in `~/.config/google-tools-mcp/work/` instead of the default
169
167
 
170
168
  ## Tool Categories
171
169
 
172
- Call `load_google_tools` with one or more category names to load them. You can load multiple at once.
173
-
174
170
  ### `files` (16 tools)
175
171
  Google Drive file management and content reading.
176
172
 
@@ -230,7 +226,7 @@ This package replaces both [`gdrive-tools-mcp`](https://www.npmjs.com/package/gd
230
226
 
231
227
  1. Replace both MCP server entries with a single `google-tools-mcp` entry
232
228
  2. Re-authenticate (the combined server uses its own config dir at `~/.config/google-tools-mcp/`)
233
- 3. All the same tools are available — the agent just needs to call `load_google_tools` first
229
+ 3. All tools are available immediately no discovery step needed
234
230
 
235
231
  ## License
236
232
 
package/dist/index.js CHANGED
@@ -1,14 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  // google-tools-mcp — Combined Google Workspace MCP server
3
3
  //
4
- // Provides lazy-loaded tool categories for Drive, Docs, Sheets, and Gmail.
5
- // Only a discovery tool is exposed at startup; individual tools are loaded on demand.
4
+ // All tool categories (Drive, Docs, Sheets, Gmail, Calendar) are loaded at
5
+ // startup so they're available in the initial tools/list response.
6
6
  //
7
7
  // Usage:
8
8
  // google-tools-mcp Start the MCP server (default)
9
9
  // google-tools-mcp auth Run the interactive OAuth flow
10
10
  import { FastMCP } from 'fastmcp';
11
- import { collectToolsWhileRegistering, installCachedToolsListHandler } from './cachedToolsList.js';
12
11
  import { registerAllTools } from './tools/index.js';
13
12
  import { logger } from './logger.js';
14
13
 
@@ -38,17 +37,13 @@ const server = new FastMCP({
38
37
  version: '1.0.0',
39
38
  });
40
39
 
41
- const registeredTools = [];
42
- collectToolsWhileRegistering(server, registeredTools);
43
- registerAllTools(server);
40
+ await registerAllTools(server);
44
41
 
45
42
  try {
46
43
  logger.info('Starting google-tools-mcp server...');
47
44
  await server.start({ transportType: 'stdio' });
48
- installCachedToolsListHandler(server, registeredTools);
49
45
  logger.info('MCP Server running using stdio. Awaiting client connection...');
50
46
  logger.info('Google auth will run automatically on first tool call.');
51
- logger.info(`${registeredTools.length} tools registered at startup (discovery + logout). Call load_google_tools to load more.`);
52
47
  } catch (startError) {
53
48
  logger.error('FATAL: Server failed to start:', startError.message || startError);
54
49
  process.exit(1);
@@ -1,8 +1,6 @@
1
- // Tool discovery and lazy-loading registration.
2
- //
3
- // Only the `load_google_tools` discovery tool is registered at startup.
4
- // When a category is loaded, its tools are dynamically registered and the
5
- // client is notified via tools/list_changed so it picks them up.
1
+ // Tool registration all categories loaded eagerly at startup.
2
+ // (Claude Code doesn't support notifications/tools/list_changed,
3
+ // so lazy-loading doesn't work.)
6
4
  import { z } from 'zod';
7
5
  import * as fs from 'fs/promises';
8
6
  import { getTokenPath } from '../auth.js';
@@ -10,11 +8,8 @@ import { resetClients } from '../clients.js';
10
8
  import { logger } from '../logger.js';
11
9
 
12
10
  // --- Category registry ---
13
- // Maps category names to { loader, description, toolCount }
14
11
  const CATEGORIES = {
15
12
  files: {
16
- description: 'Google Drive file management — list, search, create, copy, move, rename, delete files/folders, read file contents (pdf, docx), search within files',
17
- toolCount: 16,
18
13
  async loader(server) {
19
14
  const { registerDriveTools } = await import('./drive/index.js');
20
15
  const { registerExtrasTools } = await import('./extras/index.js');
@@ -23,8 +18,6 @@ const CATEGORIES = {
23
18
  },
24
19
  },
25
20
  documents: {
26
- description: 'Google Docs — read, write, insert text/tables/images, formatting, comments, tabs, markdown conversion',
27
- toolCount: 23,
28
21
  async loader(server) {
29
22
  const { registerDocsTools } = await import('./docs/index.js');
30
23
  const { registerUtilsTools } = await import('./utils/index.js');
@@ -33,16 +26,12 @@ const CATEGORIES = {
33
26
  },
34
27
  },
35
28
  spreadsheets: {
36
- description: 'Google Sheets — read, write, format cells, charts, tables, conditional formatting, data validation',
37
- toolCount: 30,
38
29
  async loader(server) {
39
30
  const { registerSheetsTools } = await import('./sheets/index.js');
40
31
  registerSheetsTools(server);
41
32
  },
42
33
  },
43
34
  email: {
44
- description: 'Gmail — send, reply, forward, get, list, delete, trash messages, create/update/send drafts, attachments, batch operations',
45
- toolCount: 19,
46
35
  async loader(server) {
47
36
  const { register: registerMessages } = await import('./gmail/messages.js');
48
37
  const { register: registerDrafts } = await import('./gmail/drafts.js');
@@ -51,32 +40,24 @@ const CATEGORIES = {
51
40
  },
52
41
  },
53
42
  email_threads: {
54
- description: 'Gmail threads — get, list, batch get, modify, delete, trash/untrash conversation threads',
55
- toolCount: 7,
56
43
  async loader(server) {
57
44
  const { register } = await import('./gmail/threads.js');
58
45
  register(server);
59
46
  },
60
47
  },
61
48
  email_labels: {
62
- description: 'Gmail labels — create, delete, get, list, update labels for organizing email',
63
- toolCount: 6,
64
49
  async loader(server) {
65
50
  const { register } = await import('./gmail/labels.js');
66
51
  register(server);
67
52
  },
68
53
  },
69
54
  email_settings: {
70
- description: 'Gmail settings — auto-forwarding, IMAP, POP, vacation responder, delegates, filters, forwarding addresses, send-as aliases, S/MIME, profile, mailbox watch',
71
- toolCount: 37,
72
55
  async loader(server) {
73
56
  const { register } = await import('./gmail/settings.js');
74
57
  register(server);
75
58
  },
76
59
  },
77
60
  calendar: {
78
- description: 'Google Calendar — list calendars, get/create/update/delete events, check busy times, find free slots, move events, recurring event instances, manage calendars',
79
- toolCount: 8,
80
61
  async loader(server) {
81
62
  const { registerCalendarTools } = await import('./calendar/index.js');
82
63
  registerCalendarTools(server);
@@ -84,69 +65,15 @@ const CATEGORIES = {
84
65
  },
85
66
  };
86
67
 
87
- // Track which categories have been loaded
88
- const loadedCategories = new Set();
89
-
90
68
  // ---------------------------------------------------------------------------
91
- // Notify the MCP client that the tool list has changed
69
+ // Public: register all tools eagerly, plus the logout utility.
92
70
  // ---------------------------------------------------------------------------
93
- function notifyToolsChanged(server) {
94
- try {
95
- const session = server.sessions?.[0];
96
- if (session?.server?.notification) {
97
- session.server.notification({ method: 'notifications/tools/list_changed' });
98
- logger.debug('Sent tools/list_changed notification.');
99
- } else {
100
- logger.debug('No session available for tools/list_changed notification.');
101
- }
102
- } catch (err) {
103
- logger.warn('Failed to send tools/list_changed notification:', err.message);
71
+ export async function registerAllTools(server) {
72
+ // Load every category
73
+ for (const [name, { loader }] of Object.entries(CATEGORIES)) {
74
+ await loader(server);
104
75
  }
105
- }
106
-
107
- // ---------------------------------------------------------------------------
108
- // Public: register the discovery tool (and logout)
109
- // ---------------------------------------------------------------------------
110
- export function registerAllTools(server) {
111
- // --- Discovery tool ---
112
- server.addTool({
113
- name: 'load_google_tools',
114
- description:
115
- 'Load Google Workspace tools by category. Call this first before using any Google service.\n\n' +
116
- 'Categories:\n' +
117
- Object.entries(CATEGORIES)
118
- .map(([name, { description, toolCount }]) => ` • ${name} (${toolCount} tools) — ${description}`)
119
- .join('\n') +
120
- '\n\nYou can load multiple categories at once by passing an array.',
121
- parameters: z.object({
122
- categories: z
123
- .array(z.enum(Object.keys(CATEGORIES)))
124
- .describe('One or more category names to load'),
125
- }),
126
- execute: async ({ categories }, { log }) => {
127
- const results = [];
128
- for (const cat of categories) {
129
- if (loadedCategories.has(cat)) {
130
- results.push({ category: cat, status: 'already_loaded' });
131
- continue;
132
- }
133
- log.info(`Loading category: ${cat}`);
134
- await CATEGORIES[cat].loader(server);
135
- loadedCategories.add(cat);
136
- results.push({
137
- category: cat,
138
- status: 'loaded',
139
- toolCount: CATEGORIES[cat].toolCount,
140
- });
141
- }
142
- notifyToolsChanged(server);
143
- return JSON.stringify({
144
- loaded: results,
145
- message: 'Tools are now available. You can call them directly.',
146
- all_loaded_categories: [...loadedCategories],
147
- });
148
- },
149
- });
76
+ logger.info(`Loaded all ${Object.keys(CATEGORIES).length} categories at startup.`);
150
77
 
151
78
  // --- Logout tool (always available) ---
152
79
  server.addTool({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "google-tools-mcp",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Combined Google Workspace MCP server (Drive, Docs, Sheets, Gmail) with lazy-loaded tool categories",
5
5
  "type": "module",
6
6
  "bin": {