mcp-gee-sweet 0.0.0.dev133__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.
Files changed (92) hide show
  1. mcp_gee_sweet-0.0.0.dev133/.claude/commands/prep-for-pr.md +36 -0
  2. mcp_gee_sweet-0.0.0.dev133/.dockerignore +4 -0
  3. mcp_gee_sweet-0.0.0.dev133/.github/workflows/ci.yml +35 -0
  4. mcp_gee_sweet-0.0.0.dev133/.github/workflows/docs.yml +30 -0
  5. mcp_gee_sweet-0.0.0.dev133/.github/workflows/publish-dev.yml +55 -0
  6. mcp_gee_sweet-0.0.0.dev133/.github/workflows/release.yml +72 -0
  7. mcp_gee_sweet-0.0.0.dev133/.gitignore +18 -0
  8. mcp_gee_sweet-0.0.0.dev133/.pre-commit-config.yaml +7 -0
  9. mcp_gee_sweet-0.0.0.dev133/.python-version +1 -0
  10. mcp_gee_sweet-0.0.0.dev133/CLAUDE.md +73 -0
  11. mcp_gee_sweet-0.0.0.dev133/CONTRIBUTING.md +155 -0
  12. mcp_gee_sweet-0.0.0.dev133/Dockerfile +45 -0
  13. mcp_gee_sweet-0.0.0.dev133/LICENSE +22 -0
  14. mcp_gee_sweet-0.0.0.dev133/Makefile +57 -0
  15. mcp_gee_sweet-0.0.0.dev133/PKG-INFO +147 -0
  16. mcp_gee_sweet-0.0.0.dev133/README.md +126 -0
  17. mcp_gee_sweet-0.0.0.dev133/TODO.md +153 -0
  18. mcp_gee_sweet-0.0.0.dev133/docker-compose.yml +18 -0
  19. mcp_gee_sweet-0.0.0.dev133/docs/auth.md +94 -0
  20. mcp_gee_sweet-0.0.0.dev133/docs/client-setup.md +91 -0
  21. mcp_gee_sweet-0.0.0.dev133/docs/configuration.md +68 -0
  22. mcp_gee_sweet-0.0.0.dev133/docs/decisions/decision-chart-theming.md +85 -0
  23. mcp_gee_sweet-0.0.0.dev133/docs/decisions/decision-composite-tools.md +50 -0
  24. mcp_gee_sweet-0.0.0.dev133/docs/decisions/decision-docs-formatting.md +135 -0
  25. mcp_gee_sweet-0.0.0.dev133/docs/decisions/decision-fork.md +57 -0
  26. mcp_gee_sweet-0.0.0.dev133/docs/decisions/decision-publishing.md +54 -0
  27. mcp_gee_sweet-0.0.0.dev133/docs/decisions/decision-testing.md +124 -0
  28. mcp_gee_sweet-0.0.0.dev133/docs/decisions/index.md +12 -0
  29. mcp_gee_sweet-0.0.0.dev133/docs/design/docs-ast-pipeline.md +302 -0
  30. mcp_gee_sweet-0.0.0.dev133/docs/design/effectiveformat-spike.md +88 -0
  31. mcp_gee_sweet-0.0.0.dev133/docs/design/index.md +9 -0
  32. mcp_gee_sweet-0.0.0.dev133/docs/design/markdown-support.md +195 -0
  33. mcp_gee_sweet-0.0.0.dev133/docs/design/phase3-theme-system.md +86 -0
  34. mcp_gee_sweet-0.0.0.dev133/docs/design.md +84 -0
  35. mcp_gee_sweet-0.0.0.dev133/docs/index.md +42 -0
  36. mcp_gee_sweet-0.0.0.dev133/docs/notes-read.md +31 -0
  37. mcp_gee_sweet-0.0.0.dev133/docs/qa/README.md +41 -0
  38. mcp_gee_sweet-0.0.0.dev133/docs/qa/fixtures.template.md +16 -0
  39. mcp_gee_sweet-0.0.0.dev133/docs/qa/operations.yaml +225 -0
  40. mcp_gee_sweet-0.0.0.dev133/docs/qa/results/.gitkeep +0 -0
  41. mcp_gee_sweet-0.0.0.dev133/docs/qa/results/2026-06-02.md +364 -0
  42. mcp_gee_sweet-0.0.0.dev133/docs/qa/results/2026-06-14.md +104 -0
  43. mcp_gee_sweet-0.0.0.dev133/docs/qa/results/2026-06-17.md +65 -0
  44. mcp_gee_sweet-0.0.0.dev133/docs/qa/results/2026-06-18.md +41 -0
  45. mcp_gee_sweet-0.0.0.dev133/docs/qa/run.md +111 -0
  46. mcp_gee_sweet-0.0.0.dev133/docs/qa/setup.md +121 -0
  47. mcp_gee_sweet-0.0.0.dev133/docs/qa/tests/calendar.md +441 -0
  48. mcp_gee_sweet-0.0.0.dev133/docs/qa/tests/docs.md +1012 -0
  49. mcp_gee_sweet-0.0.0.dev133/docs/qa/tests/drive.md +1771 -0
  50. mcp_gee_sweet-0.0.0.dev133/docs/qa/tests/infra.md +230 -0
  51. mcp_gee_sweet-0.0.0.dev133/docs/qa/tests/sheets_charts.md +145 -0
  52. mcp_gee_sweet-0.0.0.dev133/docs/qa/tests/sheets_mgmt.md +287 -0
  53. mcp_gee_sweet-0.0.0.dev133/docs/qa/tests/sheets_read.md +429 -0
  54. mcp_gee_sweet-0.0.0.dev133/docs/qa/tests/sheets_write.md +340 -0
  55. mcp_gee_sweet-0.0.0.dev133/docs/qa-checklist.md +447 -0
  56. mcp_gee_sweet-0.0.0.dev133/docs/roadmap.md +240 -0
  57. mcp_gee_sweet-0.0.0.dev133/docs/tools.md +133 -0
  58. mcp_gee_sweet-0.0.0.dev133/mkdocs.yml +69 -0
  59. mcp_gee_sweet-0.0.0.dev133/pyproject.toml +64 -0
  60. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/__init__.py +10 -0
  61. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/auth.py +185 -0
  62. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/cache.py +446 -0
  63. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/server.py +209 -0
  64. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/__init__.py +20 -0
  65. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/cache.py +54 -0
  66. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/calendar.py +432 -0
  67. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/docs/__init__.py +1309 -0
  68. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/docs/ast.py +105 -0
  69. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/docs/emitter.py +639 -0
  70. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/docs/html_parser.py +352 -0
  71. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/drive/__init__.py +5 -0
  72. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/drive/files.py +655 -0
  73. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/drive/sharing.py +299 -0
  74. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/drive/transfer.py +998 -0
  75. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/sheets/__init__.py +0 -0
  76. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/sheets/data.py +473 -0
  77. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/sheets/helpers.py +107 -0
  78. mcp_gee_sweet-0.0.0.dev133/src/mcp_gee_sweet/tools/sheets/structure.py +512 -0
  79. mcp_gee_sweet-0.0.0.dev133/tests/__init__.py +0 -0
  80. mcp_gee_sweet-0.0.0.dev133/tests/drive/__init__.py +0 -0
  81. mcp_gee_sweet-0.0.0.dev133/tests/drive/test_files.py +192 -0
  82. mcp_gee_sweet-0.0.0.dev133/tests/drive/test_sharing.py +278 -0
  83. mcp_gee_sweet-0.0.0.dev133/tests/drive/test_transfer.py +137 -0
  84. mcp_gee_sweet-0.0.0.dev133/tests/sheets/__init__.py +0 -0
  85. mcp_gee_sweet-0.0.0.dev133/tests/sheets/test_data.py +139 -0
  86. mcp_gee_sweet-0.0.0.dev133/tests/sheets/test_helpers.py +101 -0
  87. mcp_gee_sweet-0.0.0.dev133/tests/sheets/test_structure.py +236 -0
  88. mcp_gee_sweet-0.0.0.dev133/tests/test_cache.py +272 -0
  89. mcp_gee_sweet-0.0.0.dev133/tests/test_calendar.py +366 -0
  90. mcp_gee_sweet-0.0.0.dev133/tests/test_docs.py +1877 -0
  91. mcp_gee_sweet-0.0.0.dev133/tests/test_server.py +95 -0
  92. mcp_gee_sweet-0.0.0.dev133/uv.lock +1858 -0
@@ -0,0 +1,36 @@
1
+ # PR Readiness Checklist
2
+
3
+ Review the current branch against this checklist and report the status of each item. Be specific — name the files, test IDs, or code paths involved rather than answering generically.
4
+
5
+ ## 1. Tests
6
+
7
+ - [ ] **Unit tests written** — are there new tests in `tests/` covering the changed code?
8
+ - [ ] **Unit tests passing** — has `uv run python -m pytest tests/` been run and passed?
9
+ - [ ] **Regression coverage** — were tests that touch the modified files (not just new tests) also run?
10
+ - [ ] **QA test cases written** — are there AI-driven test cases in `docs/qa/tests/` for the new/changed tools?
11
+ - [ ] **QA tests run** — have those test cases been executed live against the fixture doc?
12
+ - [ ] **QA results recorded** — does each test case have a `**Result (date) ✅/❌**` entry with actual observed output?
13
+
14
+ ## 2. QA test case tags
15
+
16
+ - [ ] **`⚠️ requires-oauth` accuracy** — scan all new and modified test cases:
17
+ - Tag IS present when: the tool itself requires OAuth (e.g. creates files in personal Drive: `create_doc`, `create_doc_from_file`)
18
+ - Tag IS NOT present when: the tool is auth-agnostic and only the test fixture happens to live in personal Drive (`write_doc_content`, `get_doc_structure`, `insert_doc_text`, `delete_doc_range`, `style_doc_range`, `style_doc_table_cells`, etc.)
19
+ - Tag IS NOT present on error-path tests that return before making any API call
20
+
21
+ ## 3. Safety
22
+
23
+ - [ ] **No resource IDs committed** — no Google Drive/Docs/Sheets/Calendar IDs appear in committed files. IDs belong in `.env` or `fixtures.local.md` (both gitignored).
24
+ - [ ] **No secrets or credentials** — no API keys, tokens, or service account JSON content committed.
25
+
26
+ ## 4. Documentation
27
+
28
+ - [ ] **Design doc** — if the work involved an architectural decision or a non-obvious design choice, is it captured in `docs/design/`?
29
+ - [ ] **CLAUDE.md** — if a new tool was added or the architecture changed, does `CLAUDE.md` reflect it?
30
+
31
+ ## 5. PR hygiene
32
+
33
+ - [ ] **Feature branch** — changes are on a named branch, not directly on `main`.
34
+ - [ ] **Issues referenced** — the PR body includes `Closes #N` for every issue this work resolves. Check the branch name, commit messages, and code for issue numbers — all referenced tickets must be linked, not just the primary one.
35
+ - [ ] **PR preview shown** — the full PR title and body were displayed to the user for review before the PR was opened.
36
+ - [ ] **No auto-push** — `git push` only happened after the user approved.
@@ -0,0 +1,4 @@
1
+ .venv/
2
+ __pycache__/
3
+ dist/
4
+ .env
@@ -0,0 +1,35 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ name: Lint and test
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - uses: actions/checkout@v5
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v8.1.0
21
+
22
+ - name: Set up Python 3.12
23
+ run: uv python install 3.12
24
+
25
+ - name: Install dependencies
26
+ run: uv sync --frozen --all-extras --dev --python 3.12
27
+
28
+ - name: Lint
29
+ run: uv run ruff check .
30
+
31
+ - name: Format check
32
+ run: uv run ruff format --check .
33
+
34
+ - name: Run tests
35
+ run: uv run python -m pytest --tb=short
@@ -0,0 +1,30 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+
7
+ permissions:
8
+ contents: write # needed for gh-deploy to push to gh-pages branch
9
+
10
+ jobs:
11
+ deploy:
12
+ name: Build and publish docs
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - uses: actions/checkout@v5
17
+ with:
18
+ fetch-depth: 0 # full history for git-revision-date plugins if added later
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v8.1.0
22
+
23
+ - name: Set up Python 3.12
24
+ run: uv python install 3.12
25
+
26
+ - name: Install dependencies
27
+ run: uv sync --frozen --all-extras --dev --python 3.12
28
+
29
+ - name: Deploy docs
30
+ run: uv run mkdocs gh-deploy --force
@@ -0,0 +1,55 @@
1
+ name: Publish dev
2
+
3
+ on:
4
+ push:
5
+ branches: ["develop"]
6
+
7
+ permissions:
8
+ contents: read
9
+ id-token: write # for OIDC trusted publishing
10
+
11
+ jobs:
12
+ test:
13
+ name: Run tests
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v5
17
+ with:
18
+ fetch-depth: 0 # full history so uv-dynamic-versioning can read tags
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v8.1.0
22
+
23
+ - name: Set up Python 3.12
24
+ run: uv python install 3.12
25
+
26
+ - name: Install dependencies
27
+ run: uv sync --frozen --all-extras --dev --python 3.12
28
+
29
+ - name: Run tests
30
+ run: uv run python -m pytest --tb=short
31
+
32
+ build-and-publish:
33
+ name: Build and publish dev release
34
+ runs-on: ubuntu-latest
35
+ needs: test
36
+
37
+ steps:
38
+ - uses: actions/checkout@v5
39
+ with:
40
+ fetch-depth: 0 # full history so uv-dynamic-versioning can read tags
41
+
42
+ - name: Install uv
43
+ uses: astral-sh/setup-uv@v8.1.0
44
+
45
+ - name: Set up Python 3.12
46
+ run: uv python install 3.12
47
+
48
+ - name: Install dependencies
49
+ run: uv sync --frozen --all-extras --dev --python 3.12
50
+
51
+ - name: Build package
52
+ run: uv build
53
+
54
+ - name: Publish to PyPI
55
+ uses: pypa/gh-action-pypi-publish@v1.14.0
@@ -0,0 +1,72 @@
1
+ name: Publishing
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read # default minimal; pypi-publish job overrides with id-token: write
9
+
10
+ jobs:
11
+ test:
12
+ name: Run tests before release
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v5
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v8.1.0
19
+
20
+ - name: Set up Python 3.12
21
+ run: uv python install 3.12
22
+
23
+ - name: Install dependencies
24
+ run: uv sync --frozen --all-extras --dev --python 3.12
25
+
26
+ - name: Run tests
27
+ run: uv run python -m pytest --tb=short
28
+
29
+ release-build:
30
+ name: Build distribution
31
+ runs-on: ubuntu-latest
32
+ needs: test
33
+ steps:
34
+ - uses: actions/checkout@v5
35
+ with:
36
+ fetch-depth: 0
37
+
38
+ - name: Install uv
39
+ uses: astral-sh/setup-uv@v8.1.0
40
+
41
+ - name: Set up Python 3.12
42
+ run: uv python install 3.12
43
+
44
+ - name: Install dependencies
45
+ run: uv sync --frozen --all-extras --dev --python 3.12
46
+
47
+ - name: Build package
48
+ run: uv build
49
+
50
+ - name: Upload distribution
51
+ uses: actions/upload-artifact@v7
52
+
53
+ with:
54
+ name: release-dists
55
+ path: dist/
56
+
57
+ pypi-publish:
58
+ name: Upload release to PyPI
59
+ runs-on: ubuntu-latest
60
+ needs: release-build
61
+ permissions:
62
+ id-token: write # For trusted publishing
63
+
64
+ steps:
65
+ - name: Download release dists
66
+ uses: actions/download-artifact@v8
67
+ with:
68
+ name: release-dists
69
+ path: dist/
70
+
71
+ - name: Publish to PyPI
72
+ uses: pypa/gh-action-pypi-publish@v1.14.0
@@ -0,0 +1,18 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+ **/credentials.json
9
+ **/token.json
10
+ **/service_account.json
11
+
12
+ .env
13
+
14
+ # Virtual environments
15
+ .venv
16
+ timings.log
17
+ site/
18
+ .workspace
@@ -0,0 +1,7 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.11.9
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,73 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ Run locally from the cloned repo:
8
+ ```bash
9
+ uv run mcp-gee-sweet
10
+ uv run mcp-gee-sweet --transport sse # SSE instead of stdio
11
+ ```
12
+
13
+ Build and publish:
14
+ ```bash
15
+ uv build # produces dist/*.whl
16
+ uv sync # install deps from uv.lock
17
+ ```
18
+
19
+ Docker:
20
+ ```bash
21
+ docker build -t mcp-gee-sweet .
22
+ docker run --rm -p 8000:8000 \
23
+ -e CREDENTIALS_CONFIG=<base64> \
24
+ -e DRIVE_FOLDER_ID=<id> \
25
+ mcp-gee-sweet
26
+ ```
27
+
28
+ Tests live in `tests/` and can be run with `uv run pytest`.
29
+
30
+ ## Architecture
31
+
32
+ Logic is split across `src/mcp_gee_sweet/`: `server.py` (MCP setup, tool decorator, resources), `auth.py` (lifespan, `SpreadsheetContext`), and `tools/` (domain-based layout):
33
+
34
+ - `tools/sheets/data.py` — read/write cell data (`get_sheet_data`, `get_sheet_formulas`, `get_multiple_*`, `find_in_spreadsheet`, `update_cells`, `batch_update_cells`, `batch_update`)
35
+ - `tools/sheets/structure.py` — sheet structure (`list_sheets`, `copy_sheet`, `rename_sheet`, `create_sheet`, `add_rows`, `add_columns`, `add_chart`)
36
+ - `tools/sheets/helpers.py` — A1 notation helpers (`_parse_a1_notation`, `_column_index_to_letter`, etc.)
37
+ - `tools/drive/files.py` — file/folder operations (`create_spreadsheet`, `list_spreadsheets`, `list_files`, `search_files`, `create_folder`, `copy_file`, `move_file`, `rename_file`, `delete_file`, etc.)
38
+ - `tools/drive/sharing.py` — permissions (`share_spreadsheet`, `share_file`, `list_permissions`, `update_permission`, `remove_permission`)
39
+ - `tools/drive/transfer.py` — upload/download/sync/export/revisions
40
+ - `tools/docs/` — Google Docs package (`create_doc`, `get_doc_content`, `write_doc_content`, `create_doc_from_file`, `insert_doc_text`, `delete_doc_range`, `get_doc_structure`, `style_doc_range`, `style_doc_table_cells`, `get_doc_theme`, `get_doc_named_styles`, `apply_theme`); sub-modules: `ast.py` (dataclass schema), `html_parser.py` (HTML→AST), `emitter.py` (AST→Docs API requests + multi-phase table fill including nested table and cell styling support)
41
+ - `tools/cache.py` — `refresh_cache`
42
+ - `tools/calendar.py` — Calendar API tools
43
+
44
+ `__init__.py` just re-exports `main()`.
45
+
46
+ **Startup / auth** (`spreadsheet_lifespan`): FastMCP lifespan context manager that authenticates on server start and injects a `SpreadsheetContext` (holding `sheets_service` and `drive_service`) into every tool call via `ctx.request_context.lifespan_context`.
47
+
48
+ The project philosophy is to be as powerful and flexible as possible by default, while giving security-conscious users the configuration knobs to lock things down. Two mechanisms reflect this:
49
+
50
+ - **Auth** (`AUTH_METHOD`): out of the box the waterfall tries everything so the server just works; setting `AUTH_METHOD` restricts it to exactly one method with no fallback.
51
+ - **Tool surface** (`ENABLED_TOOLS` / `--include-tools`): by default all tools are registered; setting `ENABLED_TOOLS` to a comma-separated list of function names limits the server to exactly that subset. This lets operators expose only the tools their users need.
52
+
53
+ By default (`AUTH_METHOD` unset), auth falls through in order: OAuth (`CREDENTIALS_PATH`/`TOKEN_PATH`) → service account (`CREDENTIALS_CONFIG` or `SERVICE_ACCOUNT_PATH`) → Application Default Credentials. OAuth is tried first because it authenticates as the user (full personal Drive access); service account is a fallback for headless/server deployments.
54
+
55
+ Set `AUTH_METHOD` to pin a specific method with no fallback — removes ambiguity for security audits, CI, or testing a tool's behavior under a known credential type:
56
+ - `AUTH_METHOD=oauth` — OAuth only; fails fast if credentials are missing
57
+ - `AUTH_METHOD=service_account` — service account only; requires `CREDENTIALS_CONFIG` or `SERVICE_ACCOUNT_PATH`
58
+ - `AUTH_METHOD=adc` — ADC only
59
+
60
+ **Tool registration** (`tool` decorator wrapper): A custom `@tool()` decorator wraps `@mcp.tool()`. It checks `ENABLED_TOOLS` (set via `ENABLED_TOOLS` env var or `--include-tools` CLI arg) and skips registration for any tool not in the allowlist. This is how tool filtering works — tools simply aren't registered with FastMCP rather than being conditionally hidden.
61
+
62
+ **Two Google API clients**: The server builds both a Sheets client (`sheets/v4`) and a Drive client (`drive/v3`). Most tools use only the Sheets client; `list_spreadsheets`, `create_spreadsheet`, `share_spreadsheet`, and `list_folders` use Drive. `create_spreadsheet` uses Drive to create the file (so it can place it in a folder), not the Sheets API.
63
+
64
+ **A1 notation helpers**: `_parse_a1_notation`, `_column_index_to_letter`, and `_letter_to_column_index` convert between A1 ranges and the 0-based row/column indices the Sheets batchUpdate API requires. The Sheets values API uses A1 notation directly; batchUpdate requires numeric indices — keep that distinction in mind when adding new tools.
65
+
66
+ **MCP resources**: Two resources are registered — `server://auth-status` (active auth method and Drive capability limits) and `spreadsheet://{spreadsheet_id}/info` (sheet list and grid properties). Both use `mcp.get_lifespan_context()` (not `ctx`) because resources don't receive a `Context` argument the same way tools do.
67
+
68
+ **`batch_update` tool**: This is a passthrough to the Sheets `spreadsheets().batchUpdate()` endpoint and accepts raw request objects. It's the escape hatch for any operation not covered by the named tools (formatting, conditional formatting, dimension properties, etc.).
69
+
70
+ ## Development workflow
71
+
72
+ **MCP restart**: After `docker compose restart mcp-gee-sweet`, Claude Code does not automatically reconnect to the SSE server — you must restart Claude Code too to re-establish the connection.
73
+
@@ -0,0 +1,155 @@
1
+ # Contributing to mcp-gee-sweet
2
+
3
+ ## Quick orientation
4
+
5
+ - `src/mcp_gee_sweet/tools/` — one file per tool category
6
+ - `docs/qa/tests/` — one QA test file per category, matching the tool files
7
+ - `docs/decisions/` — ADRs; `docs/design.md` — living principles doc
8
+ - `docs/qa/operations.yaml` — machine-readable QA operations manifest (see below)
9
+
10
+ ---
11
+
12
+ ## First-time setup
13
+
14
+ ### 1. Clone and install
15
+
16
+ ```bash
17
+ git clone https://github.com/khuisman/mcp-gee-sweet.git
18
+ cd mcp-gee-sweet
19
+ uv sync
20
+ make install-hooks
21
+ ```
22
+
23
+ ### 2. Configure auth and environment
24
+
25
+ Copy the environment template and fill in your credentials:
26
+
27
+ ```bash
28
+ # .env is gitignored — create it at the repo root
29
+ cp /dev/null .env
30
+ ```
31
+
32
+ At minimum you need one auth method and a Drive folder. See [Authentication in the README](README.md#-authentication--environment-variables-detailed) for all options.
33
+
34
+ #### Choosing an auth method
35
+
36
+ | Method | Setup | QA coverage | Best for |
37
+ |---|---|---|---|
38
+ | **Service account** | Place `service_account.json` in repo root; share your Drive folder with the service account email | ~85% of tests — Drive file creation/copy/upload skipped (service accounts have no Drive storage quota) | Headless server deployment; most development work |
39
+ | **OAuth** | Download OAuth client JSON; set `CREDENTIALS_PATH`; browser login on first run | ~95% of tests — all Drive create/copy/upload tests eligible | Full QA runs; local development with a personal Drive |
40
+ | **ADC** | `gcloud auth application-default login` | Same as OAuth | Google Cloud environments; local dev with gcloud installed |
41
+
42
+ **For contributors:** service account covers all read, write, sheets, and chart tests. If you're adding or fixing Drive create/copy/upload tools, OAuth or ADC gives full coverage. Set `QA_AUTH_METHOD` in `.env` to match — the QA conductor will warn you which tests will be skipped before each run.
43
+
44
+ The most common setup for local development:
45
+
46
+ ```
47
+ SERVICE_ACCOUNT_PATH=./service_account.json
48
+ DRIVE_FOLDER_ID=<your folder id>
49
+ QA_AUTH_METHOD=service_account
50
+ ```
51
+
52
+ ### 3. Set up QA fixtures
53
+
54
+ Give your AI assistant a writable Drive folder and tell it to set up your fixtures:
55
+
56
+ > "Read `docs/qa/operations.yaml` and run the `setup_fixtures` operation. My Drive folder is at https://drive.google.com/drive/folders/YOUR_FOLDER_ID"
57
+
58
+ The assistant will:
59
+ - List the folder contents
60
+ - Identify or ask you to create the fixture spreadsheet and doc
61
+ - Populate them with known fixture data
62
+ - Write `TEST_*` IDs to your `.env`
63
+
64
+ **If you are using service account auth:** the folder and both files must be shared with the service account email. Find it at `service_account.json` → `client_email`. The service account cannot access files in personal Drive unless explicitly shared — see [the README](README.md#-google-cloud-platform-setup-detailed) for the sharing steps.
65
+
66
+ ### 4. Run the server
67
+
68
+ ```bash
69
+ make start # Docker (recommended)
70
+ # or
71
+ uv run mcp-gee-sweet --transport sse
72
+ ```
73
+
74
+ ---
75
+
76
+ ## QA operations
77
+
78
+ All QA workflows are defined in [`docs/qa/operations.yaml`](qa/operations.yaml). Any AI assistant that can read files can parse this manifest and offer the operations as a menu.
79
+
80
+ **To see what's available:**
81
+ > "Read `docs/qa/operations.yaml` and tell me what QA operations are available and which ones I can run right now."
82
+
83
+ The assistant will check preconditions (`.env` keys, server connectivity) and tell you which operations are ready.
84
+
85
+ | Operation | When to use |
86
+ |---|---|
87
+ | `setup_fixtures` | First time; or after losing your `.env` |
88
+ | `reset_fixtures` | After destructive tests; any time fixture state is uncertain |
89
+ | `run_suite` | Full regression run across all tool categories |
90
+ | `run_group` | Focused run after changing a specific tool category |
91
+ | `human_confirmation` | Step-by-step with human sign-off on each result |
92
+
93
+ ### Running a group
94
+
95
+ > "Read `docs/qa/operations.yaml` and run the `run_group` operation for `sheets`."
96
+
97
+ Available groups: `read`, `write`, `sheets`, `drive`, `charts`, `calendar`, `infra`
98
+
99
+ ### Human confirmation flow
100
+
101
+ The `human_confirmation` operation steps through tests one at a time — the AI presents each prompt and its evaluation, you confirm the verdict. This is the primary QA method for new test cases and first-time verification. See [`docs/decisions/decision-testing.md`](decisions/decision-testing.md) for the full rationale and phased trust model.
102
+
103
+ ---
104
+
105
+ ## Adding a new tool
106
+
107
+ 1. Add the implementation to the appropriate file in `src/mcp_gee_sweet/tools/`.
108
+ 2. Add QA test cases to the matching file in `docs/qa/tests/` with the next sequential TC number.
109
+ 3. Add the tool name to the `Available Tool Names` list in `README.md`.
110
+ 4. Run `run_group` for the affected category to verify.
111
+
112
+ Every new tool must have at least:
113
+ - A happy-path test case
114
+ - An error/edge-case test case
115
+ - The tool included in the `docs/qa-checklist.md` attestation
116
+
117
+ See [`docs/design.md`](design.md) for the tool inclusion criteria and composite tool rules.
118
+
119
+ ---
120
+
121
+ ## Development workflow
122
+
123
+ ```bash
124
+ make test # unit tests (no credentials needed)
125
+ make lint # ruff linter + formatter
126
+ make logs # tail server logs (Docker)
127
+ make restart # restart server after code changes, then restart your MCP client
128
+ ```
129
+
130
+ Pre-commit hooks run `ruff` on staged files. If a commit is blocked, fix the lint issue and commit again — don't skip hooks.
131
+
132
+ ---
133
+
134
+ ## Tracking work
135
+
136
+ Active tasks, bugs, product decisions, and QA gaps are tracked in [GitHub Issues](https://github.com/khuisman/mcp-gee-sweet/issues). Labels:
137
+
138
+ | Label | Used for |
139
+ |---|---|
140
+ | `bug` | Confirmed defects |
141
+ | `decision-needed` | Observed behaviours that need a deliberate product or design decision |
142
+ | `qa` | Missing fixtures, test infrastructure plans, QA gaps |
143
+ | `infrastructure` | Build, CI, publishing, dev tooling |
144
+ | `enhancement` | New features from the roadmap tiers |
145
+
146
+ `docs/roadmap.md` is an orientation doc — feature ideas and historical context. Open an issue when a feature is scheduled to be built.
147
+
148
+ ---
149
+
150
+ ## Pull requests
151
+
152
+ - Open a feature branch before pushing (`feat/`, `fix/`, `docs/` prefixes).
153
+ - New tools require QA test cases and a checklist entry — PRs without them will be asked to add them.
154
+ - Update `docs/design.md` if your change affects scope, tool inclusion criteria, or testing approach.
155
+ - If your change warrants a new ADR, add it to `docs/decisions/` following the existing format.
@@ -0,0 +1,45 @@
1
+ FROM alpine:latest AS base
2
+
3
+ WORKDIR /app
4
+ # Set environment variables for non-interactive installs and minimal locale
5
+ ENV LANG=C.UTF-8
6
+
7
+ # Update and install basic packages for a low resource machine
8
+ RUN apk update && \
9
+ apk upgrade && \
10
+ apk add --no-cache \
11
+ bash \
12
+ curl \
13
+ tini \
14
+ curl \
15
+ coreutils \
16
+ git
17
+
18
+ # Set tini as the init system to handle PID 1
19
+ ENTRYPOINT ["/sbin/tini", "--"]
20
+
21
+ RUN curl -LsSf https://astral.sh/uv/install.sh | sh
22
+
23
+ # Ensure uv is on PATH (installer places it in /root/.local/bin for root)
24
+ ENV PATH="/root/.local/bin:${PATH}"
25
+
26
+ COPY .python-version .
27
+
28
+ RUN uv venv
29
+
30
+ FROM base AS builder
31
+
32
+ COPY . .
33
+
34
+ RUN uv sync
35
+
36
+ # Build the project (produces dist/*.whl)
37
+ RUN uv build
38
+
39
+ FROM base AS runner
40
+
41
+ COPY --from=builder /app/dist/*.whl /app/
42
+
43
+ RUN uv pip install /app/*.whl
44
+
45
+ CMD ["uv", "run", "mcp-gee-sweet", "--transport", "sse"]
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Xing Wu
4
+ Copyright (c) 2026 Kevin Huisman
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,57 @@
1
+ .DEFAULT_GOAL = help
2
+
3
+ .PHONY: build
4
+ build: ## Build container image.
5
+ docker compose build
6
+
7
+ .PHONY: start
8
+ start: ## Spin up container.
9
+ docker compose up -d
10
+
11
+ .PHONY: down
12
+ down: ## Stop and remove container.
13
+ docker compose down
14
+
15
+ .PHONY: restart
16
+ restart: ## Restart container (requires Claude Code restart to reconnect SSE).
17
+ docker compose restart mcp-gee-sweet
18
+
19
+ .PHONY: recreate
20
+ recreate: ## Recreate container from scratch (removes historical logs).
21
+ docker compose up -d --force-recreate
22
+
23
+ .PHONY: logs
24
+ logs: ## Tail container logs.
25
+ docker compose logs -f
26
+
27
+ .PHONY: sh
28
+ sh: ## Open a shell in the container.
29
+ docker compose exec mcp-gee-sweet bash
30
+
31
+ .PHONY: docs
32
+ docs: ## Serve docs locally at http://127.0.0.1:8000 (live reload).
33
+ uv run mkdocs serve
34
+
35
+ .PHONY: install-hooks
36
+ install-hooks: ## Install pre-commit hooks into the local git repo.
37
+ uv run pre-commit install
38
+
39
+ .PHONY: test
40
+ test: ## Run unit tests.
41
+ uv run python -m pytest
42
+
43
+ .PHONY: lint
44
+ lint: ## Run ruff linter and formatter, fixing issues in place.
45
+ uv run ruff check --fix src/
46
+ uv run ruff format src/
47
+
48
+ .PHONY: lint-extra
49
+ lint-extra: ## Run extended ruff rules (bugbear, pyupgrade, simplify) with fixes.
50
+ uv run ruff check --fix --extend-select B,UP,SIM,RUF src/
51
+ uv run ruff format src/
52
+
53
+ # Self-documenting help
54
+ # https://www.freecodecamp.org/news/self-documenting-makefile/
55
+ .PHONY: help
56
+ help: ## Show this help.
57
+ @egrep -h '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-16s\033[0m %s\n", $$1, $$2}'