Skip to main content
Glama
MCP Google Tools Server
by Artoxem

Workspace Operator

Deep automation for Google Workspace through the Model Context Protocol

Drive · Docs · Sheets · Slides · Gmail · Calendar · Apps Script — one local MCP server with 67 tools, staged writes and server-side tool profiles.

Python MCP Tools PyPI Antigravity License: MIT

English · Русский


Workspace Operator (formerly yet-another-google-mcp) runs on your machine, talks to Google over your own OAuth client, and gives an AI agent the operations that turn "read my inbox" into "do the work and let me undo it": staged Apps Script updates, file transfer in both directions, presentation assembly, sheet formatting, threaded replies and attachments.

67 tools · 3 resources · 3 resource templates · 8 prompts, every tool annotated with readOnlyHint / destructiveHint.

Nothing here is tied to a specific account, spreadsheet or document: every tool takes identifiers and ranges, and all examples use synthetic data.

How it compares

Google Workspace MCP (remote)

Workspace Operator

Transport

Streamable HTTP, Google-hosted

stdio, local

Availability

Developer Preview

public, MIT

Data path

Google MCP endpoint

your machine, your OAuth client

Apps Script

—

create · read · stage · execute · cancel · restore · run function

Local files

—

upload, download, export to pdf/docx/xlsx/pptx

Slides

—

create, add slides, fill text, insert images

Sheets formatting

—

bold, colours, number formats, widths, freeze

Gmail threads

single messages

threads, attachments, in-thread replies

Server-side tool profiles

IAM / admin allow-list

read-only / read-write / full + allow-deny

Official servers are the right default for "ask my mail a question". Workspace Operator is for "change the workspace and be able to roll it back".

Related MCP server: MCP Google Workspace Server

What you get

Group

Tools

Highlights

🔎 Cross-search

1

One query over Drive, Gmail and Calendar, merged by date

📁 Drive

8

Search, move, copy, share, permissions, revoke public access

💾 Drive files

3

Upload/download/export, conversion to native Google formats

📊 Sheets

12

Read/write, formatting, filter views, named ranges, CSV

📄 Docs

5

Read (tables included), append, templates, PDF export

🖼 Slides

5

Create decks, add slides, replace text, insert images

⚙️ Apps Script

7

Staged updates with backups, rollback, run functions

📧 Gmail

14

Threads, attachments, replies, drafts, labels, batch delete

📅 Calendar

7

Events, free slots, meetings, update/delete, invite responses

🧩 Composite

5

report from sheet, digest, table diff, template clone, table → deck

Plus 3 resources, 3 resource templates and 8 prompts — see the tool catalog.

Quick start

1 — Install

pip install workspace-operator-mcp

From source (development):

git clone https://github.com/Artoxem/workspace-operator.git
cd workspace-operator
python -m venv .venv && .venv\Scripts\activate    # Windows
pip install -r requirements.txt

Python 3.10 or newer. The package installs the workspace-operator command; the python -m workspace_operator form works from a source checkout too.

2 — Google OAuth

  1. Create an OAuth 2.0 Client ID (type: Desktop app) in Google Cloud Console.

  2. Enable these APIs: Drive, Docs, Sheets, Slides, Gmail, Calendar, Apps Script.

  3. Download the client JSON — the server will read it on first run.

Step by step: docs/AUTH_SETUP.md · docs/ru/AUTH_SETUP.md Upgrading? Slides needs the .../auth/presentations scope — re-run the OAuth flow once.

3 — Configure

cp config.example.yaml config.yaml
client_secrets_file: "C:\\Users\\you\\.google\\oauth.keys.json"
token_file: "C:\\Users\\you\\.google\\token.json"
backup_dir: "C:\\Users\\you\\.google\\backups"
mcp_auth_token: "MySecretToken_2026!"
tool_profile: "read-write"      # full | read-write | read-only

mcp_auth_token is a local activation key, not network security: the server refuses to handle tools until it is set. Every key can be overridden by an environment variable — see docs/SECURITY.md.

4 — Connect a client

~/.gemini/config/mcp_config.json (global) or <workspace>/.agents/mcp_config.json:

{
  "mcpServers": {
    "workspace-operator": {
      "command": "python",
      "args": ["D:\\DEV\\workspace-operator\\server.py"],
      "env": {
        "MCP_CONFIG_FILE": "D:\\DEV\\workspace-operator\\config.yaml",
        "MCP_AUTH_TOKEN": "MySecretToken_2026!",
        "MCP_TOOL_PROFILE": "read-write"
      },
      "timeoutSeconds": 300,
      "tools": { "workspace_search": { "eager": true } }
    }
  }
}

Ready-made file: antigravity/mcp_config.example.json · walkthrough: antigravity/README.md · Agent Skill: skills/google-workspace/SKILL.md

{
  "mcpServers": {
    "workspace-operator": {
      "command": "python",
      "args": ["D:\\DEV\\workspace-operator\\server.py"],
      "env": {
        "MCP_CONFIG_FILE": "D:\\DEV\\workspace-operator\\config.yaml",
        "MCP_AUTH_TOKEN": "MySecretToken_2026!"
      }
    }
  }
}

Per-client paths: docs/IDE_SETUP.md · docs/ru/IDE_SETUP.md.

Tool profiles

A profile is a server-side allow-list: tools outside it are neither listed nor callable. It complements OAuth scopes (what Google allows) and client permissions (what the agent may do without asking).

Profile

Tools

Use it for

full

67

your own machine, full trust

read-write

59

daily work — destructive tools hidden

read-only

21

exploration, demos, shared machines, untrusted agents

tool_profile: "read-write"
# Optional, applied on top. Deny wins over allow.
allowed_tools: ["workspace_search", "find_files", "read_sheet", "read_email"]
denied_tools: ["send_email", "share_file"]

Environment overrides: MCP_TOOL_PROFILE, MCP_ALLOWED_TOOLS, MCP_DENIED_TOOLS. A blocked call returns a clear explanation instead of failing silently.

Operations

python -m workspace_operator doctor     # config, token, scopes, API reachability
python -m workspace_operator doctor --offline   # same, without network probes
python -m workspace_operator tools      # catalog (--profile read-only, --json)
python -m workspace_operator serve      # stdio server (same as python server.py)

Feature

How to use it

What it does

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

Audit log

MCP_AUDIT_LOG=~/.google/audit.jsonl

One JSON line per call: tool, profile, status, duration, argument names (never values)

Retries

MCP_RETRY_ATTEMPTS=3

Transient Google API errors (429/5xx) are retried with exponential backoff

Doctor

python -m workspace_operator doctor

Checks secrets, token, granted vs configured scopes, and Drive/Gmail/Calendar reachability

In dry-run the read-only tools still work, so an agent can explore data while every write is turned into an explicit preview.

HTTP transport (localhost first)

python -m workspace_operator serve --http --port 8765
  • binds 127.0.0.1 by default — not reachable from the network;

  • every request needs Authorization: Bearer <mcp_auth_token>; extra per-client tokens can be listed under http_tokens in config.yaml, and the audit log records the token name as client;

  • DNS-rebinding protection is on: only expected Host headers pass, browser origins are denied unless explicitly allowed;

  • GET /healthz is unauthenticated and returns only version and transport info;

  • binding a non-loopback address requires both --allow-network and --insecure; loopback names accept any host port (containers, proxies), anything else needs an explicit --allow-host; --insecure, so network exposure is always deliberate.

Docker

docker pull ghcr.io/artoxem/workspace-operator:latest

docker run --rm -p 127.0.0.1:8765:8765 \
  -v "$HOME/.google:/home/app/.google" \
  -v "$PWD/config.docker.yaml:/app/config.yaml:ro" \
  -e MCP_AUTH_TOKEN="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')" \
  ghcr.io/artoxem/workspace-operator:latest

The image runs as an unprivileged user (uid 10001), publishes only to loopback and mounts the Google credentials read-write, because the server refreshes the token in place. docker compose up --build builds the same image locally.

Clients that only speak stdio can still use the image — the entrypoint takes the same arguments as the CLI:

docker run -i --rm \
  -v "$HOME/.google:/home/app/.google" \
  --entrypoint python \
  ghcr.io/artoxem/workspace-operator:latest -m workspace_operator serve

Something not working? See docs/TROUBLESHOOTING.md.

Tool catalog

Tool

Type

Description

workspace_search

read

One query across Drive, Gmail and Calendar, date-sorted, partial failures reported

Tool

Type

Description

find_files

read

Search by name or Drive query

drive_search_advanced

read

Full Drive query syntax with a limit

drive_list_permissions

read

List permissions of a file

create_folder

write

Create a folder

move_file

write

Move a file into a folder

drive_copy_file

write

Copy a file

share_file

write

Share with user/group/domain/anyone

drive_revoke_public

destructive

Revoke public access (confirm=true)

Tool

Type

Description

drive_upload

write

Upload a local file; convert_to turns docx/xlsx/pptx into native Google files

drive_download

read

Download a binary file to disk

drive_export

read

Export a Doc/Sheet/Slide to pdf, docx, xlsx, pptx, csv…

Tool

Type

Description

read_sheet

read

Read a cell range

get_spreadsheet_meta

read

Sheet names and IDs

sheet_export_csv

read

Export a range as CSV

append_row

write

Append a row

update_sheet

write

Write rows to a range

create_spreadsheet

write

Create a spreadsheet

add_sheet

write

Add a tab

sheet_create_filter_view

write

Create a filter view

sheet_create_named_range

write

Create a named range

sheet_find_replace

write

Find & replace (dry_run=true by default)

sheet_format

write

Bold, colours, number formats, widths, row heights, frozen panes

clear_range

destructive

Clear a range (auto dry-run for large ranges)

Tool

Type

Description

read_doc

read

Read text and tables

doc_export_pdf

read

Export as binary PDF

create_doc

write

Create a document

append_to_doc

write

Append text

doc_fill_template

destructive

Fill placeholders (confirm=true)

Tool

Type

Description

slides_create

write

Create a presentation

slides_get

read

Slide count, IDs and text per slide

slides_add_slide

write

Add a slide with a predefined layout

slides_replace_text

destructive

Replace placeholders (confirm=true)

slides_insert_image

write

Insert a public image URL onto a slide

Tool

Type

Description

get_script_content

read

Read project files

create_script_project

write

Create a project

prepare_script_update

write

Stage an update, returns operation_id

execute_operation

write

Apply a staged update (auto-backup first)

cancel_operation

write

Cancel a staged update

restore_script_backup

write

Restore from a backup

script_run_function

destructive

Run a function from an API-executable deployment

Tool

Type

Description

get_gmail_profile

read

Authenticated address

list_emails

read

List with date, sender and subject

read_email

read

Headers, labels, attachments and decoded body

gmail_search_and_summarize

read

Search with a compact summary

gmail_get_thread

read

Whole conversation

gmail_get_attachment

read

Save an attachment to disk

create_draft

write

Create a draft

send_email

write

Send or draft (draft_mode=true by default)

send_draft

write

Send an existing draft

gmail_reply

write

Reply in-thread (draft_mode=true by default)

gmail_label_apply

write

Apply a label (dry_run=true by default)

gmail_archive

write

Archive (confirm=true)

delete_email

destructive

Delete (confirm=true)

batch_delete_emails

destructive

Delete many (dry_run=true by default)

Tool

Type

Description

report_from_sheet

write

Read a range → column statistics → Doc with native tables or plain text (output=text)

digest

write

Last N hours across Gmail, Calendar and Drive → text or Doc

compare_tables

write

Diff two ranges by a key column; output=doc builds native tables

clone_and_fill

write

Copy any Drive file and replace placeholders in the copy

sheet_to_slides

write

Read a range → deck: title slide + one slide per row group

Tool

Type

Description

list_events

read

Upcoming events with times and locations

calendar_find_free_slots

read

Free slots in a window

create_event

write

Create an event

calendar_create_meeting

write

Meeting with attendees (confirm=true)

calendar_update_event

write

Change any field; only what you pass is modified

calendar_delete_event

destructive

Delete an event (confirm=true)

calendar_respond_to_invite

write

Accept / decline / tentative (confirm=true)

Resources

URI

Attaches

gdrive://recent

20 most recently modified Drive files

gmail://inbox

Recent unread inbox messages

gcalendar://upcoming

Events for the next 7 days

gdrive://file/{file_id}

Metadata for one file

gsheets://{spreadsheet_id}/{range}

A sheet range as a table

gdocs://{document_id}

Full document text, tables included

Prompts

Prompt

What it does

summarize_inbox

Fetch recent mail → ready for a summary

analyze_spreadsheet

Read a range → ready for analysis

plan_week

Load calendar events → ready for planning

search_drive

Search files → ready for organisation advice

weekly_review

Last N days of mail, files and agenda → weekly summary

inbox_triage

Gmail slice → urgent / waiting / informational / archive

sheet_brief

Range → statistics plus a briefing question

compare_brief

Two ranges → reconciliation report

Safety by default

Guard

Applies to

confirm=true required

delete_email, gmail_archive, calendar_create_meeting, drive_revoke_public, doc_fill_template, slides_replace_text

dry_run=true by default

batch_delete_emails, sheet_find_replace, gmail_label_apply

Draft mode by default

send_email, gmail_reply

Public sharing blocked

share_file refuses type=anyone without allow_public=true

No silent overwrite

drive_download, drive_export, gmail_get_attachment

Staged Apps Script

prepare_script_update → execute_operation (backup first)

Tool annotations

every tool carries readOnlyHint / destructiveHint

Server-side profiles

read-only / read-write / full + allow/deny lists

⚠️ An agent can reach everything your OAuth token can. Use read-only scopes and the read-only profile for sensitive accounts — docs/SECURITY.md.

How it works

server.py                    MCP server: 67 tool definitions, resources, prompts, profiles
workspace_operator/
├─ profiles.py               read-only / read-write / full + allow-deny lists
├─ config.py                 config file + environment overrides
├─ auth.py                   OAuth 2.0 credentials and token cache
├─ text.py                   entity/whitespace normalisation, timestamps, error hints
├─ operations.py             staged-operation store for Apps Script
├─ security.py               token and email checks
├─ runtime.py                retries, audit log, dry-run helpers
├─ cli.py                    doctor / tools / serve
└─ handlers/
   ├─ search.py              workspace_search — Drive + Gmail + Calendar
   ├─ files.py               drive_upload / drive_download / drive_export
   ├─ formatting.py          sheet_format request builders
   ├─ gmail_threads.py       threads, attachments, in-thread replies
   ├─ slides.py              presentations
   ├─ calendar_writes.py     update / delete / invite responses
   ├─ report.py              report_from_sheet: stats + document
   ├─ digest.py              digest across mail, calendar and drive
   ├─ compare.py             table diff by key column
   ├─ template.py            clone a file and fill placeholders
   ├─ deck.py                table → presentation
   ├─ drive.py  sheets.py  docs.py
   ├─ gmail.py  calendar.py  apps_script.py
tests/                       unit, live and round-trip checks
antigravity/                 ready-to-paste mcp_config.json
skills/google-workspace/     Agent Skill: when to use which tool

Design rules:

  • every handler returns a string — exceptions never reach the transport;

  • writes are staged, confirmed or drafted, never silent;

  • Apps Script is a two-phase commit with an automatic backup;

  • server-side profiles keep the exposed surface small.

Testing

python -m unittest discover -s tests -v     # 251 unit tests, no network
python tests/live_smoke.py                  # 51 checks against a real account
python tests/pptx_roundtrip.py deck.pptx    # 5 checks: pptx → Slides → replace

The live suite is self-cleaning: it uploads and trashes a temp file, creates and trashes a presentation and a spreadsheet, drafts and deletes a reply, downloads an attachment and removes it. tests/test_docs.py keeps this README, the docs and the code in sync (tool counts, profile numbers, links, examples).

Documentation

🇬🇧 English

Document

Description

AUTH_SETUP.md

Google OAuth setup, step by step

TOOLS_REFERENCE.md

Every tool, resource and prompt

SECURITY.md

Scopes, profiles, safety model

IDE_SETUP.md

Antigravity, Cursor, Windsurf, VS Code

TROUBLESHOOTING.md

Symptom → cause → fix, including Docker

LEARN.md

How this server was built

docs/

Release notes and specs for every version

🇷🇺 На русском

Документ

Описание

AUTH_SETUP.md

Пошаговая настройка OAuth

TOOLS_REFERENCE.md

Справочник инструментов

SECURITY.md

Скоупы, профили, модель безопасности

IDE_SETUP.md

Antigravity, Cursor, Windsurf, VS Code

Limitations

Knowing the edges is part of the contract:

  • Drive: files can be created, copied, moved and unshared, but not deleted — use the Drive UI for that.

  • Sheets: no conditional formatting, charts or pivot tables; plain cell formatting only.

  • Docs: no comments, and tables can be created by the report tool but not edited cell by cell afterwards.

  • Slides: slides can be added and filled, but not deleted or reordered.

  • One account per server: a single OAuth token, no multi-tenant mode.

Roadmap

  • Cross-product search, tool profiles

  • Files, Slides, Apps Script execution

  • Sheet formatting

  • Gmail threads, attachments, replies

  • Calendar update/delete/respond

  • Composite tools: report_from_sheet, digest, compare_tables, clone_and_fill

  • Optional HTTP transport (Streamable HTTP, stateless, localhost-first)

Responsibility

You are responsible for what the agent does with your account. Read docs/SECURITY.md, start with read-only, keep backups on.


MIT licensed · built on the MCP Python SDK

Related MCP Connectors

Related MCP Servers