mcp-google-multi 4.5.0-alpha.3 → 5.0.0-beta.1
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 +76 -417
- package/dist/accounts.js +4 -1
- package/dist/auth.d.ts +0 -2
- package/dist/auth.js +0 -11
- package/dist/index.js +1 -3
- package/dist/tools/admin.d.ts +1 -10
- package/dist/tools/admin.js +2 -77
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -1,470 +1,129 @@
|
|
|
1
1
|
# mcp-google-multi
|
|
2
2
|
|
|
3
|
-
A local [MCP](https://modelcontextprotocol.io) server that gives Claude Code (and any MCP client) access to
|
|
3
|
+
A **local** [MCP](https://modelcontextprotocol.io) server that gives Claude Code (and any MCP client) access to your **Google Workspace** — Gmail, Drive, Calendar, Sheets, Docs, Contacts, Tasks, Meet, Search Console (plus optional Forms, Chat, and Workspace Admin) — across **multiple Google accounts** at once.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/mcp-google-multi)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **Multi-account** — manage any number of Google accounts from a single server
|
|
10
|
-
- **175 tools** across 13 Google services
|
|
11
|
-
- **Tiered OAuth scopes** — base scopes always granted; Forms/Chat/Alert Center are opt-in bundles; Admin scopes are per-account opt-in with a separate safety flag for destructive writes
|
|
12
|
-
- **Config-driven accounts** — defined in `.env`, no code changes needed
|
|
13
|
-
- **Auto-refresh** — OAuth tokens refresh transparently and persist to disk
|
|
14
|
-
- **Stdio transport** — runs as a local subprocess, no hosting needed
|
|
15
|
-
|
|
16
|
-
## Tools
|
|
17
|
-
|
|
18
|
-
### Gmail (21 tools)
|
|
19
|
-
|
|
20
|
-
| Tool | Description |
|
|
21
|
-
|------|-------------|
|
|
22
|
-
| `gmail_search` | Search messages with Gmail query syntax |
|
|
23
|
-
| `gmail_read` | Read a full message by ID |
|
|
24
|
-
| `gmail_read_thread` | Read all messages in a thread |
|
|
25
|
-
| `gmail_send` | Send an email (optional `htmlBody` for multipart/alternative) |
|
|
26
|
-
| `gmail_download_attachment` | Download an email attachment to local disk |
|
|
27
|
-
| `gmail_create_draft` | Create a draft (optional `htmlBody` for multipart/alternative) |
|
|
28
|
-
| `gmail_modify_labels` | Add/remove labels on a message (star, archive, mark read, etc.) |
|
|
29
|
-
| `gmail_trash` | Move a message to Trash (recoverable) |
|
|
30
|
-
| `gmail_delete` | Permanently delete a message (irreversible) |
|
|
31
|
-
| `gmail_batch_modify` | Bulk add/remove labels across up to 1000 messages |
|
|
32
|
-
| `gmail_batch_delete` | Permanently delete multiple messages (irreversible) |
|
|
33
|
-
| `gmail_list_drafts` | List all drafts |
|
|
34
|
-
| `gmail_get_draft` | Read a specific draft |
|
|
35
|
-
| `gmail_send_draft` | Send an existing draft |
|
|
36
|
-
| `gmail_list_labels` | List all labels (system + custom) |
|
|
37
|
-
| `gmail_create_label` | Create a custom label |
|
|
38
|
-
| `gmail_delete_label` | Delete a label |
|
|
39
|
-
| `gmail_get_profile` | Get account email, message count, history ID |
|
|
40
|
-
| `gmail_list_history` | Get mailbox changes since a history ID |
|
|
41
|
-
| `gmail_get_vacation` | Read vacation responder settings |
|
|
42
|
-
| `gmail_set_vacation` | Enable/disable vacation responder |
|
|
43
|
-
|
|
44
|
-
### Google Drive (35 tools)
|
|
45
|
-
|
|
46
|
-
| Tool | Description |
|
|
47
|
-
|------|-------------|
|
|
48
|
-
| `drive_search` | Search files with Drive query syntax (shared drives included) |
|
|
49
|
-
| `drive_read` | Read file content (exports Workspace docs as text) |
|
|
50
|
-
| `drive_list` | List files in a folder or root |
|
|
51
|
-
| `drive_upload` | Upload a local file to Drive (optional `convertTo` imports it as a native Google Doc/Sheet/Slides) |
|
|
52
|
-
| `drive_download` | Download a binary file to local disk |
|
|
53
|
-
| `drive_export` | Export Google Docs/Sheets/Slides to PDF, DOCX, XLSX, Markdown, etc. |
|
|
54
|
-
| `drive_create_folder` | Create a new folder |
|
|
55
|
-
| `drive_update` | Rename, move, or replace file content |
|
|
56
|
-
| `drive_delete` | Permanently delete a file (irreversible) |
|
|
57
|
-
| `drive_trash` | Move a file to trash (recoverable) |
|
|
58
|
-
| `drive_untrash` | Restore a trashed file |
|
|
59
|
-
| `drive_empty_trash` | Permanently delete every file in trash |
|
|
60
|
-
| `drive_copy` | Duplicate a file |
|
|
61
|
-
| `drive_move` | Move a file between folders |
|
|
62
|
-
| `drive_share` | Share with user/group/domain/anyone (with `transferOwnership` + `expirationTime`) |
|
|
63
|
-
| `drive_list_permissions` | List who has access to a file |
|
|
64
|
-
| `drive_permission_update` | Change a permission's role / expiration in place |
|
|
65
|
-
| `drive_remove_permission` | Revoke access |
|
|
66
|
-
| `drive_comment_create` / `_list` / `_get` / `_update` / `_delete` | Full comment CRUD with anchor support |
|
|
67
|
-
| `drive_reply_create` / `_list` / `_update` / `_delete` | Reply CRUD; reply.create accepts `action: resolve | reopen` |
|
|
68
|
-
| `drive_revision_list` / `_update` / `_delete` | Version history; `keepForever` pins against the 200-version cap |
|
|
69
|
-
| `drive_access_proposal_list` / `_resolve` | Triage "Request access" submissions |
|
|
70
|
-
| `drive_shared_drives_list` / `drive_shared_drive_get` | Shared drive discovery |
|
|
71
|
-
| `drive_get_about` | Storage quota and account info |
|
|
72
|
-
|
|
73
|
-
### Google Calendar (11 tools)
|
|
74
|
-
|
|
75
|
-
| Tool | Description |
|
|
76
|
-
|------|-------------|
|
|
77
|
-
| `calendar_list_calendars` | List all calendars |
|
|
78
|
-
| `calendar_list_events` | List/search events with time range |
|
|
79
|
-
| `calendar_get_event` | Get a single event by ID |
|
|
80
|
-
| `calendar_create_event` | Create an event |
|
|
81
|
-
| `calendar_update_event` | Update an event |
|
|
82
|
-
| `calendar_delete_event` | Delete an event |
|
|
83
|
-
| `calendar_quick_add` | Create event from natural language (e.g. "Lunch Thursday 1pm") |
|
|
84
|
-
| `calendar_move_event` | Move an event between calendars |
|
|
85
|
-
| `calendar_list_instances` | List occurrences of a recurring event |
|
|
86
|
-
| `calendar_get_freebusy` | Check free/busy times for calendars |
|
|
87
|
-
| `calendar_create_calendar` | Create a new calendar |
|
|
88
|
-
|
|
89
|
-
### Google Sheets (29 tools)
|
|
90
|
-
|
|
91
|
-
| Tool | Description |
|
|
92
|
-
|------|-------------|
|
|
93
|
-
| `sheets_create` | Create a new spreadsheet |
|
|
94
|
-
| `sheets_get` | Get spreadsheet metadata |
|
|
95
|
-
| `sheets_read_range` / `sheets_batch_read` | Read values |
|
|
96
|
-
| `sheets_write_range` / `sheets_batch_write` | Write values |
|
|
97
|
-
| `sheets_append_rows` | Append after existing data |
|
|
98
|
-
| `sheets_clear_range` / `sheets_batch_clear` | Clear values (preserves formatting) |
|
|
99
|
-
| `sheets_add_sheet` / `sheets_delete_sheet` / `sheets_duplicate_sheet` | Tab management |
|
|
100
|
-
| `sheets_update_sheet_properties` | Rename, freeze, color, hide, resize |
|
|
101
|
-
| `sheets_format_cells` | Colors, fonts, alignment, number formats |
|
|
102
|
-
| `sheets_update_borders` | Cell borders with style + color |
|
|
103
|
-
| `sheets_merge_cells` / `sheets_unmerge_cells` | Cell merging |
|
|
104
|
-
| `sheets_add_conditional_format_rule` | Boolean and gradient conditional formatting |
|
|
105
|
-
| `sheets_sort_range` | Multi-column sort |
|
|
106
|
-
| `sheets_set_basic_filter` / `sheets_clear_basic_filter` | Filter rows |
|
|
107
|
-
| `sheets_find_replace` | Regex-capable, scope-aware find/replace |
|
|
108
|
-
| `sheets_auto_resize_dimensions` | Fit rows/columns to content |
|
|
109
|
-
| `sheets_set_data_validation` | Dropdowns, checkboxes, custom rules |
|
|
110
|
-
| `sheets_add_named_range` / `sheets_delete_named_range` | Named ranges |
|
|
111
|
-
| `sheets_insert_dimension` / `sheets_delete_dimension` | Insert/delete rows or columns |
|
|
112
|
-
| `sheets_batch_update` | Generic batchUpdate escape hatch (any Request type) |
|
|
113
|
-
|
|
114
|
-
### Google Docs (27 tools)
|
|
115
|
-
|
|
116
|
-
| Tool | Description |
|
|
117
|
-
|------|-------------|
|
|
118
|
-
| `docs_create` | Create a new document |
|
|
119
|
-
| `docs_get` | Metadata + optional tab content / suggestionsViewMode |
|
|
120
|
-
| `docs_read` | Read document content as plain text |
|
|
121
|
-
| `docs_insert_text` | Insert text at position or end |
|
|
122
|
-
| `docs_replace_text` | Find and replace |
|
|
123
|
-
| `docs_delete_range` | Delete a character range |
|
|
124
|
-
| `docs_update_style` | Inline text formatting (bold, italic, font, size) |
|
|
125
|
-
| `docs_update_paragraph_style` | Alignment, heading, indents, spacing |
|
|
126
|
-
| `docs_update_document_style` | Page size, margins, header/footer behavior |
|
|
127
|
-
| `docs_insert_table` | Insert a table |
|
|
128
|
-
| `docs_modify_table` | insertRow / insertColumn / deleteRow / deleteColumn / mergeCells / unmergeCells |
|
|
129
|
-
| `docs_create_named_range` / `docs_delete_named_range` / `docs_replace_named_range_content` | Mail-merge primitive |
|
|
130
|
-
| `docs_create_paragraph_bullets` / `docs_delete_paragraph_bullets` | Bulleted/numbered lists |
|
|
131
|
-
| `docs_insert_inline_image` | PNG/JPEG/GIF image insertion |
|
|
132
|
-
| `docs_insert_page_break` / `docs_insert_section_break` | Layout breaks |
|
|
133
|
-
| `docs_create_header` / `docs_delete_header` / `docs_create_footer` / `docs_delete_footer` | Branded headers and footers |
|
|
134
|
-
| `docs_add_tab` / `docs_delete_tab` / `docs_update_tab_properties` | Tabs CRUD |
|
|
135
|
-
| `docs_batch_update` | Generic batchUpdate escape hatch (any Request type) |
|
|
136
|
-
|
|
137
|
-
### Google Contacts (9 tools)
|
|
138
|
-
|
|
139
|
-
| Tool | Description |
|
|
140
|
-
|------|-------------|
|
|
141
|
-
| `contacts_search` | Search contacts |
|
|
142
|
-
| `contacts_get` | Get one contact |
|
|
143
|
-
| `contacts_list` | List contacts (paginated) |
|
|
144
|
-
| `contacts_create` | Create a contact |
|
|
145
|
-
| `contacts_update` | Update a contact |
|
|
146
|
-
| `contacts_delete` | Delete a contact |
|
|
147
|
-
| `contacts_groups_list` | List groups |
|
|
148
|
-
| `contacts_group_members` | List members of a group |
|
|
149
|
-
| `contacts_group_create` | Create a group |
|
|
150
|
-
|
|
151
|
-
### Google Search Console (10 tools)
|
|
152
|
-
|
|
153
|
-
| Tool | Description |
|
|
154
|
-
|------|-------------|
|
|
155
|
-
| `searchconsole_sites_list` | List Search Console properties |
|
|
156
|
-
| `searchconsole_sites_get` | Get a property |
|
|
157
|
-
| `searchconsole_sites_add` | Add a property |
|
|
158
|
-
| `searchconsole_sites_delete` | Remove a property |
|
|
159
|
-
| `searchconsole_sitemaps_list` | List sitemaps |
|
|
160
|
-
| `searchconsole_sitemaps_get` | Sitemap status |
|
|
161
|
-
| `searchconsole_sitemaps_submit` | Submit a sitemap |
|
|
162
|
-
| `searchconsole_sitemaps_delete` | Delete a sitemap |
|
|
163
|
-
| `searchconsole_searchanalytics_query` | Query search analytics |
|
|
164
|
-
| `searchconsole_url_inspect` | Inspect a URL |
|
|
165
|
-
|
|
166
|
-
### Google Tasks (12 tools) — _new in v4_
|
|
167
|
-
|
|
168
|
-
| Tool | Description |
|
|
169
|
-
|------|-------------|
|
|
170
|
-
| `tasks_lists_list` / `tasks_list_get` / `tasks_list_insert` / `tasks_list_update` / `tasks_list_delete` | Tasklist management |
|
|
171
|
-
| `tasks_list` | List tasks (filter by completion, due, updated time) |
|
|
172
|
-
| `tasks_get` / `tasks_insert` / `tasks_update` / `tasks_delete` | Task CRUD |
|
|
173
|
-
| `tasks_move` | Re-parent / re-position / move to another list |
|
|
174
|
-
| `tasks_clear` | Delete every completed task |
|
|
175
|
-
|
|
176
|
-
### Google Meet (5 tools) — _new in v4_
|
|
177
|
-
|
|
178
|
-
| Tool | Description |
|
|
179
|
-
|------|-------------|
|
|
180
|
-
| `meet_conference_records_list` | List past Meet sessions |
|
|
181
|
-
| `meet_conference_record_get` | Get one record |
|
|
182
|
-
| `meet_recordings_list` | Recordings on a record |
|
|
183
|
-
| `meet_transcripts_list` | Transcripts on a record |
|
|
184
|
-
| `meet_transcript_entries_list` | Per-speaker transcript text |
|
|
185
|
-
|
|
186
|
-
### Google Forms (4 tools, optional bundle) — _new in v4_
|
|
187
|
-
|
|
188
|
-
Enable with `GOOGLE_OPTIONAL_SCOPES=forms` in `.env`.
|
|
189
|
-
|
|
190
|
-
| Tool | Description |
|
|
191
|
-
|------|-------------|
|
|
192
|
-
| `forms_get` | Form definition |
|
|
193
|
-
| `forms_responses_list` | List responses with filter |
|
|
194
|
-
| `forms_response_get` | Single response |
|
|
195
|
-
| `forms_watches_list` | List Pub/Sub watches |
|
|
196
|
-
|
|
197
|
-
### Google Chat (4 tools, optional bundle) — _new in v4_
|
|
198
|
-
|
|
199
|
-
Enable with `GOOGLE_OPTIONAL_SCOPES=chat` in `.env` (combine: `GOOGLE_OPTIONAL_SCOPES=forms,chat`).
|
|
200
|
-
|
|
201
|
-
| Tool | Description |
|
|
202
|
-
|------|-------------|
|
|
203
|
-
| `chat_spaces_list` | Spaces the user is in |
|
|
204
|
-
| `chat_spaces_get` | One space |
|
|
205
|
-
| `chat_messages_create` | Send text or Card v2 |
|
|
206
|
-
| `chat_messages_list` | List messages with filter / orderBy |
|
|
207
|
-
|
|
208
|
-
### Google Workspace Admin (6 tools, admin bundle) — _new in v4_
|
|
209
|
-
|
|
210
|
-
Enable per-account with `GOOGLE_ADMIN_ACCOUNTS=alias1,alias2` in `.env`. Requires the account to be a Workspace super-admin. Personal `@gmail.com` accounts will 403 — never list them here. Destructive writes additionally require `GOOGLE_ALLOW_ADMIN_WRITES=true`.
|
|
211
|
-
|
|
212
|
-
| Tool | Description |
|
|
213
|
-
|------|-------------|
|
|
214
|
-
| `reports_activities_list` | Workspace audit log (login, drive, gmail, admin, token, etc.) |
|
|
215
|
-
| `admin_users_list` / `admin_users_get` | User directory reads |
|
|
216
|
-
| `admin_users_update` | User edits (gated, see env flag above) |
|
|
217
|
-
| `admin_groups_list` / `admin_group_members_list` | Group + member reads |
|
|
218
|
-
|
|
219
|
-
Every tool accepts an `account` parameter matching one of your configured aliases.
|
|
220
|
-
|
|
221
|
-
### Google Alert Center (2 tools, optional bundle) — _new in v4_
|
|
222
|
-
|
|
223
|
-
Enable with `GOOGLE_OPTIONAL_SCOPES=alertcenter` in `.env`.
|
|
224
|
-
|
|
225
|
-
| Tool | Description |
|
|
226
|
-
|------|-------------|
|
|
227
|
-
| `alertcenter_alerts_list` / `alertcenter_alert_get` | Security alerts (suspicious login, phishing, leaked password, Drive exfil) |
|
|
228
|
-
|
|
229
|
-
> **⚠ Requires service-account domain-wide delegation.** Unlike every other bundle, the Alert Center `apps.alerts` scope **cannot** be granted through this server's interactive user-consent OAuth flow — Google rejects it with `Error 400: invalid_scope` / "Some requested scopes cannot be shown". Per [Google's docs](https://developers.google.com/workspace/admin/alertcenter/guides/auth), Alert Center requires a service account with domain-wide delegation. This server is user-OAuth only, so enabling this bundle declares the scope and registers the tools, but the API will reject the resulting tokens until service-account auth is added (see [#4](https://github.com/bakissation/mcp-google-multi/issues/4)). The bundle is kept separate precisely so this limitation never blocks the working admin tools above.
|
|
230
|
-
|
|
231
|
-
## Prerequisites
|
|
232
|
-
|
|
233
|
-
- Node.js 18+
|
|
234
|
-
- A Google Cloud project with the relevant APIs enabled (see step 1 below)
|
|
235
|
-
- An OAuth 2.0 Client ID (Desktop app type)
|
|
7
|
+
> Open-source and **funded by [IdeaCrafters](https://github.com/IdeaCraftersHQ)** — the studio that pays for its development and upkeep.
|
|
236
8
|
|
|
237
|
-
|
|
9
|
+
- 🔑 **Multi-account** — drive any number of your Google accounts from one server, each by a short alias.
|
|
10
|
+
- 🔒 **Secure by default** — refresh tokens **encrypted at rest** (AES-256-GCM); **writes are deny-by-default**; no telemetry — it talks only to Google.
|
|
11
|
+
- 📦 **npm-first** — install and run with `npx`; everything configured through env vars.
|
|
12
|
+
- 🧰 **~170 tools** across 12 services → full list in **[COVERAGE.md](./COVERAGE.md)**.
|
|
238
13
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
1. Go to [Google Cloud Console](https://console.cloud.google.com).
|
|
242
|
-
2. Create or select a project.
|
|
243
|
-
3. Enable the APIs you intend to use:
|
|
244
|
-
- **Always required:** [Gmail API](https://console.cloud.google.com/apis/library/gmail.googleapis.com), [Google Drive API](https://console.cloud.google.com/apis/library/drive.googleapis.com), [Google Calendar API](https://console.cloud.google.com/apis/library/calendar-json.googleapis.com), [Google Sheets API](https://console.cloud.google.com/apis/library/sheets.googleapis.com), [Google Docs API](https://console.cloud.google.com/apis/library/docs.googleapis.com), [People API](https://console.cloud.google.com/apis/library/people.googleapis.com), [Search Console API](https://console.cloud.google.com/apis/library/searchconsole.googleapis.com), [Google Tasks API](https://console.cloud.google.com/apis/library/tasks.googleapis.com), [Google Meet API](https://console.cloud.google.com/apis/library/meet.googleapis.com).
|
|
245
|
-
- **Optional bundles (only if you enable them):** [Google Forms API](https://console.cloud.google.com/apis/library/forms.googleapis.com), [Google Chat API](https://console.cloud.google.com/apis/library/chat.googleapis.com), [Alert Center API](https://console.cloud.google.com/apis/library/alertcenter.googleapis.com) (the `alertcenter` bundle also needs service-account domain-wide delegation — see the Alert Center section above).
|
|
246
|
-
- **Admin bundle (only if you set `GOOGLE_ADMIN_ACCOUNTS`):** [Admin SDK API](https://console.cloud.google.com/apis/library/admin.googleapis.com).
|
|
247
|
-
4. Go to **APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID**.
|
|
248
|
-
5. Application type: **Desktop app**.
|
|
249
|
-
6. Add authorized redirect URI: `http://localhost:4242/oauth2callback`.
|
|
250
|
-
7. Copy the **Client ID** and **Client Secret**.
|
|
14
|
+
> v5 is **local + user-OAuth only**. Service accounts and hosting (and the APIs they unlock) are on the [roadmap](https://github.com/bakissation/mcp-google-multi/milestones). **Upgrading from v4?** Jump to [Upgrading](#upgrading-from-v4).
|
|
251
15
|
|
|
252
|
-
|
|
16
|
+
## Quick start
|
|
253
17
|
|
|
254
|
-
**
|
|
18
|
+
You need **Node 20+**, a Google Cloud OAuth client (~2 min — [setup below](#google-cloud-setup)), and a random 32-byte key.
|
|
255
19
|
|
|
256
20
|
```bash
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
Published with channel dist-tags — `@latest` (stable), `@dev` (alpha), `@staging` (beta); e.g. `npm i -g mcp-google-multi@dev` for the latest alpha.
|
|
262
|
-
|
|
263
|
-
**Option B — from source:**
|
|
264
|
-
|
|
265
|
-
```bash
|
|
266
|
-
git clone https://github.com/bakissation/mcp-google-multi.git
|
|
267
|
-
cd mcp-google-multi
|
|
268
|
-
npm install && npm run build
|
|
269
|
-
cp .env.example .env
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
Create a `.env` (from source, `.env.example` is the template; from npm, make one in the directory you'll run the server from) with:
|
|
21
|
+
# 1) install
|
|
22
|
+
npm i -g mcp-google-multi
|
|
273
23
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
GOOGLE_CLIENT_SECRET
|
|
24
|
+
# 2) put your config + creds in the environment (see "Configuration").
|
|
25
|
+
# Easiest for a quick try — export them, or drop a .env in your working dir:
|
|
26
|
+
# GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_ACCOUNTS, MASTER_KEY, GOOGLE_PROFILE
|
|
277
27
|
|
|
278
|
-
#
|
|
279
|
-
|
|
28
|
+
# 3) authenticate each account (opens a browser; one-time per account)
|
|
29
|
+
mcp-google-multi auth --account work
|
|
30
|
+
mcp-google-multi auth --account personal
|
|
280
31
|
|
|
281
|
-
#
|
|
282
|
-
|
|
283
|
-
# GOOGLE_OPTIONAL_SCOPES=forms,chat
|
|
284
|
-
|
|
285
|
-
# Optional (v4): grant Workspace admin scopes to specific accounts
|
|
286
|
-
# GOOGLE_ADMIN_ACCOUNTS=work
|
|
287
|
-
|
|
288
|
-
# Optional (v4): unlock destructive admin writes (admin_users_update)
|
|
289
|
-
# GOOGLE_ALLOW_ADMIN_WRITES=true
|
|
32
|
+
# 4) register with Claude Code
|
|
33
|
+
claude mcp add google-multi -s user -- npx -y mcp-google-multi
|
|
290
34
|
```
|
|
291
35
|
|
|
292
|
-
|
|
36
|
+
Restart your MCP client and the tools appear. Tokens are written **encrypted** to `~/.config/mcp-google-multi/tokens/` (override with `TOKEN_STORE_PATH`) — useless to anyone without your `MASTER_KEY`.
|
|
293
37
|
|
|
294
|
-
|
|
295
|
-
npm run build
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### 4. Authenticate Accounts
|
|
299
|
-
|
|
300
|
-
```bash
|
|
301
|
-
npm run auth -- work # opens browser → log in with you@company.com
|
|
302
|
-
npm run auth -- personal # opens browser → log in with you@gmail.com
|
|
303
|
-
```
|
|
38
|
+
Generate a key: `openssl rand -base64 32`.
|
|
304
39
|
|
|
305
|
-
|
|
40
|
+
## Recommended: keep secrets in a vault (Infisical)
|
|
306
41
|
|
|
307
|
-
|
|
42
|
+
A plaintext `.env` is fine to try it out, but for a daily driver, **don't leave `GOOGLE_CLIENT_SECRET` + `MASTER_KEY` on disk** — inject them at launch from a secrets manager. The server just reads `process.env` (it has no idea where the values come from), so wrap it with [Infisical](https://infisical.com):
|
|
308
43
|
|
|
309
44
|
```bash
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
"mcpServers": {
|
|
318
|
-
"google-multi": {
|
|
319
|
-
"command": "node",
|
|
320
|
-
"args": ["/absolute/path/to/mcp-google-multi/dist/index.js"]
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
45
|
+
#!/usr/bin/env bash
|
|
46
|
+
# ~/.local/bin/mcp-google-multi-run — chmod +x, then register this as the MCP command
|
|
47
|
+
set -euo pipefail
|
|
48
|
+
export INFISICAL_TOKEN="$(infisical login --method=universal-auth \
|
|
49
|
+
--client-id "$YOUR_CLIENT_ID" --client-secret "$YOUR_CLIENT_SECRET" --plain --silent)"
|
|
50
|
+
exec infisical run --projectId <project> --env prod --path /mcp-google-multi \
|
|
51
|
+
-- npx -y mcp-google-multi
|
|
324
52
|
```
|
|
325
53
|
|
|
326
|
-
If you installed from npm, point at the package instead and pass config via `env` (authenticate first with `mcp-google-multi auth --account <alias>`):
|
|
327
|
-
|
|
328
|
-
```json
|
|
329
|
-
{
|
|
330
|
-
"mcpServers": {
|
|
331
|
-
"google-multi": {
|
|
332
|
-
"command": "npx",
|
|
333
|
-
"args": ["-y", "mcp-google-multi"],
|
|
334
|
-
"env": {
|
|
335
|
-
"GOOGLE_CLIENT_ID": "your_client_id_here",
|
|
336
|
-
"GOOGLE_CLIENT_SECRET": "your_client_secret_here",
|
|
337
|
-
"GOOGLE_ACCOUNTS": "work:you@company.com,personal:you@gmail.com"
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
## Migrating from v3
|
|
345
|
-
|
|
346
|
-
v4.0.0 grows the base OAuth scope set (Tasks and Meet are now included by default). Existing v3 tokens lack those scopes and the corresponding tools will 403.
|
|
347
|
-
|
|
348
|
-
1. `git pull && npm install && npm run build`.
|
|
349
|
-
2. Re-authenticate every account: `npm run auth -- <alias>` for each alias.
|
|
350
|
-
3. If you want Forms or Chat tools: set `GOOGLE_OPTIONAL_SCOPES=forms,chat` in `.env` **before** re-authing.
|
|
351
|
-
4. If you're a Workspace admin: list relevant accounts in `GOOGLE_ADMIN_ACCOUNTS` **before** re-authing those accounts. Set `GOOGLE_ALLOW_ADMIN_WRITES=true` only if you need destructive admin operations.
|
|
352
|
-
5. In Google Cloud Console, enable any new APIs you'll use (Tasks, Meet, Forms, Chat, Admin SDK, Alert Center).
|
|
353
|
-
|
|
354
|
-
## Adding / Removing Accounts
|
|
355
|
-
|
|
356
|
-
Edit the `GOOGLE_ACCOUNTS` variable in `.env`, rebuild, and authenticate the new account:
|
|
357
|
-
|
|
358
54
|
```bash
|
|
359
|
-
|
|
360
|
-
# .env: GOOGLE_ACCOUNTS=work:you@company.com,personal:you@gmail.com,freelance:you@freelance.com
|
|
361
|
-
|
|
362
|
-
npm run build
|
|
363
|
-
npm run auth -- freelance
|
|
55
|
+
claude mcp add google-multi -s user -- ~/.local/bin/mcp-google-multi-run
|
|
364
56
|
```
|
|
365
57
|
|
|
366
|
-
|
|
58
|
+
Now the only thing on disk is the **encrypted** token store. Pass the token via the `INFISICAL_TOKEN` env var (as above), **not** a `--token` flag, so it never shows up in `ps`. (Any secrets manager works — Doppler, Vault, 1Password CLI, etc. — the pattern is the same.)
|
|
367
59
|
|
|
368
|
-
##
|
|
60
|
+
## Configuration
|
|
369
61
|
|
|
370
|
-
|
|
62
|
+
| Env var | Required | Description |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` | ✓ | OAuth **Desktop** client from Google Cloud |
|
|
65
|
+
| `GOOGLE_ACCOUNTS` | ✓ | `alias:email,…` — e.g. `work:you@co.com,personal:you@gmail.com` |
|
|
66
|
+
| `MASTER_KEY` | ✓ | base64 32-byte key that encrypts the token store (`openssl rand -base64 32`) |
|
|
67
|
+
| `GOOGLE_PROFILE` | — | write policy: `read-only` (default) · `safe-writes` · `full-writes` |
|
|
68
|
+
| `GOOGLE_READ_ONLY` | — | `true` = hard kill-switch for all writes |
|
|
69
|
+
| `GOOGLE_WRITE_ALLOW` / `GOOGLE_WRITE_DENY` | — | glob overrides, e.g. `calendar:*`, `*:delete*` |
|
|
70
|
+
| `GOOGLE_OPTIONAL_SCOPES` | — | extra bundles: `forms`, `chat` |
|
|
71
|
+
| `GOOGLE_ADMIN_ACCOUNTS` | — | aliases granted Workspace-admin scopes (the account's own super-admin OAuth) |
|
|
72
|
+
| `TOKEN_STORE_PATH` | — | override the encrypted token dir (default: `~/.config/mcp-google-multi/tokens`) |
|
|
371
73
|
|
|
372
|
-
|
|
373
|
-
|-------|--------|
|
|
374
|
-
| `gmail.modify` | Read, label, trash, delete emails |
|
|
375
|
-
| `gmail.send` | Send emails |
|
|
376
|
-
| `drive` | Full Drive access (read, upload, share, comments, etc.) |
|
|
377
|
-
| `calendar` | Full calendar access |
|
|
378
|
-
| `spreadsheets` | Read/write Google Sheets |
|
|
379
|
-
| `documents` | Read/write Google Docs |
|
|
380
|
-
| `contacts` | Read/write Google Contacts |
|
|
381
|
-
| `webmasters` | Google Search Console |
|
|
382
|
-
| `tasks` | Read/write Google Tasks |
|
|
383
|
-
| `meetings.space.readonly` | Read past Meet conference records and transcripts |
|
|
74
|
+
Inspect the resolved setup any time: `mcp-google-multi config check`.
|
|
384
75
|
|
|
385
|
-
|
|
76
|
+
## Write-control (deny-by-default)
|
|
386
77
|
|
|
387
|
-
|
|
388
|
-
|------------|--------|
|
|
389
|
-
| `forms` | `forms.body`, `forms.responses.readonly` |
|
|
390
|
-
| `chat` | `chat.spaces`, `chat.messages`, `chat.messages.create` |
|
|
391
|
-
| `alertcenter` | `apps.alerts` — ⚠ requires service-account domain-wide delegation; not grantable via user OAuth (see Alert Center section) |
|
|
78
|
+
Reads are never gated. **Every create/update/delete is off until you opt in** — pick a profile:
|
|
392
79
|
|
|
393
|
-
|
|
80
|
+
| `GOOGLE_PROFILE` | Allows |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `read-only` (default) | reads only |
|
|
83
|
+
| `safe-writes` | create + update (deletes still blocked) |
|
|
84
|
+
| `full-writes` | everything |
|
|
394
85
|
|
|
395
|
-
|
|
86
|
+
`GOOGLE_READ_ONLY=true` overrides all. For fine control: `GOOGLE_WRITE_ALLOW="calendar:*, sheets:update*"` and `GOOGLE_WRITE_DENY="*:delete*"` (deny wins). `mcp-google-multi config check` prints the resolved policy and exactly which tools are enabled.
|
|
396
87
|
|
|
397
|
-
|
|
398
|
-
|-------|--------|
|
|
399
|
-
| `admin.reports.audit.readonly` | Workspace audit log |
|
|
400
|
-
| `admin.directory.user` | Read/write Workspace users (writes also gated by `GOOGLE_ALLOW_ADMIN_WRITES`) |
|
|
401
|
-
| `admin.directory.group.readonly` | Read groups |
|
|
402
|
-
| `admin.directory.group.member.readonly` | Read group members |
|
|
88
|
+
## What's covered
|
|
403
89
|
|
|
404
|
-
|
|
90
|
+
~170 tools across Gmail, Drive, Calendar, Sheets, Docs, Contacts, Search Console, Tasks, Meet, and (optional) Forms, Chat, Workspace Admin. **Full per-tool list → [COVERAGE.md](./COVERAGE.md).** Every tool takes an `account` argument matching one of your aliases.
|
|
405
91
|
|
|
406
|
-
|
|
407
|
-
mcp-google-multi/
|
|
408
|
-
├── src/
|
|
409
|
-
│ ├── index.ts # Entry point: MCP server or auth CLI
|
|
410
|
-
│ ├── accounts.ts # Account config parser (reads from .env)
|
|
411
|
-
│ ├── auth.ts # Scope tier resolution + OAuth flow
|
|
412
|
-
│ ├── client.ts # OAuth2Client factory with auto-refresh
|
|
413
|
-
│ ├── types.ts # Shared TypeScript types
|
|
414
|
-
│ └── tools/
|
|
415
|
-
│ ├── _errors.ts # Shared googleapis error → MCP response mapper
|
|
416
|
-
│ ├── gmail.ts # Gmail (21)
|
|
417
|
-
│ ├── drive.ts # Drive (35)
|
|
418
|
-
│ ├── calendar.ts # Calendar (11)
|
|
419
|
-
│ ├── sheets.ts # Sheets (29)
|
|
420
|
-
│ ├── docs.ts # Docs (27)
|
|
421
|
-
│ ├── contacts.ts # Contacts (9)
|
|
422
|
-
│ ├── searchconsole.ts # Search Console (10)
|
|
423
|
-
│ ├── tasks.ts # Tasks (12) — v4
|
|
424
|
-
│ ├── meet.ts # Meet (5) — v4
|
|
425
|
-
│ ├── forms.ts # Forms (4, optional) — v4
|
|
426
|
-
│ ├── chat.ts # Chat (4, optional) — v4
|
|
427
|
-
│ └── admin.ts # Admin SDK (6, admin) + Alert Center (2, alertcenter bundle) — v4
|
|
428
|
-
├── tests/ # vitest unit tests (gmail-mime, path-safety, field-mask helpers)
|
|
429
|
-
├── tokens/ # OAuth tokens per account (gitignored)
|
|
430
|
-
├── dist/ # Compiled output (gitignored)
|
|
431
|
-
├── .env # Your credentials (gitignored)
|
|
432
|
-
├── .env.example # Template for .env
|
|
433
|
-
├── CHANGELOG.md
|
|
434
|
-
├── CLAUDE.md # Conventions for AI assistants working on this codebase
|
|
435
|
-
├── package.json
|
|
436
|
-
├── tsconfig.json
|
|
437
|
-
└── LICENSE
|
|
438
|
-
```
|
|
92
|
+
## Google Cloud setup
|
|
439
93
|
|
|
440
|
-
|
|
94
|
+
1. [Google Cloud Console](https://console.cloud.google.com) → create or select a project.
|
|
95
|
+
2. Enable the APIs you'll use: Gmail, Drive, Calendar, Sheets, Docs, People, Search Console, Tasks, Meet (+ Forms / Chat / Admin SDK if you enable those bundles).
|
|
96
|
+
3. **APIs & Services → Credentials → Create Credentials → OAuth client ID → Desktop app**.
|
|
97
|
+
4. Add the redirect URI `http://localhost:4242/oauth2callback`.
|
|
98
|
+
5. Copy the **Client ID** + **Client Secret** into your environment.
|
|
441
99
|
|
|
442
|
-
|
|
100
|
+
## Upgrading from v4
|
|
443
101
|
|
|
444
|
-
|
|
102
|
+
v5 is a breaking change, but the migration is a one-time, ~2-minute step:
|
|
445
103
|
|
|
446
|
-
|
|
104
|
+
1. Update: `npm i -g mcp-google-multi@latest` (or update your client config).
|
|
105
|
+
2. Add **`MASTER_KEY`** to your environment (`openssl rand -base64 32`) — now required.
|
|
106
|
+
3. Encrypt existing tokens: `mcp-google-multi migrate-tokens` (reads your old `tokens/<alias>/token.json` and encrypts them) — or just re-auth each account.
|
|
107
|
+
4. Writes are now **deny-by-default** — set `GOOGLE_PROFILE=safe-writes` (or `full-writes`) to keep writing. (`GOOGLE_ALLOW_ADMIN_WRITES` is gone — replaced by write-control profiles.)
|
|
447
108
|
|
|
448
|
-
|
|
109
|
+
## Security
|
|
449
110
|
|
|
450
|
-
|
|
111
|
+
Your OAuth, your machine. Refresh tokens are **AES-256-GCM encrypted at rest** (decryptable only with your `MASTER_KEY`), writes are deny-by-default, and the server has **no telemetry** — it connects only to Google's APIs. Found a vulnerability? Report it privately — see [SECURITY.md](./SECURITY.md), never a public issue.
|
|
451
112
|
|
|
452
|
-
|
|
113
|
+
## Roadmap
|
|
453
114
|
|
|
454
|
-
|
|
115
|
+
Maintainer-led. Direction is tracked publicly as **[GitHub Milestones](https://github.com/bakissation/mcp-google-multi/milestones)** (discover-first tooling → exhaustive API coverage → service accounts + hosting in v6). Not accepting unsolicited feature PRs; bug reports are welcome.
|
|
455
116
|
|
|
456
117
|
## Contributing
|
|
457
118
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
By participating you agree to the [Code of Conduct](CODE_OF_CONDUCT.md). For security issues, **do not open a public issue** — see [SECURITY.md](SECURITY.md).
|
|
119
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) and the [Code of Conduct](./CODE_OF_CONDUCT.md). Security issues go to [SECURITY.md](./SECURITY.md), never a public issue.
|
|
461
120
|
|
|
462
|
-
##
|
|
121
|
+
## Credits
|
|
463
122
|
|
|
464
|
-
**Abdelbaki Berkati** — [berkati.xyz](https://berkati.xyz) · [@bakissation](https://github.com/bakissation)
|
|
123
|
+
Built and maintained by **Abdelbaki Berkati** — [berkati.xyz](https://berkati.xyz) · [@bakissation](https://github.com/bakissation). [Read the case study →](https://berkati.xyz/case-studies/mcp-google-multi/)
|
|
465
124
|
|
|
466
|
-
|
|
125
|
+
Development is **funded by [IdeaCrafters](https://ideacrafters.com)** ([@IdeaCraftersHQ](https://github.com/IdeaCraftersHQ)) — the studio that pays for this OSS to exist.
|
|
467
126
|
|
|
468
127
|
## License
|
|
469
128
|
|
|
470
|
-
[MIT](LICENSE)
|
|
129
|
+
[MIT](./LICENSE)
|
package/dist/accounts.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import dotenv from 'dotenv';
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
4
5
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
dotenv.config();
|
|
5
7
|
dotenv.config({ path: path.resolve(__dirname, '..', '.env') });
|
|
8
|
+
const defaultTokenDir = path.join(process.env.XDG_CONFIG_HOME || path.join(homedir(), '.config'), 'mcp-google-multi', 'tokens');
|
|
6
9
|
const tokenDir = process.env.TOKEN_STORE_PATH
|
|
7
10
|
? path.resolve(process.env.TOKEN_STORE_PATH)
|
|
8
|
-
:
|
|
11
|
+
: defaultTokenDir;
|
|
9
12
|
/**
|
|
10
13
|
* Parse accounts from the GOOGLE_ACCOUNTS env var.
|
|
11
14
|
* Format: "alias1:email1,alias2:email2,..."
|
package/dist/auth.d.ts
CHANGED
|
@@ -10,6 +10,4 @@ export declare function getAdminAccounts(): string[];
|
|
|
10
10
|
* Resolves env flags: GOOGLE_OPTIONAL_SCOPES (global) and GOOGLE_ADMIN_ACCOUNTS (per-account allowlist).
|
|
11
11
|
*/
|
|
12
12
|
export declare function resolveScopesForAccount(alias: string): string[];
|
|
13
|
-
/** True if admin writes are explicitly enabled. Default refuses to prevent accidents on small orgs. */
|
|
14
|
-
export declare function adminWritesEnabled(): boolean;
|
|
15
13
|
export declare function runAuthFlow(args: string[]): Promise<void>;
|
package/dist/auth.js
CHANGED
|
@@ -36,13 +36,6 @@ export const OPTIONAL_SCOPE_BUNDLES = {
|
|
|
36
36
|
'https://www.googleapis.com/auth/chat.messages',
|
|
37
37
|
'https://www.googleapis.com/auth/chat.messages.create',
|
|
38
38
|
],
|
|
39
|
-
// Alert Center's apps.alerts scope is NOT grantable through the interactive
|
|
40
|
-
// user-consent flow this server uses — it requires a service account with
|
|
41
|
-
// domain-wide delegation. It lives in its own opt-in bundle so it never
|
|
42
|
-
// blocks the working Admin SDK admin scopes. See README "Alert Center".
|
|
43
|
-
alertcenter: [
|
|
44
|
-
'https://www.googleapis.com/auth/apps.alerts',
|
|
45
|
-
],
|
|
46
39
|
};
|
|
47
40
|
export const ADMIN_SCOPES = [
|
|
48
41
|
'https://www.googleapis.com/auth/admin.reports.audit.readonly',
|
|
@@ -79,10 +72,6 @@ export function resolveScopesForAccount(alias) {
|
|
|
79
72
|
}
|
|
80
73
|
return Array.from(new Set(scopes));
|
|
81
74
|
}
|
|
82
|
-
/** True if admin writes are explicitly enabled. Default refuses to prevent accidents on small orgs. */
|
|
83
|
-
export function adminWritesEnabled() {
|
|
84
|
-
return process.env.GOOGLE_ALLOW_ADMIN_WRITES === 'true';
|
|
85
|
-
}
|
|
86
75
|
export async function runAuthFlow(args) {
|
|
87
76
|
const accountIdx = args.indexOf('--account');
|
|
88
77
|
if (accountIdx === -1 || !args[accountIdx + 1]) {
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { registerTasksTools } from './tools/tasks.js';
|
|
|
16
16
|
import { registerMeetTools } from './tools/meet.js';
|
|
17
17
|
import { registerFormsTools } from './tools/forms.js';
|
|
18
18
|
import { registerChatTools } from './tools/chat.js';
|
|
19
|
-
import { registerAdminTools
|
|
19
|
+
import { registerAdminTools } from './tools/admin.js';
|
|
20
20
|
import { getOptionalBundles, getAdminAccounts } from './auth.js';
|
|
21
21
|
import { ToolRegistry } from './registry.js';
|
|
22
22
|
import { resolvePolicy, isAllowed, describePolicy } from './write-control.js';
|
|
@@ -38,8 +38,6 @@ function buildRegistry(server, policy) {
|
|
|
38
38
|
registerFormsTools(registry);
|
|
39
39
|
if (optional.has('chat'))
|
|
40
40
|
registerChatTools(registry);
|
|
41
|
-
if (optional.has('alertcenter'))
|
|
42
|
-
registerAlertCenterTools(registry);
|
|
43
41
|
if (getAdminAccounts().length > 0)
|
|
44
42
|
registerAdminTools(registry);
|
|
45
43
|
return registry;
|
package/dist/tools/admin.d.ts
CHANGED
|
@@ -3,15 +3,6 @@ import type { ToolRegistry } from '../registry.js';
|
|
|
3
3
|
* Admin SDK tools require Workspace super-admin (or delegated admin) privileges on the target account.
|
|
4
4
|
* Personal `@gmail.com` accounts will 403 on every endpoint.
|
|
5
5
|
*
|
|
6
|
-
* Writes are gated
|
|
7
|
-
* (a stray users.update on a 3-person Workspace is a bad day).
|
|
6
|
+
* Writes (e.g. admin_users_update) are gated by write-control like any CUD tool.
|
|
8
7
|
*/
|
|
9
8
|
export declare function registerAdminTools(server: ToolRegistry): void;
|
|
10
|
-
/**
|
|
11
|
-
* Alert Center tools. Gated behind the `alertcenter` optional bundle, NOT the
|
|
12
|
-
* admin bundle: the apps.alerts scope cannot be granted via this server's
|
|
13
|
-
* interactive user-consent OAuth flow — it requires a service account with
|
|
14
|
-
* domain-wide delegation. Registered separately so a missing/ungrantable
|
|
15
|
-
* apps.alerts scope never blocks the working Admin SDK admin tools.
|
|
16
|
-
*/
|
|
17
|
-
export declare function registerAlertCenterTools(server: ToolRegistry): void;
|
package/dist/tools/admin.js
CHANGED
|
@@ -4,14 +4,12 @@ import { google } from 'googleapis';
|
|
|
4
4
|
import { ACCOUNTS } from '../accounts.js';
|
|
5
5
|
import { getClient } from '../client.js';
|
|
6
6
|
import { handleGoogleApiError } from './_errors.js';
|
|
7
|
-
import { adminWritesEnabled } from '../auth.js';
|
|
8
7
|
const accountEnum = z.enum(ACCOUNTS);
|
|
9
8
|
/**
|
|
10
9
|
* Admin SDK tools require Workspace super-admin (or delegated admin) privileges on the target account.
|
|
11
10
|
* Personal `@gmail.com` accounts will 403 on every endpoint.
|
|
12
11
|
*
|
|
13
|
-
* Writes are gated
|
|
14
|
-
* (a stray users.update on a 3-person Workspace is a bad day).
|
|
12
|
+
* Writes (e.g. admin_users_update) are gated by write-control like any CUD tool.
|
|
15
13
|
*/
|
|
16
14
|
export function registerAdminTools(server) {
|
|
17
15
|
// ─── Reports / audit log ───────────────────────────────────────────────
|
|
@@ -125,7 +123,7 @@ export function registerAdminTools(server) {
|
|
|
125
123
|
}
|
|
126
124
|
});
|
|
127
125
|
server.registerTool('admin_users_update', {
|
|
128
|
-
description: 'Update a Workspace user (PATCH semantics).
|
|
126
|
+
description: 'Update a Workspace user (PATCH semantics). Gated by write-control (a CUD tool).',
|
|
129
127
|
inputSchema: {
|
|
130
128
|
account: accountEnum.describe('Google account alias (must be a Workspace admin)'),
|
|
131
129
|
userKey: z.string().describe('User email or ID'),
|
|
@@ -138,18 +136,6 @@ export function registerAdminTools(server) {
|
|
|
138
136
|
},
|
|
139
137
|
}, async ({ account, userKey, givenName, familyName, suspended, password, changePasswordAtNextLogin, orgUnitPath }) => {
|
|
140
138
|
try {
|
|
141
|
-
if (!adminWritesEnabled()) {
|
|
142
|
-
return {
|
|
143
|
-
content: [{
|
|
144
|
-
type: 'text',
|
|
145
|
-
text: JSON.stringify({
|
|
146
|
-
error: 'admin_writes_disabled',
|
|
147
|
-
hint: 'Admin write operations are disabled by default. Set GOOGLE_ALLOW_ADMIN_WRITES=true in .env and restart to enable.',
|
|
148
|
-
}),
|
|
149
|
-
}],
|
|
150
|
-
isError: true,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
139
|
const auth = await getClient(account);
|
|
154
140
|
const directory = google.admin({ version: 'directory_v1', auth });
|
|
155
141
|
const requestBody = {};
|
|
@@ -242,67 +228,6 @@ export function registerAdminTools(server) {
|
|
|
242
228
|
}
|
|
243
229
|
});
|
|
244
230
|
}
|
|
245
|
-
/**
|
|
246
|
-
* Alert Center tools. Gated behind the `alertcenter` optional bundle, NOT the
|
|
247
|
-
* admin bundle: the apps.alerts scope cannot be granted via this server's
|
|
248
|
-
* interactive user-consent OAuth flow — it requires a service account with
|
|
249
|
-
* domain-wide delegation. Registered separately so a missing/ungrantable
|
|
250
|
-
* apps.alerts scope never blocks the working Admin SDK admin tools.
|
|
251
|
-
*/
|
|
252
|
-
export function registerAlertCenterTools(server) {
|
|
253
|
-
server.registerTool('alertcenter_alerts_list', {
|
|
254
|
-
description: 'List Workspace security alerts (suspicious login, phishing, leaked password, Drive exfil, etc.). Requires the alertcenter bundle + service-account domain-wide delegation.',
|
|
255
|
-
inputSchema: {
|
|
256
|
-
account: accountEnum.describe('Google account alias (must be a Workspace admin)'),
|
|
257
|
-
pageSize: z.number().min(1).max(1000).optional(),
|
|
258
|
-
pageToken: z.string().optional(),
|
|
259
|
-
filter: z.string().optional().describe('Filter expression, e.g. "type = \\"Suspicious login\\""'),
|
|
260
|
-
orderBy: z.string().optional(),
|
|
261
|
-
customerId: z.string().optional(),
|
|
262
|
-
},
|
|
263
|
-
}, async ({ account, pageSize, pageToken, filter, orderBy, customerId }) => {
|
|
264
|
-
try {
|
|
265
|
-
const auth = await getClient(account);
|
|
266
|
-
const alertcenter = google.alertcenter({ version: 'v1beta1', auth });
|
|
267
|
-
const res = await alertcenter.alerts.list({
|
|
268
|
-
pageSize: pageSize ?? 50,
|
|
269
|
-
pageToken,
|
|
270
|
-
filter,
|
|
271
|
-
orderBy,
|
|
272
|
-
customerId,
|
|
273
|
-
});
|
|
274
|
-
return {
|
|
275
|
-
content: [{ type: 'text', text: JSON.stringify(res.data, null, 2) }],
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
catch (error) {
|
|
279
|
-
return handleAlertCenterError(error, account);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
server.registerTool('alertcenter_alert_get', {
|
|
283
|
-
description: 'Get a single alert by ID. Requires the alertcenter bundle + service-account domain-wide delegation.',
|
|
284
|
-
inputSchema: {
|
|
285
|
-
account: accountEnum.describe('Google account alias (must be a Workspace admin)'),
|
|
286
|
-
alertId: z.string().describe('Alert ID'),
|
|
287
|
-
customerId: z.string().optional(),
|
|
288
|
-
},
|
|
289
|
-
}, async ({ account, alertId, customerId }) => {
|
|
290
|
-
try {
|
|
291
|
-
const auth = await getClient(account);
|
|
292
|
-
const alertcenter = google.alertcenter({ version: 'v1beta1', auth });
|
|
293
|
-
const res = await alertcenter.alerts.get({ alertId, customerId });
|
|
294
|
-
return {
|
|
295
|
-
content: [{ type: 'text', text: JSON.stringify(res.data, null, 2) }],
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
catch (error) {
|
|
299
|
-
return handleAlertCenterError(error, account);
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
231
|
function handleAdminError(error, account) {
|
|
304
232
|
return handleGoogleApiError(error, account, "Admin tools require Workspace super-admin privileges AND the account must be listed in GOOGLE_ADMIN_ACCOUNTS (then re-authenticated). Personal Gmail accounts cannot use these endpoints.");
|
|
305
233
|
}
|
|
306
|
-
function handleAlertCenterError(error, account) {
|
|
307
|
-
return handleGoogleApiError(error, account, "Alert Center (apps.alerts) is not grantable via this server's user-consent OAuth flow — it requires a service account with domain-wide delegation. Enabling GOOGLE_OPTIONAL_SCOPES=alertcenter only declares the scope; the API will reject user-OAuth tokens. See README \"Alert Center\".");
|
|
308
|
-
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-google-multi",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "MCP server for Gmail,
|
|
3
|
+
"version": "5.0.0-beta.1",
|
|
4
|
+
"description": "Local MCP server for Google Workspace (Gmail, Drive, Calendar, Sheets, Docs, Contacts, Tasks, Meet, Search Console, +Forms/Chat/Admin) across multiple accounts — OAuth-only, encrypted token storage, deny-by-default writes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -36,6 +36,12 @@
|
|
|
36
36
|
"google-sheets",
|
|
37
37
|
"google-docs",
|
|
38
38
|
"google-contacts",
|
|
39
|
+
"google-workspace",
|
|
40
|
+
"google-tasks",
|
|
41
|
+
"google-meet",
|
|
42
|
+
"search-console",
|
|
43
|
+
"oauth",
|
|
44
|
+
"mcp-server",
|
|
39
45
|
"claude",
|
|
40
46
|
"claude-code"
|
|
41
47
|
],
|