mcp-gee-sweet 0.7.0.dev67__tar.gz → 0.7.0.dev69__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 (136) hide show
  1. mcp_gee_sweet-0.7.0.dev69/.github/workflows/docs.yml +45 -0
  2. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/CONTRIBUTING.md +5 -5
  3. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/PKG-INFO +9 -9
  4. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/README.md +8 -8
  5. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/configuration.md +2 -2
  6. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/calendar.md +138 -0
  7. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/tools.md +4 -1
  8. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/mkdocs.yml +4 -0
  9. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/pyproject.toml +1 -0
  10. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/scripts/gen_tool_docs.py +3 -0
  11. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/calendar.py +134 -0
  12. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_calendar.py +186 -0
  13. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/uv.lock +28 -0
  14. mcp_gee_sweet-0.7.0.dev67/.github/workflows/docs.yml +0 -30
  15. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.claude/commands/prep-for-pr.md +0 -0
  16. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.dockerignore +0 -0
  17. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  18. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  19. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  20. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/dependabot.yml +0 -0
  21. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/workflows/ci.yml +0 -0
  22. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/workflows/publish-dev.yml +0 -0
  23. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/workflows/release.yml +0 -0
  24. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.gitignore +0 -0
  25. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.pre-commit-config.yaml +0 -0
  26. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.python-version +0 -0
  27. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/CHANGELOG.md +0 -0
  28. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/CLAUDE.md +0 -0
  29. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/CODE_OF_CONDUCT.md +0 -0
  30. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/Dockerfile +0 -0
  31. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/LICENSE +0 -0
  32. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/Makefile +0 -0
  33. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/SECURITY.md +0 -0
  34. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docker-compose.yml +0 -0
  35. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/auth.md +0 -0
  36. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/client-setup.md +0 -0
  37. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-chart-theming.md +0 -0
  38. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-composite-tools.md +0 -0
  39. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-docs-formatting.md +0 -0
  40. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-fork.md +0 -0
  41. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-grid-data-size-cap.md +0 -0
  42. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-publishing.md +0 -0
  43. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-response-size-cap-generalization.md +0 -0
  44. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-testing.md +0 -0
  45. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/index.md +0 -0
  46. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design/docs-ast-pipeline.md +0 -0
  47. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design/effectiveformat-spike.md +0 -0
  48. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design/index.md +0 -0
  49. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design/markdown-support.md +0 -0
  50. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design/phase3-theme-system.md +0 -0
  51. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design.md +0 -0
  52. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/index.md +0 -0
  53. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/known-limitations.md +0 -0
  54. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/notes-read.md +0 -0
  55. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/README.md +0 -0
  56. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/fixtures/tc-d195-create-doc.md +0 -0
  57. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/fixtures/tc-d196-create-doc.html +0 -0
  58. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/fixtures/tc-d213-dollar-escape.md +0 -0
  59. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/fixtures/tc-d226-heading-table.md +0 -0
  60. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/fixtures.template.md +0 -0
  61. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/operations.yaml +0 -0
  62. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/playwright_oauth.md +0 -0
  63. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/.gitkeep +0 -0
  64. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-02.md +0 -0
  65. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-14.md +0 -0
  66. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-17.md +0 -0
  67. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-18.md +0 -0
  68. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-21-drive-discovery.md +0 -0
  69. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-21-sheets-delete-clear.md +0 -0
  70. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-28.md +0 -0
  71. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-07-04-docs.md +0 -0
  72. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-07-04-drive-smoke.md +0 -0
  73. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-07-04-infra.md +0 -0
  74. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-07-04-sheets_read.md +0 -0
  75. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-07-04.md +0 -0
  76. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/retro-v0.8.0.md +0 -0
  77. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/run.md +0 -0
  78. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/runs/README.md +0 -0
  79. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/runs/v0.8.0.md +0 -0
  80. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/runs/v0.8.1.md +0 -0
  81. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/setup.md +0 -0
  82. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/docs.md +0 -0
  83. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/drive.md +0 -0
  84. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/infra.md +0 -0
  85. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/sheets_charts.md +0 -0
  86. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/sheets_mgmt.md +0 -0
  87. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/sheets_read.md +0 -0
  88. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/sheets_write.md +0 -0
  89. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa-checklist.md +0 -0
  90. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/roadmap.md +0 -0
  91. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/scripts/oauth_setup.py +0 -0
  92. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/.env.template +0 -0
  93. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/__init__.py +0 -0
  94. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/auth.py +0 -0
  95. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/cache.py +0 -0
  96. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/server.py +0 -0
  97. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/__init__.py +0 -0
  98. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/cache.py +0 -0
  99. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/__init__.py +0 -0
  100. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/ast.py +0 -0
  101. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/content.py +0 -0
  102. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/emitter.py +0 -0
  103. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/html_parser.py +0 -0
  104. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/layout.py +0 -0
  105. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/style.py +0 -0
  106. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/tables.py +0 -0
  107. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/drive/__init__.py +0 -0
  108. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/drive/activity.py +0 -0
  109. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/drive/files.py +0 -0
  110. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/drive/sharing.py +0 -0
  111. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/drive/transfer.py +0 -0
  112. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/response_limits.py +0 -0
  113. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/sheets/__init__.py +0 -0
  114. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/sheets/data.py +0 -0
  115. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/sheets/helpers.py +0 -0
  116. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/sheets/structure.py +0 -0
  117. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/__init__.py +0 -0
  118. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/drive/__init__.py +0 -0
  119. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/drive/test_activity.py +0 -0
  120. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/drive/test_files.py +0 -0
  121. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/drive/test_sharing.py +0 -0
  122. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/drive/test_transfer.py +0 -0
  123. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/sheets/__init__.py +0 -0
  124. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/sheets/test_data.py +0 -0
  125. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/sheets/test_helpers.py +0 -0
  126. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/sheets/test_structure.py +0 -0
  127. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_auth.py +0 -0
  128. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_cache.py +0 -0
  129. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_docs_content.py +0 -0
  130. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_docs_core.py +0 -0
  131. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_docs_layout.py +0 -0
  132. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_docs_style.py +0 -0
  133. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_docs_tables.py +0 -0
  134. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_gen_tool_docs.py +0 -0
  135. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_response_limits.py +0 -0
  136. {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_server.py +0 -0
@@ -0,0 +1,45 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: ["main", "develop"]
6
+
7
+ permissions:
8
+ contents: write # needed for mike 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@v7
17
+ with:
18
+ fetch-depth: 0 # full history so mike can see existing gh-pages versions
19
+
20
+ - name: Install uv
21
+ uses: astral-sh/setup-uv@v8.2.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: Configure git identity
30
+ run: |
31
+ git config user.name "github-actions[bot]"
32
+ git config user.email "github-actions[bot]@users.noreply.github.com"
33
+
34
+ - name: Fetch existing gh-pages
35
+ run: git fetch origin gh-pages --depth=1 || true
36
+
37
+ - name: Deploy docs (main -> latest)
38
+ if: github.ref == 'refs/heads/main'
39
+ run: |
40
+ uv run mike deploy --push --update-aliases main latest
41
+ uv run mike set-default --push latest
42
+
43
+ - name: Deploy docs (develop)
44
+ if: github.ref == 'refs/heads/develop'
45
+ run: uv run mike deploy --push develop
@@ -29,9 +29,9 @@ Two ways to supply configuration — pick whichever fits how you're running the
29
29
  ```bash
30
30
  cp src/mcp_gee_sweet/.env.template src/mcp_gee_sweet/.env
31
31
  ```
32
- - **Your MCP client's config directly** — if you're pointing your client at `uv run --directory /path/to/mcp-gee-sweet mcp-gee-sweet` (the README's stdio quick-start), you can set env vars in the client's `env` block instead, the same way the [MCP client config](https://khuisman.github.io/mcp-gee-sweet/client-setup/) examples do. Many contributors find this a better day-to-day experience than maintaining a separate `.env` file — client config takes precedence over `.env` either way.
32
+ - **Your MCP client's config directly** — if you're pointing your client at `uv run --directory /path/to/mcp-gee-sweet mcp-gee-sweet` (the README's stdio quick-start), you can set env vars in the client's `env` block instead, the same way the [MCP client config](https://khuisman.github.io/mcp-gee-sweet/latest/client-setup/) examples do. Many contributors find this a better day-to-day experience than maintaining a separate `.env` file — client config takes precedence over `.env` either way.
33
33
 
34
- At minimum you need one auth method and a Drive folder. Full details on all four methods (including GCP setup steps) are in [Authentication](https://khuisman.github.io/mcp-gee-sweet/auth/); the full environment variable reference is in [Configuration](https://khuisman.github.io/mcp-gee-sweet/configuration/).
34
+ At minimum you need one auth method and a Drive folder. Full details on all four methods (including GCP setup steps) are in [Authentication](https://khuisman.github.io/mcp-gee-sweet/latest/auth/); the full environment variable reference is in [Configuration](https://khuisman.github.io/mcp-gee-sweet/latest/configuration/).
35
35
 
36
36
  #### Choosing an auth method
37
37
 
@@ -65,7 +65,7 @@ The assistant will:
65
65
  - Populate them with known fixture data
66
66
  - Write `TEST_*` IDs to your `.env`
67
67
 
68
- **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 [Authentication](https://khuisman.github.io/mcp-gee-sweet/auth/) for the sharing steps.
68
+ **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 [Authentication](https://khuisman.github.io/mcp-gee-sweet/latest/auth/) for the sharing steps.
69
69
 
70
70
  ### 4. Enable observability
71
71
 
@@ -87,7 +87,7 @@ Every tool call emits one line to the access log:
87
87
  - `make logs` — tail Docker container logs directly (SSE; `DEBUG_LEVEL=DEBUG` is already the Docker Compose default, no `.env` change needed)
88
88
  - `make access-logs` — tail `ACCESS_LOG_FILE` only, if set
89
89
 
90
- Full details on log levels and file routing: [Configuration → Logging](https://khuisman.github.io/mcp-gee-sweet/configuration/).
90
+ Full details on log levels and file routing: [Configuration → Logging](https://khuisman.github.io/mcp-gee-sweet/latest/configuration/).
91
91
 
92
92
  ### 5. Run the server
93
93
 
@@ -143,7 +143,7 @@ Every new tool must have at least:
143
143
  - The tool included in the `docs/qa-checklist.md` attestation
144
144
  - The tool's happy-path TC added to the smoke suite in `docs/qa/runs/README.md`
145
145
 
146
- See [Design Principles](https://khuisman.github.io/mcp-gee-sweet/design/) for the tool inclusion criteria and composite tool rules.
146
+ See [Design Principles](https://khuisman.github.io/mcp-gee-sweet/latest/design/) for the tool inclusion criteria and composite tool rules.
147
147
 
148
148
  ---
149
149
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-gee-sweet
3
- Version: 0.7.0.dev67
3
+ Version: 0.7.0.dev69
4
4
  Summary: MCP server for Google Workspace — Sheets, Drive, Docs, and Calendar. 60+ tools for AI clients.
5
5
  Project-URL: Homepage, https://github.com/khuisman/mcp-gee-sweet
6
6
  Project-URL: Bug Tracker, https://github.com/khuisman/mcp-gee-sweet/issues
@@ -83,7 +83,7 @@ The server tries auth methods in a waterfall by default, OAuth first — it auth
83
83
  export CREDENTIALS_PATH="/path/to/credentials.json"
84
84
  ```
85
85
 
86
- Service accounts (recommended for headless server deployments — see Option B above), base64 credential injection, and Application Default Credentials are also supported. See [Authentication](https://khuisman.github.io/mcp-gee-sweet/auth/) for all options.
86
+ Service accounts (recommended for headless server deployments — see Option B above), base64 credential injection, and Application Default Credentials are also supported. See [Authentication](https://khuisman.github.io/mcp-gee-sweet/latest/auth/) for all options.
87
87
 
88
88
  ---
89
89
 
@@ -116,18 +116,18 @@ Service accounts (recommended for headless server deployments — see Option B a
116
116
  }
117
117
  ```
118
118
 
119
- See [Client Setup](https://khuisman.github.io/mcp-gee-sweet/client-setup/) for more options including tool filtering.
119
+ See [Client Setup](https://khuisman.github.io/mcp-gee-sweet/latest/client-setup/) for more options including tool filtering.
120
120
 
121
121
  ---
122
122
 
123
123
  ## Docs
124
124
 
125
- - [Tools](https://khuisman.github.io/mcp-gee-sweet/tools/) — full tool reference (84 tools)
126
- - [Authentication](https://khuisman.github.io/mcp-gee-sweet/auth/) — all four auth methods
127
- - [Configuration](https://khuisman.github.io/mcp-gee-sweet/configuration/) — env vars, caching, tool filtering
128
- - [Client Setup](https://khuisman.github.io/mcp-gee-sweet/client-setup/) — MCP client config examples
129
- - [Design Principles](https://khuisman.github.io/mcp-gee-sweet/design/) — tool inclusion policy, composite tool decisions
130
- - [Roadmap](https://khuisman.github.io/mcp-gee-sweet/roadmap/) — planned features and known gaps
125
+ - [Tools](https://khuisman.github.io/mcp-gee-sweet/latest/tools/) — full tool reference (84 tools)
126
+ - [Authentication](https://khuisman.github.io/mcp-gee-sweet/latest/auth/) — all four auth methods
127
+ - [Configuration](https://khuisman.github.io/mcp-gee-sweet/latest/configuration/) — env vars, caching, tool filtering
128
+ - [Client Setup](https://khuisman.github.io/mcp-gee-sweet/latest/client-setup/) — MCP client config examples
129
+ - [Design Principles](https://khuisman.github.io/mcp-gee-sweet/latest/design/) — tool inclusion policy, composite tool decisions
130
+ - [Roadmap](https://khuisman.github.io/mcp-gee-sweet/latest/roadmap/) — planned features and known gaps
131
131
 
132
132
  ---
133
133
 
@@ -61,7 +61,7 @@ The server tries auth methods in a waterfall by default, OAuth first — it auth
61
61
  export CREDENTIALS_PATH="/path/to/credentials.json"
62
62
  ```
63
63
 
64
- Service accounts (recommended for headless server deployments — see Option B above), base64 credential injection, and Application Default Credentials are also supported. See [Authentication](https://khuisman.github.io/mcp-gee-sweet/auth/) for all options.
64
+ Service accounts (recommended for headless server deployments — see Option B above), base64 credential injection, and Application Default Credentials are also supported. See [Authentication](https://khuisman.github.io/mcp-gee-sweet/latest/auth/) for all options.
65
65
 
66
66
  ---
67
67
 
@@ -94,18 +94,18 @@ Service accounts (recommended for headless server deployments — see Option B a
94
94
  }
95
95
  ```
96
96
 
97
- See [Client Setup](https://khuisman.github.io/mcp-gee-sweet/client-setup/) for more options including tool filtering.
97
+ See [Client Setup](https://khuisman.github.io/mcp-gee-sweet/latest/client-setup/) for more options including tool filtering.
98
98
 
99
99
  ---
100
100
 
101
101
  ## Docs
102
102
 
103
- - [Tools](https://khuisman.github.io/mcp-gee-sweet/tools/) — full tool reference (84 tools)
104
- - [Authentication](https://khuisman.github.io/mcp-gee-sweet/auth/) — all four auth methods
105
- - [Configuration](https://khuisman.github.io/mcp-gee-sweet/configuration/) — env vars, caching, tool filtering
106
- - [Client Setup](https://khuisman.github.io/mcp-gee-sweet/client-setup/) — MCP client config examples
107
- - [Design Principles](https://khuisman.github.io/mcp-gee-sweet/design/) — tool inclusion policy, composite tool decisions
108
- - [Roadmap](https://khuisman.github.io/mcp-gee-sweet/roadmap/) — planned features and known gaps
103
+ - [Tools](https://khuisman.github.io/mcp-gee-sweet/latest/tools/) — full tool reference (84 tools)
104
+ - [Authentication](https://khuisman.github.io/mcp-gee-sweet/latest/auth/) — all four auth methods
105
+ - [Configuration](https://khuisman.github.io/mcp-gee-sweet/latest/configuration/) — env vars, caching, tool filtering
106
+ - [Client Setup](https://khuisman.github.io/mcp-gee-sweet/latest/client-setup/) — MCP client config examples
107
+ - [Design Principles](https://khuisman.github.io/mcp-gee-sweet/latest/design/) — tool inclusion policy, composite tool decisions
108
+ - [Roadmap](https://khuisman.github.io/mcp-gee-sweet/latest/roadmap/) — planned features and known gaps
109
109
 
110
110
  ---
111
111
 
@@ -69,7 +69,7 @@ Access logs are emitted at `INFO` level — they appear when `DEBUG_LEVEL` is `D
69
69
 
70
70
  <!-- Auto-generated by `scripts/gen_tool_docs.py` — do not edit by hand, your changes will be overwritten on the next commit. -->
71
71
 
72
- By default all 84 tools are registered. Use `ENABLED_TOOLS` (or `--include-tools` on the CLI) to restrict the server to exactly the tools you need. This reduces the AI's context window cost — each registered tool is a name the model must reason about on every call.
72
+ By default all 87 tools are registered. Use `ENABLED_TOOLS` (or `--include-tools` on the CLI) to restrict the server to exactly the tools you need. This reduces the AI's context window cost — each registered tool is a name the model must reason about on every call.
73
73
 
74
74
  ```bash
75
75
  # Environment variable
@@ -100,7 +100,7 @@ create_doc,get_doc_content,get_doc_structure,write_doc_content,insert_doc_text,i
100
100
 
101
101
  **Calendar only:**
102
102
  ```
103
- list_calendars,get_calendar,list_events,get_event,create_event,update_event,delete_event,find_free_slots
103
+ list_calendars,get_calendar,create_calendar,update_calendar,delete_calendar,list_events,get_event,create_event,update_event,delete_event,find_free_slots
104
104
  ```
105
105
 
106
106
  See [Tools](tools.md) for the full list of tool names.
@@ -105,6 +105,144 @@ Fixtures: see [`docs/qa/setup.md`](../setup.md). Substitute your `{CALENDAR_ID}`
105
105
 
106
106
  ---
107
107
 
108
+ ## `create_calendar`
109
+
110
+ ### TC-CAL44: Create a secondary calendar ⚠️ destructive
111
+
112
+ **Prompt**
113
+ > "Create a new calendar called 'mcp-gee-sweet-qa-lifecycle-test' with description 'QA scratch calendar' and timezone 'America/Los_Angeles'"
114
+
115
+ **Checks**
116
+ - Returns `id`, `summary`, `description`, `time_zone`
117
+ - `summary` is `mcp-gee-sweet-qa-lifecycle-test`
118
+ - `time_zone` is `America/Los_Angeles`
119
+ - The new calendar appears in a follow-up `list_calendars` call (cache invalidated)
120
+
121
+ **Result (2026-07-05) ✅** — Created via OAuth; response had `summary`, `description`, and `time_zone: "America/Los_Angeles"` exactly as requested. Confirmed present in a follow-up `list_calendars` call.
122
+
123
+ ---
124
+
125
+ ### TC-CAL45: Create with only summary
126
+
127
+ **Prompt**
128
+ > "Create a new calendar called 'mcp-gee-sweet-qa-minimal'"
129
+
130
+ **Checks**
131
+ - Succeeds with only `summary` provided
132
+ - `description` is `null`/absent
133
+ - `time_zone` reflects the account default
134
+
135
+ **Result (2026-07-05) ✅** — Created with only `summary` provided. `description: null`. `time_zone: "UTC"` (account default rather than the creator's local timezone — noted for documentation purposes). Confirmed present in a follow-up `list_calendars` call.
136
+
137
+ ---
138
+
139
+ ## `update_calendar`
140
+
141
+ ### TC-CAL46: Rename and change timezone ⚠️ destructive
142
+
143
+ **Setup:** use the calendar created in TC-CAL44
144
+
145
+ **Prompt**
146
+ > "Update calendar 'mcp-gee-sweet-qa-lifecycle-test' — rename it to 'mcp-gee-sweet-qa-renamed' and set its timezone to 'America/New_York'"
147
+
148
+ **Checks**
149
+ - `summary` is `mcp-gee-sweet-qa-renamed`
150
+ - `time_zone` is `America/New_York`
151
+ - `description` unchanged from TC-CAL44
152
+ - `get_calendar` on the same ID reflects the new values
153
+
154
+ **Result (2026-07-05) ✅** — Patched with `summary: "mcp-gee-sweet-qa-renamed"` and `timezone: "America/New_York"`. Response reflected both changes; `description` unchanged from TC-CAL44 (`"QA scratch calendar"`).
155
+
156
+ ---
157
+
158
+ ### TC-CAL47: Change color only ⚠️ destructive
159
+
160
+ **Setup:** use the calendar from TC-CAL44/46
161
+
162
+ **Prompt**
163
+ > "Change the color of calendar 'mcp-gee-sweet-qa-renamed' to color ID '5'"
164
+
165
+ **Checks**
166
+ - `color_id` in the response is `5`
167
+ - `summary`/`description`/`time_zone` unchanged (verify with `get_calendar`)
168
+ - Confirms the color patch goes through `calendarList().patch()`, not `calendars().patch()`
169
+
170
+ **Result (2026-07-05) ✅** — Patched `color_id="5"` only (no summary/description/timezone). Response had `color_id: "5"` with `summary`, `description`, `time_zone` all unchanged from TC-CAL46 — confirms the tool fell back to `calendars().get()` for the base fields and routed color through `calendarList().patch()`.
171
+
172
+ ---
173
+
174
+ ### TC-CAL48: No fields provided
175
+
176
+ **Prompt**
177
+ > "Update calendar {CALENDAR_ID} with no changes — just fetch its current state through update_calendar"
178
+
179
+ **Checks**
180
+ - Returns current calendar metadata unchanged
181
+ - `color_id` is `null` (no color patch attempted)
182
+ - No API error
183
+
184
+ **Result (2026-07-05) ✅** — Called with `calendar_id="primary"` and no other fields. Returned the account's real primary calendar summary/timezone unchanged, `color_id: null`. Confirms the no-op path uses `calendars().get()` without issuing any patch.
185
+
186
+ ---
187
+
188
+ ### TC-CAL49: Non-existent calendar ID
189
+
190
+ **Prompt**
191
+ > "Update calendar 'totally-invalid-cal-id@example.com' — rename it to 'Nope'"
192
+
193
+ **Checks**
194
+ - Returns `{"error": "..."}` — not a top-level exception
195
+
196
+ **Result (2026-07-05) ✅** — Returned `{"error": "<HttpError 404 ... 'reason': 'notFound' ...>"}`. No exception raised.
197
+
198
+ ---
199
+
200
+ ## `delete_calendar`
201
+
202
+ ### TC-CAL50: Delete a calendar ⚠️ destructive
203
+
204
+ **Setup:** use the calendar created in TC-CAL44 (after TC-CAL46/47 updates)
205
+
206
+ **Prompt**
207
+ > "Delete the calendar 'mcp-gee-sweet-qa-renamed'"
208
+
209
+ **Checks**
210
+ - Returns `{"calendar_id": "...", "action": "deleted"}`
211
+ - Calendar no longer appears in a follow-up `list_calendars` call
212
+ - `get_calendar` on the deleted ID returns an error
213
+
214
+ **Result (2026-07-05) ✅** — Returned `{"calendar_id": "...", "action": "deleted"}`. Confirmed absent from a follow-up `list_calendars` call. `get_calendar` on the deleted ID returned a 404 `notFound` error.
215
+
216
+ ---
217
+
218
+ ### TC-CAL51: Delete the minimal test calendar ⚠️ destructive
219
+
220
+ **Setup:** use the calendar created in TC-CAL45
221
+
222
+ **Prompt**
223
+ > "Delete the calendar 'mcp-gee-sweet-qa-minimal'"
224
+
225
+ **Checks**
226
+ - Returns `{"calendar_id": "...", "action": "deleted"}`
227
+ - Cleans up the fixture so it doesn't linger in the account's calendar list
228
+
229
+ **Result (2026-07-05) ✅** — Returned `{"calendar_id": "...", "action": "deleted"}`. Confirmed removed from the account's `list_calendars` output alongside TC-CAL50's cleanup.
230
+
231
+ ---
232
+
233
+ ### TC-CAL52: Non-existent calendar ID
234
+
235
+ **Prompt**
236
+ > "Delete the calendar 'totally-invalid-cal-id@example.com'"
237
+
238
+ **Checks**
239
+ - Returns `{"error": "..."}` — not a top-level exception
240
+ - No side effects
241
+
242
+ **Result (2026-07-05) ✅** — Returned `{"error": "<HttpError 404 ... 'reason': 'notFound' ...>"}`. No side effects.
243
+
244
+ ---
245
+
108
246
  ## `list_events`
109
247
 
110
248
  ### TC-CAL09: No time filters — upcoming events
@@ -2,7 +2,7 @@
2
2
 
3
3
  <!-- Auto-generated by `scripts/gen_tool_docs.py` — do not edit by hand, your changes will be overwritten on the next commit. -->
4
4
 
5
- 84 tools. All tool names are lowercase with underscores — use these exact strings with `ENABLED_TOOLS` or `--include-tools`.
5
+ 87 tools. All tool names are lowercase with underscores — use these exact strings with `ENABLED_TOOLS` or `--include-tools`.
6
6
 
7
7
  ## Sheets — data
8
8
 
@@ -141,6 +141,9 @@ Requires the `drive.activity.readonly` scope; uses the Drive Activity API v2.
141
141
  |---|---|---|
142
142
  | `list_calendars` | List all calendars accessible to the authenticated user. | — |
143
143
  | `get_calendar` | Fetch metadata for a single calendar. | `calendar_id` |
144
+ | `create_calendar` | Create a new secondary calendar owned by the authenticated user. | `summary`, `description?`, `timezone?` |
145
+ | `update_calendar` | Update fields on an existing calendar using patch semantics. Only the fields you provide are changed; omitted fields are left as-is. | `calendar_id`, `summary?`, `description?`, `timezone?`, `color_id?` |
146
+ | `delete_calendar` | Permanently delete a calendar. For calendars you own, this deletes the calendar entirely for all users it is shared with — use with caution. To only stop seeing a calendar in your own list, use remove_calendar_from_list instead. | `calendar_id` |
144
147
  | `list_events` | List events in a calendar. | `calendar_id`, `time_min?`, `time_max?`, `query?`, `max_results?`, `expand_recurring?` |
145
148
  | `get_event` | Fetch a single event by calendar ID and event ID. | `calendar_id`, `event_id` |
146
149
  | `create_event` | Create a new event in a calendar. | `calendar_id`, `summary`, `start`, `end`, `description?`, `location?`, `attendees?`, `timezone?`, `recurrence?` |
@@ -33,6 +33,10 @@ markdown_extensions:
33
33
  anchor_linenums: true
34
34
  - pymdownx.superfences
35
35
 
36
+ extra:
37
+ version:
38
+ provider: mike
39
+
36
40
  nav:
37
41
  - Home: index.md
38
42
  - Reference:
@@ -58,6 +58,7 @@ ignore = ["E501"]
58
58
  dev = [
59
59
  "mkdocs>=1.6.0",
60
60
  "mkdocs-material>=9.5.0",
61
+ "mike>=2.1.0",
61
62
  "pre-commit>=4.6.0",
62
63
  "pytest>=8.0.0",
63
64
  "pytest-cov>=6.0.0",
@@ -215,6 +215,9 @@ SUBSETS = [
215
215
  [
216
216
  "list_calendars",
217
217
  "get_calendar",
218
+ "create_calendar",
219
+ "update_calendar",
220
+ "delete_calendar",
218
221
  "list_events",
219
222
  "get_event",
220
223
  "create_event",
@@ -73,6 +73,140 @@ def register(tool):
73
73
  cache.store(calendar_id, result)
74
74
  return result
75
75
 
76
+ @tool(annotations=ToolAnnotations(title="Create Calendar", destructiveHint=True))
77
+ def create_calendar(
78
+ summary: str,
79
+ description: str | None = None,
80
+ timezone: str | None = None,
81
+ ctx: Context = None,
82
+ ) -> dict[str, Any]:
83
+ """
84
+ Create a new secondary calendar owned by the authenticated user.
85
+
86
+ Args:
87
+ summary: Calendar title.
88
+ description: Optional calendar description.
89
+ timezone: IANA timezone name (e.g. 'America/Los_Angeles'). Defaults to
90
+ the account's timezone if omitted.
91
+
92
+ Returns:
93
+ Created calendar: id, summary, description, time_zone.
94
+ """
95
+ lc = ctx.request_context.lifespan_context
96
+
97
+ body: dict[str, Any] = {"summary": summary}
98
+ if description:
99
+ body["description"] = description
100
+ if timezone:
101
+ body["timeZone"] = timezone
102
+
103
+ try:
104
+ c = lc.calendar_service.calendars().insert(body=body).execute()
105
+ except Exception as e:
106
+ return {"error": str(e)}
107
+
108
+ lc.calendar_cache.mark_dirty(c["id"])
109
+ logger.debug("Created calendar %s", c["id"])
110
+ return {
111
+ "id": c["id"],
112
+ "summary": c.get("summary", ""),
113
+ "description": c.get("description"),
114
+ "time_zone": c.get("timeZone"),
115
+ }
116
+
117
+ @tool(annotations=ToolAnnotations(title="Update Calendar", destructiveHint=True))
118
+ def update_calendar(
119
+ calendar_id: str,
120
+ summary: str | None = None,
121
+ description: str | None = None,
122
+ timezone: str | None = None,
123
+ color_id: str | None = None,
124
+ ctx: Context = None,
125
+ ) -> dict[str, Any]:
126
+ """
127
+ Update fields on an existing calendar using patch semantics. Only the
128
+ fields you provide are changed; omitted fields are left as-is.
129
+
130
+ Note: color_id is set via the authenticated user's calendar list entry
131
+ (calendarList().patch()), not the calendar resource itself — it is a
132
+ per-user setting, not a property of the calendar shared with others.
133
+
134
+ Args:
135
+ calendar_id: The calendar ID, or 'primary'.
136
+ summary: New calendar title.
137
+ description: New calendar description.
138
+ timezone: New IANA timezone name (e.g. 'America/Los_Angeles').
139
+ color_id: New color ID from the palette returned by the Calendar API's
140
+ colors().get() endpoint (predefined IDs, typically '1'-'24').
141
+
142
+ Returns:
143
+ Updated calendar: id, summary, description, time_zone, color_id.
144
+ """
145
+ lc = ctx.request_context.lifespan_context
146
+
147
+ patch: dict[str, Any] = {}
148
+ if summary is not None:
149
+ patch["summary"] = summary
150
+ if description is not None:
151
+ patch["description"] = description
152
+ if timezone is not None:
153
+ patch["timeZone"] = timezone
154
+
155
+ try:
156
+ if patch:
157
+ c = (
158
+ lc.calendar_service.calendars()
159
+ .patch(calendarId=calendar_id, body=patch)
160
+ .execute()
161
+ )
162
+ else:
163
+ c = lc.calendar_service.calendars().get(calendarId=calendar_id).execute()
164
+
165
+ result_color_id = None
166
+ if color_id is not None:
167
+ list_entry = (
168
+ lc.calendar_service.calendarList()
169
+ .patch(calendarId=calendar_id, body={"colorId": color_id})
170
+ .execute()
171
+ )
172
+ result_color_id = list_entry.get("colorId")
173
+ except Exception as e:
174
+ return {"error": str(e)}
175
+
176
+ lc.calendar_cache.mark_dirty(calendar_id)
177
+ logger.debug("Updated calendar %s", calendar_id)
178
+ return {
179
+ "id": c.get("id", calendar_id),
180
+ "summary": c.get("summary", ""),
181
+ "description": c.get("description"),
182
+ "time_zone": c.get("timeZone"),
183
+ "color_id": result_color_id,
184
+ }
185
+
186
+ @tool(annotations=ToolAnnotations(title="Delete Calendar", destructiveHint=True))
187
+ def delete_calendar(calendar_id: str, ctx: Context = None) -> dict[str, Any]:
188
+ """
189
+ Permanently delete a calendar. For calendars you own, this deletes the
190
+ calendar entirely for all users it is shared with — use with caution.
191
+ To only stop seeing a calendar in your own list, use
192
+ remove_calendar_from_list instead.
193
+
194
+ Args:
195
+ calendar_id: The calendar ID to delete.
196
+
197
+ Returns:
198
+ Confirmation with calendar_id and action 'deleted'.
199
+ """
200
+ lc = ctx.request_context.lifespan_context
201
+ try:
202
+ lc.calendar_service.calendars().delete(calendarId=calendar_id).execute()
203
+ except Exception as e:
204
+ return {"error": str(e)}
205
+
206
+ lc.calendar_cache.mark_dirty(calendar_id)
207
+ logger.debug("Deleted calendar %s", calendar_id)
208
+ return {"calendar_id": calendar_id, "action": "deleted"}
209
+
76
210
  @tool(annotations=ToolAnnotations(title="List Events", readOnlyHint=True))
77
211
  def list_events(
78
212
  calendar_id: str,