Google Sheets and Drive MCP
# Google Sheets and Drive MCP
Локальный пакет с двумя MCP-серверами по `stdio`:
- `google-sheets-mcp` предоставляет 25 инструментов для предсказуемого чтения,
изменения и анализа Google-таблиц;
- `google-drive-mcp` предоставляет поиск и перечисление таблиц, а также отдельный
чувствительный инструмент для выдачи editor-доступа к разрешённым файлам.
## Инструменты MCP
- `health` — диагностика конфигурации и лимитов;
- `get_spreadsheet` — метаданные таблицы и список листов;
- `create_sheet` — создание пустого листа с ограниченным начальным размером;
- `rename_sheet` — переименование существующего листа;
- `copy_sheet` — полное дублирование листа внутри той же таблицы;
- `read_range` — чтение ограниченного A1-диапазона;
- `batch_read_ranges` — чтение нескольких ограниченных диапазонов одним API-запросом;
- `read_sheet` — безопасное постраничное чтение листа с `next_start_row`;
- `write_range` — запись прямоугольной матрицы значений;
- `batch_write_ranges` — запись нескольких прямоугольных диапазонов одним API-запросом;
- `clear_range` — очистка значений в одном ограниченном диапазоне;
- `append_rows` — добавление строк в конец табличного диапазона;
- `unpivot_range` — преобразование широкой таблицы в длинную с записью результата;
- `create_pivot_table` — создание нативной сводной таблицы Google Sheets;
- `create_chart` — создание нативной диаграммы Google Sheets;
- `set_basic_filter` и `clear_basic_filter` — установка и снятие фильтра;
- `sort_range` — сортировка по одному или нескольким заголовкам;
- `add_conditional_format` — цветовое условное форматирование;
- `freeze_panes` — закрепление верхних строк и левых колонок;
- `write_formulas` — запись прямоугольной матрицы формул;
- `insert_image` — вставка изображения внутрь ячейки по HTTP(S)-URL;
- `copy_range` — копирование значений, формул, форматов и правил;
- `grant_read_access` — выдача пользователю права `reader` на всю таблицу;
- `set_sheet_visibility` — скрытие и возврат листа.
`create_chart` поддерживает все нативные семейства диаграмм Google Sheets:
`COLUMN`, `BAR`, `LINE`, `AREA`, `SCATTER`, `COMBO`, `STEPPED_AREA`, `PIE`,
`HISTOGRAM`, `BUBBLE`, `WATERFALL`, `SCORECARD`, `CANDLESTICK`, `TREEMAP` и `ORG`.
`create_pivot_table` поддерживает группировки по строкам и столбцам, итоги и
стандартные функции агрегации: `SUM`, `COUNT`, `AVERAGE`, `MIN`, `MAX` и другие.
Для условного форматирования используются цвета `#RRGGBB`. Например, два
вызова с условиями `NUMBER_GREATER` и `NUMBER_LESS` позволяют выделить
положительные значения зелёным, а отрицательные — красным.
`batch_read_ranges` принимает список bounded A1-диапазонов и применяет лимит
чтения к их суммарному потенциальному размеру. `batch_write_ranges` принимает
список объектов `{"range": ..., "values": ...}` и применяет лимит записи к
суммарному числу ячеек во всех прямоугольных матрицах. Порядок диапазонов
сохраняется; batch-write является идемпотентной перезаписью указанных диапазонов.
`clear_range` требует явно указать лист и bounded A1-диапазон, например
`'Data'!A1:D20`. Операция учитывает общий write-лимит и очищает только значения:
форматирование, data validation, комментарии и размеры листа не изменяются.
`create_sheet` создаёт пустой лист с настраиваемым числом строк и колонок;
начальная сетка ограничена одним миллионом ячеек и 18 278 колонками.
`rename_sheet` сохраняет данные, позицию и свойства листа. `copy_sheet`
дублирует весь лист только внутри той же Google-таблицы, включая данные и
оформление; копирование между разными `spreadsheet_id` не выполняется.
`set_basic_filter` создаёт один нативный Basic Filter и заменяет предыдущий
Basic Filter листа. `clear_basic_filter` снимает его. `freeze_panes` принимает
число закреплённых строк и колонок; нулевые значения снимают закрепление.
`write_formulas` принимает только строки, начинающиеся с `=`. `insert_image`
использует нативную формулу `IMAGE()` и требует URL, доступный Google; локальные
файлы сначала нужно разместить в доступном хранилище. Поддерживаются режимы
вписывания, растягивания, исходного и пользовательского размера.
`copy_range` работает внутри одной Google-таблицы и поддерживает `PASTE_VALUES`,
`PASTE_FORMULA`, `PASTE_FORMAT`, `PASTE_NORMAL`, перенос data validation,
условного форматирования и транспонирование. Для копирования между разными
таблицами можно использовать связку `read_range` → `write_range`.
`grant_read_access` работает через Google Drive API и выдаёт доступ ко всему
файлу таблицы — Google не поддерживает отдельные права чтения для одного листа.
Для работы с существующими файлами, которые были расшарены на service account,
Drive-клиенту требуется полный scope `https://www.googleapis.com/auth/drive`:
узкий `drive.file` такие файлы не видит. Сервисный аккаунт также должен иметь
право делиться файлом, а доменная политика Google Workspace может запрещать
внешний доступ.
`set_sheet_visibility` не является механизмом защиты: скрытый лист остаётся
частью таблицы и доступен через API. Инструмент не позволяет скрыть последний
видимый лист и поддерживает обратную операцию через `hidden=false`.
## Google Drive MCP
Отдельный `google-drive-mcp` предоставляет четыре инструмента:
- `health` — диагностика credentials и собственных границ безопасности;
- `list_spreadsheets(page_size=50, page_token=null)` — перечисление доступных
Google-таблиц с пагинацией;
- `search_spreadsheets(name_query, page_size=50, page_token=null)` — безопасный
поиск по буквальной подстроке имени без произвольного Drive query;
- `grant_edit_access(file_id, email, send_notification_email=false)` — выдача
пользователю фиксированной роли `writer` на весь файл.
Read-инструменты возвращают только `file_id`, имя и время последнего изменения.
Размер страницы ограничен диапазоном 1–100. Если allowlist пуст, используются
нативные page tokens Google Drive. При включённом allowlist сервер запрашивает
только явно разрешённые ID через `files.get`, фильтрует неподходящие и недоступные
файлы и использует собственный непрозрачный page token.
Если permission отсутствует, сервер создаёт его. Существующий `reader` или
`commenter` повышается до `writer`; `writer`, `fileOrganizer`, `organizer` и
`owner` возвращают успешный no-op и никогда не понижаются. Произвольные роли,
передача владения, доменные permissions, revoke и downgrade не поддерживаются.
Google Drive не позволяет выдать editor-доступ только к одному листу или диапазону:
операция меняет доступ ко всему файлу.
## Требования
- Python 3.12–3.14
- `uv`
- Google Cloud service account с включёнными Google Sheets API и Google Drive API
## Установка
```bash
UV_CACHE_DIR=.uv-cache uv sync
```
Скопируйте `.env.example` в локальный `.env` либо экспортируйте переменные в
окружение MCP-клиента. JSON-ключ и `.env` нельзя добавлять в репозиторий.
## Подготовка Google Cloud
1. Включите Google Sheets API в нужном Google Cloud project.
2. Создайте service account и скачайте JSON-ключ в каталог вне репозитория.
3. Расшарьте тестовую таблицу на email service account с нужными правами.
4. Установите `GOOGLE_APPLICATION_CREDENTIALS` в абсолютный путь к ключу.
## Запуск
```bash
UV_CACHE_DIR=.uv-cache uv run google-sheets-mcp
UV_CACHE_DIR=.uv-cache uv run google-drive-mcp
```
Оба сервера используют `stdio`: обычный вывод зарезервирован под MCP-протокол.
Диагностический инструмент `health` проверяет конфигурацию без обращения к Google API.
## Подключение к Codex
Codex CLI, IDE extension и desktop app используют общую MCP-конфигурацию.
Зарегистрировать локальный сервер можно командой:
```bash
codex mcp add google_sheets \
--env GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
--env GOOGLE_SHEETS_MAX_READ_CELLS=100000 \
--env GOOGLE_SHEETS_MAX_WRITE_CELLS=10000 \
--env GOOGLE_SHEETS_REQUEST_TIMEOUT_SECONDS=30 \
--env GOOGLE_SHEETS_MAX_RETRIES=2 \
--env GOOGLE_SHEETS_RETRY_BASE_DELAY_SECONDS=0.5 \
--env GOOGLE_SHEETS_READ_ONLY=true \
--env GOOGLE_SHEETS_ALLOWED_SPREADSHEET_IDS=spreadsheet-id \
-- /absolute/path/to/google_sheets_tool/.venv/bin/google-sheets-mcp
codex mcp add google_drive \
--env GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
--env GOOGLE_DRIVE_REQUEST_TIMEOUT_SECONDS=30 \
--env GOOGLE_DRIVE_READ_ONLY=false \
--env GOOGLE_DRIVE_ALLOWED_FILE_IDS=file-id \
-- /absolute/path/to/google_sheets_tool/.venv/bin/google-drive-mcp
```
Проверить регистрацию:
```bash
codex mcp get google_sheets
codex mcp get google_drive
codex mcp list
```
После изменения MCP-конфигурации перезапустите Codex или IDE extension. В TUI
список подключённых серверов доступен через `/mcp`. JSON-ключ не следует
копировать в репозиторий или записывать непосредственно в `config.toml`;
конфигурация хранит только абсолютный путь к нему.
Эквивалентная ручная конфигурация в `~/.codex/config.toml`:
```toml
[mcp_servers.google_sheets]
command = "/absolute/path/to/google_sheets_tool/.venv/bin/google-sheets-mcp"
startup_timeout_sec = 10
tool_timeout_sec = 60
enabled = true
[mcp_servers.google_sheets.env]
GOOGLE_APPLICATION_CREDENTIALS = "/absolute/path/to/service-account.json"
GOOGLE_SHEETS_MAX_READ_CELLS = "100000"
GOOGLE_SHEETS_MAX_WRITE_CELLS = "10000"
GOOGLE_SHEETS_REQUEST_TIMEOUT_SECONDS = "30"
GOOGLE_SHEETS_MAX_RETRIES = "2"
GOOGLE_SHEETS_RETRY_BASE_DELAY_SECONDS = "0.5"
GOOGLE_SHEETS_READ_ONLY = "true"
GOOGLE_SHEETS_ALLOWED_SPREADSHEET_IDS = "spreadsheet-id"
[mcp_servers.google_drive]
command = "/absolute/path/to/google_sheets_tool/.venv/bin/google-drive-mcp"
startup_timeout_sec = 10
tool_timeout_sec = 60
enabled = true
[mcp_servers.google_drive.env]
GOOGLE_APPLICATION_CREDENTIALS = "/absolute/path/to/service-account.json"
GOOGLE_DRIVE_REQUEST_TIMEOUT_SECONDS = "30"
GOOGLE_DRIVE_READ_ONLY = "false"
GOOGLE_DRIVE_ALLOWED_FILE_IDS = "file-id"
```
## Границы безопасности
`GOOGLE_SHEETS_READ_ONLY=true` запускает сервер с Google scope
`spreadsheets.readonly`, убирает изменяющие инструменты из MCP discovery и
дополнительно отклоняет прямые попытки их вызова. Доступными остаются `health`,
`get_spreadsheet`, `read_range`, `batch_read_ranges` и `read_sheet`.
`GOOGLE_SHEETS_ALLOWED_SPREADSHEET_IDS` принимает разделённый запятыми список
точных `spreadsheet_id`. Если список непустой, любой инструмент отклоняет работу
с другими таблицами до создания Google API-клиента. Пустое значение сохраняет
режим без ограничений. Параметры можно совмещать:
```bash
GOOGLE_SHEETS_READ_ONLY=true
GOOGLE_SHEETS_ALLOWED_SPREADSHEET_IDS=spreadsheet-id-1,spreadsheet-id-2
```
Инструмент `health` сообщает только состояние режимов и количество разрешённых
таблиц, но не раскрывает сами идентификаторы.
`GOOGLE_DRIVE_READ_ONLY=true` убирает `grant_edit_access` из discovery и блокирует
его прямой вызов; Drive-клиент получает scope `drive.metadata.readonly` вместо
полного `drive`. `GOOGLE_DRIVE_ALLOWED_FILE_IDS` принимает разделённый запятыми
список точных `file_id`. При непустом списке list/search обращаются только к этим
ID, а editor-доступ к любому другому файлу отклоняется до создания API-клиента.
Пустой список разрешает любой видимый service account файл. Drive `health`
сообщает только факт включения allowlist и число файлов, не раскрывая ID.
## Повторы временных ошибок
Для HTTP `429`, `500`, `502`, `503` и `504` сервер выполняет ограниченный
exponential backoff. По умолчанию разрешены два повтора с задержками 0,5 и
1 секунду. `GOOGLE_SHEETS_MAX_RETRIES=0` полностью отключает повторы; допустимый
диапазон — от 0 до 5. Начальная задержка задаётся через
`GOOGLE_SHEETS_RETRY_BASE_DELAY_SECONDS`: больше 0 и не более 60 секунд.
Автоматически повторяются только чтения и операции с однозначным конечным
состоянием: `write_range` (включая формулы и изображения),
`batch_write_ranges`, `clear_range`, `rename_sheet`, установка и снятие Basic
Filter, freeze panes и visibility.
Сервер никогда автоматически не
повторяет `append_rows`, `grant_read_access`, `create_sheet`, `copy_sheet`,
создание диаграмм, pivot-таблиц и условных правил, сортировку или копирование
диапазона.
`google-drive-mcp` также не повторяет create/update permission. После timeout
вызывающая сторона должна сначала проверить фактическую роль и только затем
решать, нужен ли отдельный ручной повтор.
## Ограничения
- сервер рассчитан на локальный однопользовательский запуск по `stdio`;
- авторизация выполняется только через Google Cloud service account;
- allowlist ограничивает таблицы целиком, но не отдельные листы или диапазоны;
- `grant_read_access` использует полный Google Drive scope и меняет доступ ко
всему файлу, а не к одному листу;
- `grant_edit_access` находится только в `google-drive-mcp`, всегда запрашивает
роль `writer` для всего файла и требует capability `canShare`;
- `insert_image` требует HTTP(S)-URL, доступный серверам Google;
- сервер не создаёт и не удаляет Google-таблицы целиком;
- multi-step операции не являются транзакциями Google Sheets;
- после timeout неоднозначной операции вызывающая сторона должна проверить
фактическое состояние перед ручным повтором.
## Разработка
```bash
UV_CACHE_DIR=.uv-cache uv run ruff check .
UV_CACHE_DIR=.uv-cache uv run pytest
UV_CACHE_DIR=.uv-cache uv build
UV_CACHE_DIR=.uv-cache .venv/bin/python scripts/check_release_artifacts.py
UV_CACHE_DIR=.uv-cache .venv/bin/python scripts/smoke_package.py
```
GitHub Actions выполняет те же проверки на Python 3.12 для каждого push и pull
request: устанавливает зависимости строго из `uv.lock`, запускает Ruff и Pytest,
затем собирает sdist и wheel и устанавливает wheel в чистое временное окружение.
Явный smoke-тест чтения не выводит значения ячеек:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_SHEETS_TEST_SPREADSHEET_ID=spreadsheet-id \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_read.py
```
Smoke-тест записи создаёт или переиспользует изолированный лист `_mcp_test`,
очищает только `A:Z` на этом листе и проверяет запись чтением обратно:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_SHEETS_TEST_SPREADSHEET_ID=spreadsheet-id \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_write.py
```
Аналитический smoke-тест пересоздаёт только `_mcp_test`, затем проверяет
постраничное чтение, unpivot, нативную сводную таблицу и диаграмму:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_SHEETS_TEST_SPREADSHEET_ID=spreadsheet-id \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_analytics.py
```
Smoke-тест представления проверяет все типы диаграмм, фильтр, сортировку,
условное форматирование и закрепление панелей:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_SHEETS_TEST_SPREADSHEET_ID=spreadsheet-id \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_presentation.py
```
Smoke-тест содержимого проверяет формулы, копирование значений и формул, а
также вставку изображения в ячейку:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_SHEETS_TEST_SPREADSHEET_ID=spreadsheet-id \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_content.py
```
Smoke-тест доступа проверяет Drive capability `canShare`, временно скрывает
`_mcp_test`, подтверждает состояние и возвращает лист видимым:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_SHEETS_TEST_SPREADSHEET_ID=spreadsheet-id \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_access.py
```
Отдельный smoke-тест безопасно выдаёт право чтения: сначала проверяет наличие
permission, не создаёт дубликат и подтверждает результат чтением обратно.
Уведомление пользователю не отправляется:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_SHEETS_TEST_SPREADSHEET_ID=spreadsheet-id \
GOOGLE_SHEETS_TEST_READER_EMAIL=user@example.com \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_grant_access.py
```
Полный последовательный прогон всех smoke-тестов:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_SHEETS_TEST_SPREADSHEET_ID=spreadsheet-id \
GOOGLE_SHEETS_TEST_READER_EMAIL=user@example.com \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_all.py
```
Прогон изменяет только тестовый лист `_mcp_test`. Аналитические, presentation и
content-сценарии пересоздают этот лист, поэтому хранить на нём рабочие данные
нельзя.
Проверка всех инструментов через настоящий MCP `stdio`-протокол:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_SHEETS_TEST_SPREADSHEET_ID=spreadsheet-id \
GOOGLE_SHEETS_TEST_READER_EMAIL=user@example.com \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_mcp_stdio.py
```
Отдельный Drive MCP smoke проверяет discovery четырёх инструментов, list/search
строго внутри allowlist, выдачу writer-доступа без уведомления и восстановление
исходного permission в `finally`:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_DRIVE_TEST_FILE_ID=file-id \
GOOGLE_DRIVE_TEST_EDITOR_EMAIL=user@example.com \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_drive_mcp_stdio.py
```
Полный release-smoke объединяет Sheets API, оба MCP `stdio` сценария и временные
проверки permissions. Подробный вывод дочерних сценариев подавляется, а исходный
permission тестового пользователя восстанавливается в `finally`:
```bash
GOOGLE_APPLICATION_CREDENTIALS=/absolute/path/to/service-account.json \
GOOGLE_SHEETS_TEST_SPREADSHEET_ID=spreadsheet-id \
GOOGLE_SHEETS_TEST_READER_EMAIL=user@example.com \
UV_CACHE_DIR=.uv-cache uv run python scripts/smoke_release.py
```
## Лицензия и релиз
Проект распространяется по лицензии [MIT](LICENSE). История изменений находится
в [CHANGELOG.md](CHANGELOG.md), а обязательные проверки перед публикацией — в
[RELEASE_CHECKLIST.md](RELEASE_CHECKLIST.md).
Полный план и границы MVP описаны в [PLAN.md](PLAN.md).
TDQS
Scored across 25 tools
Each tool has a distinct and clearly defined purpose. Even similar tools like read_range, batch_read_ranges, and read_sheet are differentiated by scope (bounded range, multiple ranges, entire sheet page). No overlapping functionality.
All tool names follow a consistent verb_noun pattern in snake_case (e.g., get_spreadsheet, clear_range, create_sheet). The only exception is 'health', but it is a simple status check and fits the pattern if considered as a verb implied. Overall, naming is highly predictable.
25 tools is slightly above the typical 3-15 range, but each tool provides a specific, non-redundant operation. The count is justified by the breadth of Google Sheets functionality covered, though it could be trimmed (e.g., batch operations could be merged).
The tool set covers many common operations but has notable gaps: no delete_sheet, no create_spreadsheet, no delete_rows, and no cross-spreadsheet copy/move. This will cause agents to struggle with basic workflows like creating and deleting spreadsheets or deleting data.