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.
- mcp_gee_sweet-0.7.0.dev69/.github/workflows/docs.yml +45 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/CONTRIBUTING.md +5 -5
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/PKG-INFO +9 -9
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/README.md +8 -8
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/configuration.md +2 -2
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/calendar.md +138 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/tools.md +4 -1
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/mkdocs.yml +4 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/pyproject.toml +1 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/scripts/gen_tool_docs.py +3 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/calendar.py +134 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_calendar.py +186 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/uv.lock +28 -0
- mcp_gee_sweet-0.7.0.dev67/.github/workflows/docs.yml +0 -30
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.claude/commands/prep-for-pr.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.dockerignore +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/dependabot.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/workflows/ci.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/workflows/publish-dev.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.github/workflows/release.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.gitignore +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.pre-commit-config.yaml +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/.python-version +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/CHANGELOG.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/CLAUDE.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/CODE_OF_CONDUCT.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/Dockerfile +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/LICENSE +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/Makefile +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/SECURITY.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docker-compose.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/auth.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/client-setup.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-chart-theming.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-composite-tools.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-docs-formatting.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-fork.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-grid-data-size-cap.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-publishing.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-response-size-cap-generalization.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/decision-testing.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/decisions/index.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design/docs-ast-pipeline.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design/effectiveformat-spike.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design/index.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design/markdown-support.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design/phase3-theme-system.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/design.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/index.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/known-limitations.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/notes-read.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/README.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/fixtures/tc-d195-create-doc.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/fixtures/tc-d196-create-doc.html +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/fixtures/tc-d213-dollar-escape.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/fixtures/tc-d226-heading-table.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/fixtures.template.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/operations.yaml +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/playwright_oauth.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/.gitkeep +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-02.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-14.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-17.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-18.md +0 -0
- {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
- {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
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-06-28.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-07-04-docs.md +0 -0
- {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
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-07-04-infra.md +0 -0
- {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
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/results/2026-07-04.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/retro-v0.8.0.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/run.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/runs/README.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/runs/v0.8.0.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/runs/v0.8.1.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/setup.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/docs.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/drive.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/infra.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/sheets_charts.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/sheets_mgmt.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/sheets_read.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa/tests/sheets_write.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/qa-checklist.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/docs/roadmap.md +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/scripts/oauth_setup.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/.env.template +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/auth.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/cache.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/server.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/cache.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/ast.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/content.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/emitter.py +0 -0
- {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
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/layout.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/style.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/docs/tables.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/drive/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/drive/activity.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/drive/files.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/drive/sharing.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/drive/transfer.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/response_limits.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/sheets/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/sheets/data.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/sheets/helpers.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/src/mcp_gee_sweet/tools/sheets/structure.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/drive/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/drive/test_activity.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/drive/test_files.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/drive/test_sharing.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/drive/test_transfer.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/sheets/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/sheets/test_data.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/sheets/test_helpers.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/sheets/test_structure.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_auth.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_cache.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_docs_content.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_docs_core.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_docs_layout.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_docs_style.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_docs_tables.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_gen_tool_docs.py +0 -0
- {mcp_gee_sweet-0.7.0.dev67 → mcp_gee_sweet-0.7.0.dev69}/tests/test_response_limits.py +0 -0
- {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.
|
|
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
|
|
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
|
-
|
|
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?` |
|
|
@@ -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,
|