workspace-operator-mcp 1.12.0__tar.gz
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.
- workspace_operator_mcp-1.12.0/LICENSE +21 -0
- workspace_operator_mcp-1.12.0/PKG-INFO +546 -0
- workspace_operator_mcp-1.12.0/README.md +511 -0
- workspace_operator_mcp-1.12.0/pyproject.toml +51 -0
- workspace_operator_mcp-1.12.0/setup.cfg +4 -0
- workspace_operator_mcp-1.12.0/tests/test_calendar_writes.py +66 -0
- workspace_operator_mcp-1.12.0/tests/test_cli.py +136 -0
- workspace_operator_mcp-1.12.0/tests/test_composite.py +140 -0
- workspace_operator_mcp-1.12.0/tests/test_deck.py +97 -0
- workspace_operator_mcp-1.12.0/tests/test_doc_tables.py +97 -0
- workspace_operator_mcp-1.12.0/tests/test_docs.py +212 -0
- workspace_operator_mcp-1.12.0/tests/test_files.py +67 -0
- workspace_operator_mcp-1.12.0/tests/test_formatting.py +132 -0
- workspace_operator_mcp-1.12.0/tests/test_gmail_threads.py +104 -0
- workspace_operator_mcp-1.12.0/tests/test_http.py +91 -0
- workspace_operator_mcp-1.12.0/tests/test_profiles.py +90 -0
- workspace_operator_mcp-1.12.0/tests/test_prompts.py +51 -0
- workspace_operator_mcp-1.12.0/tests/test_report.py +142 -0
- workspace_operator_mcp-1.12.0/tests/test_runtime.py +100 -0
- workspace_operator_mcp-1.12.0/tests/test_script_run.py +51 -0
- workspace_operator_mcp-1.12.0/tests/test_slides.py +65 -0
- workspace_operator_mcp-1.12.0/tests/test_text.py +145 -0
- workspace_operator_mcp-1.12.0/tests/test_workspace_search.py +89 -0
- workspace_operator_mcp-1.12.0/workspace_operator/__init__.py +4 -0
- workspace_operator_mcp-1.12.0/workspace_operator/__main__.py +5 -0
- workspace_operator_mcp-1.12.0/workspace_operator/auth.py +46 -0
- workspace_operator_mcp-1.12.0/workspace_operator/cli.py +314 -0
- workspace_operator_mcp-1.12.0/workspace_operator/config.py +150 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/__init__.py +157 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/apps_script.py +279 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/calendar.py +267 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/calendar_writes.py +192 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/compare.py +243 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/deck.py +251 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/digest.py +216 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/doc_tables.py +246 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/docs.py +164 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/drive.py +288 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/files.py +293 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/formatting.py +378 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/gmail.py +486 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/gmail_threads.py +329 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/report.py +368 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/search.py +301 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/sheets.py +446 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/slides.py +251 -0
- workspace_operator_mcp-1.12.0/workspace_operator/handlers/template.py +147 -0
- workspace_operator_mcp-1.12.0/workspace_operator/http_transport.py +163 -0
- workspace_operator_mcp-1.12.0/workspace_operator/logging.py +32 -0
- workspace_operator_mcp-1.12.0/workspace_operator/operations.py +57 -0
- workspace_operator_mcp-1.12.0/workspace_operator/profiles.py +146 -0
- workspace_operator_mcp-1.12.0/workspace_operator/runtime.py +123 -0
- workspace_operator_mcp-1.12.0/workspace_operator/security.py +24 -0
- workspace_operator_mcp-1.12.0/workspace_operator/server.py +2572 -0
- workspace_operator_mcp-1.12.0/workspace_operator/text.py +145 -0
- workspace_operator_mcp-1.12.0/workspace_operator_mcp.egg-info/PKG-INFO +546 -0
- workspace_operator_mcp-1.12.0/workspace_operator_mcp.egg-info/SOURCES.txt +59 -0
- workspace_operator_mcp-1.12.0/workspace_operator_mcp.egg-info/dependency_links.txt +1 -0
- workspace_operator_mcp-1.12.0/workspace_operator_mcp.egg-info/entry_points.txt +2 -0
- workspace_operator_mcp-1.12.0/workspace_operator_mcp.egg-info/requires.txt +7 -0
- workspace_operator_mcp-1.12.0/workspace_operator_mcp.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Artoxem
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: workspace-operator-mcp
|
|
3
|
+
Version: 1.12.0
|
|
4
|
+
Summary: Deep Google Workspace automation for AI agents — Apps Script execution, local file transfer, Slides, document templates, cross-product search, and tool profiles
|
|
5
|
+
Author: Artoxem
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Artoxem/workspace-operator
|
|
8
|
+
Project-URL: Repository, https://github.com/Artoxem/workspace-operator
|
|
9
|
+
Project-URL: Documentation, https://github.com/Artoxem/workspace-operator#readme
|
|
10
|
+
Project-URL: Changelog, https://github.com/Artoxem/workspace-operator/tree/master/docs
|
|
11
|
+
Project-URL: Issues, https://github.com/Artoxem/workspace-operator/issues
|
|
12
|
+
Keywords: mcp,model-context-protocol,google,gmail,drive,sheets,docs,slides,calendar,apps-script,antigravity,gemini-cli
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Environment :: Console
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: google-api-python-client<3,>=2.100.0
|
|
28
|
+
Requires-Dist: google-auth-httplib2>=0.2.0
|
|
29
|
+
Requires-Dist: google-auth-oauthlib>=1.2.0
|
|
30
|
+
Requires-Dist: mcp<2,>=1.0.0
|
|
31
|
+
Requires-Dist: PyYAML>=6.0
|
|
32
|
+
Requires-Dist: uvicorn>=0.30
|
|
33
|
+
Requires-Dist: starlette>=0.40
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
<div align="center">
|
|
37
|
+
|
|
38
|
+
# Workspace Operator
|
|
39
|
+
|
|
40
|
+
**Deep automation for Google Workspace through the Model Context Protocol**
|
|
41
|
+
|
|
42
|
+
Drive · Docs · Sheets · Slides · Gmail · Calendar · Apps Script — one local MCP server
|
|
43
|
+
with 59 tools, staged writes and server-side tool profiles.
|
|
44
|
+
|
|
45
|
+
[](https://www.python.org/)
|
|
46
|
+
[](https://modelcontextprotocol.io)
|
|
47
|
+
[](#-tool-catalog)
|
|
48
|
+
[](antigravity/README.md)
|
|
49
|
+
[](LICENSE)
|
|
50
|
+
|
|
51
|
+
[English](README.md) · [Русский](README.ru.md)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
Workspace Operator (formerly *yet-another-google-mcp*) runs on your machine, talks to
|
|
58
|
+
Google over your own OAuth client, and gives an AI agent the operations that turn
|
|
59
|
+
"read my inbox" into "do the work and let me undo it": staged Apps Script updates,
|
|
60
|
+
file transfer in both directions, presentation assembly, sheet formatting, threaded
|
|
61
|
+
replies and attachments.
|
|
62
|
+
|
|
63
|
+
**67 tools · 3 resources · 3 resource templates · 8 prompts**, every tool annotated
|
|
64
|
+
with `readOnlyHint` / `destructiveHint`.
|
|
65
|
+
|
|
66
|
+
Nothing here is tied to a specific account, spreadsheet or document: every tool
|
|
67
|
+
takes identifiers and ranges, and all examples use synthetic data.
|
|
68
|
+
|
|
69
|
+
## How it compares
|
|
70
|
+
|
|
71
|
+
| | Google Workspace MCP (remote) | **Workspace Operator** |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| Transport | Streamable HTTP, Google-hosted | **stdio, local** |
|
|
74
|
+
| Availability | Developer Preview | **public, MIT** |
|
|
75
|
+
| Data path | Google MCP endpoint | **your machine, your OAuth client** |
|
|
76
|
+
| Apps Script | — | **create · read · stage · execute · cancel · restore · run function** |
|
|
77
|
+
| Local files | — | **upload, download, export to pdf/docx/xlsx/pptx** |
|
|
78
|
+
| Slides | — | **create, add slides, fill text, insert images** |
|
|
79
|
+
| Sheets formatting | — | **bold, colours, number formats, widths, freeze** |
|
|
80
|
+
| Gmail threads | single messages | **threads, attachments, in-thread replies** |
|
|
81
|
+
| Server-side tool profiles | IAM / admin allow-list | **read-only / read-write / full + allow-deny** |
|
|
82
|
+
|
|
83
|
+
Official servers are the right default for "ask my mail a question". Workspace
|
|
84
|
+
Operator is for "change the workspace and be able to roll it back".
|
|
85
|
+
|
|
86
|
+
## What you get
|
|
87
|
+
|
|
88
|
+
| Group | Tools | Highlights |
|
|
89
|
+
|---|---:|---|
|
|
90
|
+
| 🔎 Cross-search | 1 | One query over Drive, Gmail and Calendar, merged by date |
|
|
91
|
+
| 📁 Drive | 8 | Search, move, copy, share, permissions, revoke public access |
|
|
92
|
+
| 💾 Drive files | 3 | Upload/download/export, conversion to native Google formats |
|
|
93
|
+
| 📊 Sheets | 12 | Read/write, formatting, filter views, named ranges, CSV |
|
|
94
|
+
| 📄 Docs | 5 | Read (tables included), append, templates, PDF export |
|
|
95
|
+
| 🖼 Slides | 5 | Create decks, add slides, replace text, insert images |
|
|
96
|
+
| ⚙️ Apps Script | 7 | Staged updates with backups, rollback, run functions |
|
|
97
|
+
| 📧 Gmail | 14 | Threads, attachments, replies, drafts, labels, batch delete |
|
|
98
|
+
| 📅 Calendar | 7 | Events, free slots, meetings, update/delete, invite responses |
|
|
99
|
+
| 🧩 Composite | 5 | report from sheet, digest, table diff, template clone, table → deck |
|
|
100
|
+
|
|
101
|
+
Plus 3 resources, 3 resource templates and 8 prompts — see the
|
|
102
|
+
[tool catalog](#-tool-catalog).
|
|
103
|
+
|
|
104
|
+
## Quick start
|
|
105
|
+
|
|
106
|
+
### 1 — Install
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone https://github.com/Artoxem/workspace-operator.git
|
|
110
|
+
cd workspace-operator
|
|
111
|
+
python -m venv .venv && .venv\Scripts\activate # Windows
|
|
112
|
+
pip install -r requirements.txt
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Python 3.10 or newer. The package is not on PyPI yet — install from source.
|
|
116
|
+
|
|
117
|
+
### 2 — Google OAuth
|
|
118
|
+
|
|
119
|
+
1. Create an OAuth 2.0 Client ID (type: **Desktop app**) in
|
|
120
|
+
[Google Cloud Console](https://console.cloud.google.com/).
|
|
121
|
+
2. Enable these APIs: **Drive, Docs, Sheets, Slides, Gmail, Calendar, Apps Script**.
|
|
122
|
+
3. Download the client JSON — the server will read it on first run.
|
|
123
|
+
|
|
124
|
+
> Step by step: [docs/AUTH_SETUP.md](docs/AUTH_SETUP.md) · [docs/ru/AUTH_SETUP.md](docs/ru/AUTH_SETUP.md)
|
|
125
|
+
> Upgrading? Slides needs the `.../auth/presentations` scope — re-run the OAuth flow once.
|
|
126
|
+
|
|
127
|
+
### 3 — Configure
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cp config.example.yaml config.yaml
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
client_secrets_file: "C:\\Users\\you\\.google\\oauth.keys.json"
|
|
135
|
+
token_file: "C:\\Users\\you\\.google\\token.json"
|
|
136
|
+
backup_dir: "C:\\Users\\you\\.google\\backups"
|
|
137
|
+
mcp_auth_token: "MySecretToken_2026!"
|
|
138
|
+
tool_profile: "read-write" # full | read-write | read-only
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`mcp_auth_token` is a local activation key, not network security: the server refuses
|
|
142
|
+
to handle tools until it is set. Every key can be overridden by an environment
|
|
143
|
+
variable — see [docs/SECURITY.md](docs/SECURITY.md).
|
|
144
|
+
|
|
145
|
+
### 4 — Connect a client
|
|
146
|
+
|
|
147
|
+
<details open>
|
|
148
|
+
<summary><strong>Google Antigravity</strong> — App, IDE and CLI share one config</summary>
|
|
149
|
+
|
|
150
|
+
`~/.gemini/config/mcp_config.json` (global) or `<workspace>/.agents/mcp_config.json`:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"mcpServers": {
|
|
155
|
+
"workspace-operator": {
|
|
156
|
+
"command": "python",
|
|
157
|
+
"args": ["D:\\DEV\\workspace-operator\\server.py"],
|
|
158
|
+
"env": {
|
|
159
|
+
"MCP_CONFIG_FILE": "D:\\DEV\\workspace-operator\\config.yaml",
|
|
160
|
+
"MCP_AUTH_TOKEN": "MySecretToken_2026!",
|
|
161
|
+
"MCP_TOOL_PROFILE": "read-write"
|
|
162
|
+
},
|
|
163
|
+
"timeoutSeconds": 300,
|
|
164
|
+
"tools": { "workspace_search": { "eager": true } }
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Ready-made file: [antigravity/mcp_config.example.json](antigravity/mcp_config.example.json) ·
|
|
171
|
+
walkthrough: [antigravity/README.md](antigravity/README.md) ·
|
|
172
|
+
Agent Skill: [skills/google-workspace/SKILL.md](skills/google-workspace/SKILL.md)
|
|
173
|
+
|
|
174
|
+
</details>
|
|
175
|
+
|
|
176
|
+
<details>
|
|
177
|
+
<summary><strong>Claude Desktop, Cursor, VS Code, Windsurf</strong></summary>
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"mcpServers": {
|
|
182
|
+
"workspace-operator": {
|
|
183
|
+
"command": "python",
|
|
184
|
+
"args": ["D:\\DEV\\workspace-operator\\server.py"],
|
|
185
|
+
"env": {
|
|
186
|
+
"MCP_CONFIG_FILE": "D:\\DEV\\workspace-operator\\config.yaml",
|
|
187
|
+
"MCP_AUTH_TOKEN": "MySecretToken_2026!"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Per-client paths: [docs/IDE_SETUP.md](docs/IDE_SETUP.md) · [docs/ru/IDE_SETUP.md](docs/ru/IDE_SETUP.md).
|
|
195
|
+
|
|
196
|
+
</details>
|
|
197
|
+
|
|
198
|
+
## Tool profiles
|
|
199
|
+
|
|
200
|
+
A profile is a server-side allow-list: tools outside it are neither listed nor
|
|
201
|
+
callable. It complements OAuth scopes (what Google allows) and client permissions
|
|
202
|
+
(what the agent may do without asking).
|
|
203
|
+
|
|
204
|
+
| Profile | Tools | Use it for |
|
|
205
|
+
|---|---:|---|
|
|
206
|
+
| `full` | 67 | your own machine, full trust |
|
|
207
|
+
| `read-write` | 59 | daily work — destructive tools hidden |
|
|
208
|
+
| `read-only` | 21 | exploration, demos, shared machines, untrusted agents |
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
tool_profile: "read-write"
|
|
212
|
+
# Optional, applied on top. Deny wins over allow.
|
|
213
|
+
allowed_tools: ["workspace_search", "find_files", "read_sheet", "read_email"]
|
|
214
|
+
denied_tools: ["send_email", "share_file"]
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Environment overrides: `MCP_TOOL_PROFILE`, `MCP_ALLOWED_TOOLS`, `MCP_DENIED_TOOLS`.
|
|
218
|
+
A blocked call returns a clear explanation instead of failing silently.
|
|
219
|
+
|
|
220
|
+
## Operations
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
python -m workspace_operator doctor # config, token, scopes, API reachability
|
|
224
|
+
python -m workspace_operator tools # catalog (--profile read-only, --json)
|
|
225
|
+
python -m workspace_operator serve # stdio server (same as python server.py)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
| Feature | How to use it | What it does |
|
|
229
|
+
|---|---|---|
|
|
230
|
+
| **Dry run** | `MCP_DRY_RUN=1` or `dry_run: true` | Every non-read-only tool returns a preview instead of executing — safe demos, safe exploration |
|
|
231
|
+
| **Audit log** | `MCP_AUDIT_LOG=~/.google/audit.jsonl` | One JSON line per call: tool, profile, status, duration, argument **names** (never values) |
|
|
232
|
+
| **Retries** | `MCP_RETRY_ATTEMPTS=3` | Transient Google API errors (429/5xx) are retried with exponential backoff |
|
|
233
|
+
| **Doctor** | `python -m workspace_operator doctor` | Checks secrets, token, granted vs configured scopes, and Drive/Gmail/Calendar reachability |
|
|
234
|
+
|
|
235
|
+
In dry-run the read-only tools still work, so an agent can explore data while every
|
|
236
|
+
write is turned into an explicit preview.
|
|
237
|
+
|
|
238
|
+
### HTTP transport (localhost first)
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
python -m workspace_operator serve --http --port 8765
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
* binds `127.0.0.1` by default — not reachable from the network;
|
|
245
|
+
* every request needs `Authorization: Bearer <mcp_auth_token>`; extra per-client
|
|
246
|
+
tokens can be listed under `http_tokens` in `config.yaml`, and the audit log
|
|
247
|
+
records the token name as `client`;
|
|
248
|
+
* DNS-rebinding protection is on: only expected `Host` headers pass, browser
|
|
249
|
+
origins are denied unless explicitly allowed;
|
|
250
|
+
* `GET /healthz` is unauthenticated and returns only version and transport info;
|
|
251
|
+
* binding a non-loopback address requires **both** `--allow-network` and
|
|
252
|
+
`--insecure`, so network exposure is always deliberate.
|
|
253
|
+
|
|
254
|
+
### Docker
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
docker compose up --build
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The compose file publishes `127.0.0.1:8765` only and mounts your OAuth files
|
|
261
|
+
read-only.
|
|
262
|
+
|
|
263
|
+
## Tool catalog
|
|
264
|
+
|
|
265
|
+
<details>
|
|
266
|
+
<summary>🔎 Cross-search (1)</summary>
|
|
267
|
+
|
|
268
|
+
| Tool | Type | Description |
|
|
269
|
+
|---|---|---|
|
|
270
|
+
| `workspace_search` | read | One query across Drive, Gmail and Calendar, date-sorted, partial failures reported |
|
|
271
|
+
|
|
272
|
+
</details>
|
|
273
|
+
|
|
274
|
+
<details>
|
|
275
|
+
<summary>📁 Drive (8)</summary>
|
|
276
|
+
|
|
277
|
+
| Tool | Type | Description |
|
|
278
|
+
|---|---|---|
|
|
279
|
+
| `find_files` | read | Search by name or Drive query |
|
|
280
|
+
| `drive_search_advanced` | read | Full Drive query syntax with a limit |
|
|
281
|
+
| `drive_list_permissions` | read | List permissions of a file |
|
|
282
|
+
| `create_folder` | write | Create a folder |
|
|
283
|
+
| `move_file` | write | Move a file into a folder |
|
|
284
|
+
| `drive_copy_file` | write | Copy a file |
|
|
285
|
+
| `share_file` | write | Share with user/group/domain/anyone |
|
|
286
|
+
| `drive_revoke_public` | destructive | Revoke public access (`confirm=true`) |
|
|
287
|
+
|
|
288
|
+
</details>
|
|
289
|
+
|
|
290
|
+
<details>
|
|
291
|
+
<summary>💾 Drive files (3)</summary>
|
|
292
|
+
|
|
293
|
+
| Tool | Type | Description |
|
|
294
|
+
|---|---|---|
|
|
295
|
+
| `drive_upload` | write | Upload a local file; `convert_to` turns docx/xlsx/pptx into native Google files |
|
|
296
|
+
| `drive_download` | read | Download a binary file to disk |
|
|
297
|
+
| `drive_export` | read | Export a Doc/Sheet/Slide to pdf, docx, xlsx, pptx, csv… |
|
|
298
|
+
|
|
299
|
+
</details>
|
|
300
|
+
|
|
301
|
+
<details>
|
|
302
|
+
<summary>📊 Sheets (12)</summary>
|
|
303
|
+
|
|
304
|
+
| Tool | Type | Description |
|
|
305
|
+
|---|---|---|
|
|
306
|
+
| `read_sheet` | read | Read a cell range |
|
|
307
|
+
| `get_spreadsheet_meta` | read | Sheet names and IDs |
|
|
308
|
+
| `sheet_export_csv` | read | Export a range as CSV |
|
|
309
|
+
| `append_row` | write | Append a row |
|
|
310
|
+
| `update_sheet` | write | Write rows to a range |
|
|
311
|
+
| `create_spreadsheet` | write | Create a spreadsheet |
|
|
312
|
+
| `add_sheet` | write | Add a tab |
|
|
313
|
+
| `sheet_create_filter_view` | write | Create a filter view |
|
|
314
|
+
| `sheet_create_named_range` | write | Create a named range |
|
|
315
|
+
| `sheet_find_replace` | write | Find & replace (`dry_run=true` by default) |
|
|
316
|
+
| `sheet_format` | write | Bold, colours, number formats, widths, row heights, frozen panes |
|
|
317
|
+
| `clear_range` | destructive | Clear a range (auto dry-run for large ranges) |
|
|
318
|
+
|
|
319
|
+
</details>
|
|
320
|
+
|
|
321
|
+
<details>
|
|
322
|
+
<summary>📄 Docs (5)</summary>
|
|
323
|
+
|
|
324
|
+
| Tool | Type | Description |
|
|
325
|
+
|---|---|---|
|
|
326
|
+
| `read_doc` | read | Read text and tables |
|
|
327
|
+
| `doc_export_pdf` | read | Export as binary PDF |
|
|
328
|
+
| `create_doc` | write | Create a document |
|
|
329
|
+
| `append_to_doc` | write | Append text |
|
|
330
|
+
| `doc_fill_template` | destructive | Fill placeholders (`confirm=true`) |
|
|
331
|
+
|
|
332
|
+
</details>
|
|
333
|
+
|
|
334
|
+
<details>
|
|
335
|
+
<summary>🖼 Slides (5)</summary>
|
|
336
|
+
|
|
337
|
+
| Tool | Type | Description |
|
|
338
|
+
|---|---|---|
|
|
339
|
+
| `slides_create` | write | Create a presentation |
|
|
340
|
+
| `slides_get` | read | Slide count, IDs and text per slide |
|
|
341
|
+
| `slides_add_slide` | write | Add a slide with a predefined layout |
|
|
342
|
+
| `slides_replace_text` | destructive | Replace placeholders (`confirm=true`) |
|
|
343
|
+
| `slides_insert_image` | write | Insert a public image URL onto a slide |
|
|
344
|
+
|
|
345
|
+
</details>
|
|
346
|
+
|
|
347
|
+
<details>
|
|
348
|
+
<summary>⚙️ Apps Script (7)</summary>
|
|
349
|
+
|
|
350
|
+
| Tool | Type | Description |
|
|
351
|
+
|---|---|---|
|
|
352
|
+
| `get_script_content` | read | Read project files |
|
|
353
|
+
| `create_script_project` | write | Create a project |
|
|
354
|
+
| `prepare_script_update` | write | Stage an update, returns `operation_id` |
|
|
355
|
+
| `execute_operation` | write | Apply a staged update (auto-backup first) |
|
|
356
|
+
| `cancel_operation` | write | Cancel a staged update |
|
|
357
|
+
| `restore_script_backup` | write | Restore from a backup |
|
|
358
|
+
| `script_run_function` | destructive | Run a function from an API-executable deployment |
|
|
359
|
+
|
|
360
|
+
</details>
|
|
361
|
+
|
|
362
|
+
<details>
|
|
363
|
+
<summary>📧 Gmail (14)</summary>
|
|
364
|
+
|
|
365
|
+
| Tool | Type | Description |
|
|
366
|
+
|---|---|---|
|
|
367
|
+
| `get_gmail_profile` | read | Authenticated address |
|
|
368
|
+
| `list_emails` | read | List with date, sender and subject |
|
|
369
|
+
| `read_email` | read | Headers, labels, attachments and decoded body |
|
|
370
|
+
| `gmail_search_and_summarize` | read | Search with a compact summary |
|
|
371
|
+
| `gmail_get_thread` | read | Whole conversation |
|
|
372
|
+
| `gmail_get_attachment` | read | Save an attachment to disk |
|
|
373
|
+
| `create_draft` | write | Create a draft |
|
|
374
|
+
| `send_email` | write | Send or draft (`draft_mode=true` by default) |
|
|
375
|
+
| `send_draft` | write | Send an existing draft |
|
|
376
|
+
| `gmail_reply` | write | Reply in-thread (`draft_mode=true` by default) |
|
|
377
|
+
| `gmail_label_apply` | write | Apply a label (`dry_run=true` by default) |
|
|
378
|
+
| `gmail_archive` | write | Archive (`confirm=true`) |
|
|
379
|
+
| `delete_email` | destructive | Delete (`confirm=true`) |
|
|
380
|
+
| `batch_delete_emails` | destructive | Delete many (`dry_run=true` by default) |
|
|
381
|
+
|
|
382
|
+
</details>
|
|
383
|
+
|
|
384
|
+
<details>
|
|
385
|
+
<summary>🧩 Composite (5)</summary>
|
|
386
|
+
|
|
387
|
+
| Tool | Type | Description |
|
|
388
|
+
|---|---|---|
|
|
389
|
+
| `report_from_sheet` | write | Read a range → column statistics → Doc with **native tables** or plain text (`output=text`) |
|
|
390
|
+
| `digest` | write | Last N hours across Gmail, Calendar and Drive → text or Doc |
|
|
391
|
+
| `compare_tables` | write | Diff two ranges by a key column; `output=doc` builds native tables |
|
|
392
|
+
| `clone_and_fill` | write | Copy any Drive file and replace placeholders in the copy |
|
|
393
|
+
| `sheet_to_slides` | write | Read a range → deck: title slide + one slide per row group |
|
|
394
|
+
|
|
395
|
+
</details>
|
|
396
|
+
|
|
397
|
+
<details>
|
|
398
|
+
<summary>📅 Calendar (7)</summary>
|
|
399
|
+
|
|
400
|
+
| Tool | Type | Description |
|
|
401
|
+
|---|---|---|
|
|
402
|
+
| `list_events` | read | Upcoming events with times and locations |
|
|
403
|
+
| `calendar_find_free_slots` | read | Free slots in a window |
|
|
404
|
+
| `create_event` | write | Create an event |
|
|
405
|
+
| `calendar_create_meeting` | write | Meeting with attendees (`confirm=true`) |
|
|
406
|
+
| `calendar_update_event` | write | Change any field; only what you pass is modified |
|
|
407
|
+
| `calendar_delete_event` | destructive | Delete an event (`confirm=true`) |
|
|
408
|
+
| `calendar_respond_to_invite` | write | Accept / decline / tentative (`confirm=true`) |
|
|
409
|
+
|
|
410
|
+
</details>
|
|
411
|
+
|
|
412
|
+
### Resources
|
|
413
|
+
|
|
414
|
+
| URI | Attaches |
|
|
415
|
+
|---|---|
|
|
416
|
+
| `gdrive://recent` | 20 most recently modified Drive files |
|
|
417
|
+
| `gmail://inbox` | Recent unread inbox messages |
|
|
418
|
+
| `gcalendar://upcoming` | Events for the next 7 days |
|
|
419
|
+
| `gdrive://file/{file_id}` | Metadata for one file |
|
|
420
|
+
| `gsheets://{spreadsheet_id}/{range}` | A sheet range as a table |
|
|
421
|
+
| `gdocs://{document_id}` | Full document text, tables included |
|
|
422
|
+
|
|
423
|
+
### Prompts
|
|
424
|
+
|
|
425
|
+
| Prompt | What it does |
|
|
426
|
+
|---|---|
|
|
427
|
+
| `summarize_inbox` | Fetch recent mail → ready for a summary |
|
|
428
|
+
| `analyze_spreadsheet` | Read a range → ready for analysis |
|
|
429
|
+
| `plan_week` | Load calendar events → ready for planning |
|
|
430
|
+
| `search_drive` | Search files → ready for organisation advice |
|
|
431
|
+
| `weekly_review` | Last N days of mail, files and agenda → weekly summary |
|
|
432
|
+
| `inbox_triage` | Gmail slice → urgent / waiting / informational / archive |
|
|
433
|
+
| `sheet_brief` | Range → statistics plus a briefing question |
|
|
434
|
+
| `compare_brief` | Two ranges → reconciliation report |
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
## Safety by default
|
|
438
|
+
|
|
439
|
+
| Guard | Applies to |
|
|
440
|
+
|---|---|
|
|
441
|
+
| `confirm=true` required | `delete_email`, `gmail_archive`, `calendar_create_meeting`, `drive_revoke_public`, `doc_fill_template`, `slides_replace_text` |
|
|
442
|
+
| `dry_run=true` by default | `batch_delete_emails`, `sheet_find_replace`, `gmail_label_apply` |
|
|
443
|
+
| Draft mode by default | `send_email`, `gmail_reply` |
|
|
444
|
+
| Public sharing blocked | `share_file` refuses `type=anyone` without `allow_public=true` |
|
|
445
|
+
| No silent overwrite | `drive_download`, `drive_export`, `gmail_get_attachment` |
|
|
446
|
+
| Staged Apps Script | `prepare_script_update` → `execute_operation` (backup first) |
|
|
447
|
+
| Tool annotations | every tool carries `readOnlyHint` / `destructiveHint` |
|
|
448
|
+
| Server-side profiles | `read-only` / `read-write` / `full` + allow/deny lists |
|
|
449
|
+
|
|
450
|
+
> ⚠️ An agent can reach everything your OAuth token can. Use read-only scopes and the
|
|
451
|
+
> `read-only` profile for sensitive accounts — [docs/SECURITY.md](docs/SECURITY.md).
|
|
452
|
+
|
|
453
|
+
## How it works
|
|
454
|
+
|
|
455
|
+
```
|
|
456
|
+
server.py MCP server: 67 tool definitions, resources, prompts, profiles
|
|
457
|
+
workspace_operator/
|
|
458
|
+
├─ profiles.py read-only / read-write / full + allow-deny lists
|
|
459
|
+
├─ config.py config file + environment overrides
|
|
460
|
+
├─ auth.py OAuth 2.0 credentials and token cache
|
|
461
|
+
├─ text.py entity/whitespace normalisation, timestamps, error hints
|
|
462
|
+
├─ operations.py staged-operation store for Apps Script
|
|
463
|
+
├─ security.py token and email checks
|
|
464
|
+
├─ runtime.py retries, audit log, dry-run helpers
|
|
465
|
+
├─ cli.py doctor / tools / serve
|
|
466
|
+
└─ handlers/
|
|
467
|
+
├─ search.py workspace_search — Drive + Gmail + Calendar
|
|
468
|
+
├─ files.py drive_upload / drive_download / drive_export
|
|
469
|
+
├─ formatting.py sheet_format request builders
|
|
470
|
+
├─ gmail_threads.py threads, attachments, in-thread replies
|
|
471
|
+
├─ slides.py presentations
|
|
472
|
+
├─ calendar_writes.py update / delete / invite responses
|
|
473
|
+
├─ report.py report_from_sheet: stats + document
|
|
474
|
+
├─ digest.py digest across mail, calendar and drive
|
|
475
|
+
├─ compare.py table diff by key column
|
|
476
|
+
├─ template.py clone a file and fill placeholders
|
|
477
|
+
├─ deck.py table → presentation
|
|
478
|
+
├─ drive.py sheets.py docs.py
|
|
479
|
+
├─ gmail.py calendar.py apps_script.py
|
|
480
|
+
tests/ unit, live and round-trip checks
|
|
481
|
+
antigravity/ ready-to-paste mcp_config.json
|
|
482
|
+
skills/google-workspace/ Agent Skill: when to use which tool
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Design rules:
|
|
486
|
+
|
|
487
|
+
* every handler returns a string — exceptions never reach the transport;
|
|
488
|
+
* writes are staged, confirmed or drafted, never silent;
|
|
489
|
+
* Apps Script is a two-phase commit with an automatic backup;
|
|
490
|
+
* server-side profiles keep the exposed surface small.
|
|
491
|
+
|
|
492
|
+
## Testing
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
python -m unittest discover -s tests -v # 240 unit tests, no network
|
|
496
|
+
python tests/live_smoke.py # 51 checks against a real account
|
|
497
|
+
python tests/pptx_roundtrip.py deck.pptx # 5 checks: pptx → Slides → replace
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
The live suite is self-cleaning: it uploads and trashes a temp file, creates and
|
|
501
|
+
trashes a presentation and a spreadsheet, drafts and deletes a reply, downloads an
|
|
502
|
+
attachment and removes it. `tests/test_docs.py` keeps this README, the docs and the
|
|
503
|
+
code in sync (tool counts, profile numbers, links, examples).
|
|
504
|
+
|
|
505
|
+
## Documentation
|
|
506
|
+
|
|
507
|
+
### 🇬🇧 English
|
|
508
|
+
| Document | Description |
|
|
509
|
+
|---|---|
|
|
510
|
+
| [AUTH_SETUP.md](docs/AUTH_SETUP.md) | Google OAuth setup, step by step |
|
|
511
|
+
| [TOOLS_REFERENCE.md](docs/TOOLS_REFERENCE.md) | Every tool, resource and prompt |
|
|
512
|
+
| [SECURITY.md](docs/SECURITY.md) | Scopes, profiles, safety model |
|
|
513
|
+
| [IDE_SETUP.md](docs/IDE_SETUP.md) | Antigravity, Cursor, Windsurf, VS Code |
|
|
514
|
+
| [LEARN.md](LEARN.md) | How this server was built |
|
|
515
|
+
| [docs/](docs/) | Release notes and specs for every version |
|
|
516
|
+
|
|
517
|
+
### 🇷🇺 На русском
|
|
518
|
+
| Документ | Описание |
|
|
519
|
+
|---|---|
|
|
520
|
+
| [AUTH_SETUP.md](docs/ru/AUTH_SETUP.md) | Пошаговая настройка OAuth |
|
|
521
|
+
| [TOOLS_REFERENCE.md](docs/ru/TOOLS_REFERENCE.md) | Справочник инструментов |
|
|
522
|
+
| [SECURITY.md](docs/ru/SECURITY.md) | Скоупы, профили, модель безопасности |
|
|
523
|
+
| [IDE_SETUP.md](docs/ru/IDE_SETUP.md) | Antigravity, Cursor, Windsurf, VS Code |
|
|
524
|
+
|
|
525
|
+
## Roadmap
|
|
526
|
+
|
|
527
|
+
- [x] Cross-product search, tool profiles
|
|
528
|
+
- [x] Files, Slides, Apps Script execution
|
|
529
|
+
- [x] Sheet formatting
|
|
530
|
+
- [x] Gmail threads, attachments, replies
|
|
531
|
+
- [x] Calendar update/delete/respond
|
|
532
|
+
- [x] Composite tools: `report_from_sheet`, `digest`, `compare_tables`, `clone_and_fill`
|
|
533
|
+
- [x] Optional HTTP transport (Streamable HTTP, stateless, localhost-first)
|
|
534
|
+
|
|
535
|
+
## Responsibility
|
|
536
|
+
|
|
537
|
+
You are responsible for what the agent does with your account. Read
|
|
538
|
+
[docs/SECURITY.md](docs/SECURITY.md), start with `read-only`, keep backups on.
|
|
539
|
+
|
|
540
|
+
---
|
|
541
|
+
|
|
542
|
+
<div align="center">
|
|
543
|
+
|
|
544
|
+
MIT licensed · built on the [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)
|
|
545
|
+
|
|
546
|
+
</div>
|