{"_id":"@demitycho/google-workspace-mcp","_rev":"3-707e6becce817bd69cc853a36025c481","name":"@demitycho/google-workspace-mcp","dist-tags":{"latest":"3.3.0"},"versions":{"3.2.0":{"name":"@demitycho/google-workspace-mcp","version":"3.2.0","keywords":["mcp","google","drive","sheets","gmail","calendar","tasks","claude","ai"],"license":"MIT","_id":"@demitycho/google-workspace-mcp@3.2.0","maintainers":[{"name":"demitycho","email":"tanweihao94@gmail.com"}],"bin":{"google-workspace-mcp":"dist/index.js"},"dist":{"shasum":"59d09ce61ea77cd9788859fa3f5626d17a7ccd11","tarball":"https://registry.npmjs.org/@demitycho/google-workspace-mcp/-/google-workspace-mcp-3.2.0.tgz","fileCount":24,"integrity":"sha512-4M3kIA0xmWel7nFoBo1DxDXlkzI7kenI+hZOyqSOBamNjAeA9GqySGCGiqVZUdKqmB16JmRr+dvxht1hGtWIWQ==","signatures":[{"sig":"MEYCIQDdgWbqKnC8G4wWvBrAs4UfHSfcnSKTTFjJuIKRVLTsoAIhALVp3vILWHd6Rw6QTOKqcx2XLlo/K6hw6Enqy+pbuHqy","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":172528},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"c9b0a50888474513a04e43f6238fb7aecaf37144","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"demitycho","email":"tanweihao94@gmail.com"},"_npmVersion":"11.6.2","description":"MCP server for Google Workspace (Drive, Sheets, Gmail, Calendar, Tasks) with OAuth and service account auth","directories":{},"_nodeVersion":"24.11.1","dependencies":{"zod":"^3.24.2","googleapis":"^144.0.0","@modelcontextprotocol/sdk":"^1.6.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/google-workspace-mcp_3.2.0_1777617092106_0.8973376017044299","host":"s3://npm-registry-packages-npm-production"}},"3.2.1":{"name":"@demitycho/google-workspace-mcp","version":"3.2.1","keywords":["mcp","google","drive","sheets","gmail","calendar","tasks","claude","ai"],"license":"MIT","_id":"@demitycho/google-workspace-mcp@3.2.1","maintainers":[{"name":"demitycho","email":"tanweihao94@gmail.com"}],"bin":{"google-workspace-mcp":"dist/index.js"},"dist":{"shasum":"85982bda414975aa5531c245d141305e7209d5e6","tarball":"https://registry.npmjs.org/@demitycho/google-workspace-mcp/-/google-workspace-mcp-3.2.1.tgz","fileCount":26,"integrity":"sha512-IXmTFYpHrZ5v1hA7GY0ZtOyro2kvM+k1EMyXp+vuoCvUWD1wqmD/v50y7Ed3HAyZNN2nnWNgkGYV2s5NiV5EAw==","signatures":[{"sig":"MEQCIH12sMnps6h9HmugnmQ1OmXW0//8A12CQZT7vGkXQPK+AiAmPKJMBOPjgpVv0CMS9zyA8rdKK0ox2yItqinZnz7WuA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":175358},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"gitHead":"bcb178d23e233ea4c00a0f872de94989e2a442e3","scripts":{"dev":"tsx src/index.ts","build":"tsc","start":"node dist/index.js","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"demitycho","email":"tanweihao94@gmail.com"},"_npmVersion":"10.9.3","description":"MCP server for Google Workspace (Drive, Sheets, Gmail, Calendar, Tasks) with OAuth and service account auth","directories":{},"_nodeVersion":"22.20.0","dependencies":{"zod":"^3.24.2","googleapis":"^144.0.0","@modelcontextprotocol/sdk":"^1.6.1"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","typescript":"^5.7.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/google-workspace-mcp_3.2.1_1777617191082_0.03245705263585341","host":"s3://npm-registry-packages-npm-production"}},"3.3.0":{"name":"@demitycho/google-workspace-mcp","version":"3.3.0","description":"MCP server for Google Workspace (Drive, Sheets, Gmail, Calendar, Tasks) with OAuth and service account auth","type":"module","main":"dist/index.js","bin":{"google-workspace-mcp":"dist/index.js"},"scripts":{"build":"tsc","start":"node dist/index.js","dev":"tsx src/index.ts","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"dependencies":{"@modelcontextprotocol/sdk":"^1.6.1","googleapis":"^144.0.0","zod":"^3.24.2"},"devDependencies":{"@types/node":"^22.0.0","tsx":"^4.0.0","typescript":"^5.7.0"},"types":"dist/index.d.ts","engines":{"node":">=20"},"keywords":["mcp","google","drive","sheets","gmail","calendar","tasks","claude","ai"],"license":"MIT","_id":"@demitycho/google-workspace-mcp@3.3.0","gitHead":"bcb178d23e233ea4c00a0f872de94989e2a442e3","_nodeVersion":"22.20.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-FT5XU7dIcAd+kS/OvCpS0NieWybfo9Zht6N0oHvOUY+bBPBfPOWA4LUdVw/94K4JfHv4vcc0f5Hz3GZdbVN3Rg==","shasum":"303a89689311eda4cf85ed3305690c072388cad6","tarball":"https://registry.npmjs.org/@demitycho/google-workspace-mcp/-/google-workspace-mcp-3.3.0.tgz","fileCount":28,"unpackedSize":179414,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBzeUI341bMC7eRtMa40xBstzQd4tYDFTgWn1ub9/2mpAiEAhRsrxkPkPq/qRR+a/184vcriRmUehbS12s8XsecFHgw="}]},"_npmUser":{"name":"demitycho","email":"tanweihao94@gmail.com"},"directories":{},"maintainers":[{"name":"demitycho","email":"tanweihao94@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/google-workspace-mcp_3.3.0_1777707144302_0.6486650197192214"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-01T06:31:31.962Z","modified":"2026-05-02T07:32:24.599Z","3.2.0":"2026-05-01T06:31:32.260Z","3.2.1":"2026-05-01T06:33:11.242Z","3.3.0":"2026-05-02T07:32:24.487Z"},"license":"MIT","keywords":["mcp","google","drive","sheets","gmail","calendar","tasks","claude","ai"],"description":"MCP server for Google Workspace (Drive, Sheets, Gmail, Calendar, Tasks) with OAuth and service account auth","maintainers":[{"name":"demitycho","email":"tanweihao94@gmail.com"}],"readme":"# Google Workspace MCP Server\n\nMCP server providing Google Drive, Sheets, Gmail, Calendar, and Tasks access via `googleapis`. Supports two auth modes: **OAuth** (per-user consent via control plane) and **Service Account** (domain-wide delegation for business clients).\n\n## Version\n\n**3.3.0** — Added `find_lab_test_pdf` composite tool for lab test document retrieval workflows.\n\n## Architecture\n\n### OAuth Mode\n\n```mermaid\nflowchart TB\n    subgraph CP[\"Furnace Control Plane\"]\n        AuthAPI[\"/internal/google/auth-url<br/>/internal/google/tokens\"]\n        Onboard[\"/onboarding/google/callback\"]\n        DB[\"client_mcp_configs<br/>(encrypted tokens)\"]\n        AuthAPI --> DB\n        Onboard --> DB\n    end\n\n    subgraph Container[\"Agent Container\"]\n        MCP[\"MCP Server (this package)\"]\n        OAuth2[\"google-auth-library<br/>OAuth2Client\"]\n        APIs[\"googleapis<br/>(Drive/Sheets/Gmail/Calendar/Tasks)\"]\n\n        MCP -->|\"fetch tokens<br/>request auth URL\"| AuthAPI\n        MCP --> OAuth2\n        MCP --> APIs\n        APIs -->|\"API calls\"| Google[\"Google Workspace APIs\"]\n        OAuth2 -->|\"refresh token<br/>rotation\"| AuthAPI\n    end\n\n    User[\"User Browser\"] -->|\"consent\"| Onboard\n\n    style CP fill:#e1f5fe\n    style Container fill:#f3e5f5\n    style DB fill:#fff9c4\n    style Google fill:#e8f5e9\n```\n\n### Service Account Mode\n\n```mermaid\nflowchart TB\n    subgraph Container[\"Agent Container\"]\n        MCP[\"MCP Server (this package)\"]\n        JWT[\"google-auth-library<br/>JWT Client\"]\n        APIs[\"googleapis<br/>(Drive/Sheets/Gmail/Calendar/Tasks)\"]\n\n        MCP --> JWT\n        MCP --> APIs\n        APIs -->|\"API calls (impersonating user)\"| Google[\"Google Workspace APIs\"]\n        MCP -->|\"scope check (once)\"| TokenInfo[\"Google Tokeninfo API\"]\n    end\n\n    SA[\"Service Account JSON<br/>(mounted by hub)\"] -->|\"key file\"| JWT\n\n    style Container fill:#f3e5f5\n    style Google fill:#e8f5e9\n    style TokenInfo fill:#fff9c4\n```\n\n### How It Works — OAuth\n\n1. **Agent calls MCP tool** (e.g., `drive_list_files`)\n2. **MCP checks scopes** — calls control plane to fetch tokens, verifies the token has the required scopes\n3. **Has scopes** — refreshes access token if expired, executes API call\n4. **Missing scopes** — requests auth URL from control plane, returns `AUTH_REQUIRED` with URL and missing scope info\n5. **Agent sends URL to user** — user taps, Google shows only new permissions (incremental consent)\n6. **Control plane callback** — exchanges code, stores tokens encrypted in `client_mcp_configs`\n7. **Agent retries** — MCP fetches fresh tokens from control plane, succeeds\n\n### How It Works — Service Account\n\n1. **Agent calls MCP tool**\n2. **First call only** — MCP reads service account key, creates JWT client with subject impersonation, authorizes, and verifies granted scopes via Google's tokeninfo endpoint\n3. **Subsequent calls** — reuses initialized client (no refresh needed, JWT tokens are self-signed)\n4. **If scopes are missing** — returns clear error naming missing scopes and service account email (admin needs to update delegation)\n\n## Environment Variables\n\n### Shared\n\n| Variable | Required | Default | Description |\n|----------|----------|---------|-------------|\n| `GOOGLE_AUTH_MODE` | No | `oauth` | Auth mode: `oauth` or `service_account` |\n| `ENCRYPTION_KEY` | Yes | — | Shared secret for platform API authentication |\n| `CLIENT_ID` | Yes | — | Client identifier (set by hosting platform at runtime) |\n| `AGENT_CONFIG_ID` | Yes | — | Agent identifier (set by hosting platform at runtime) |\n| `GOOGLE_ROOT_FOLDER_ID` | No | — | Drive folder ID scoping Drive operations |\n| `GOOGLE_SERVICES` | No | `drive,sheets,gmail,calendar,tasks` | Comma-separated enabled services |\n| `GOOGLE_READONLY` | No | `false` | If `true`, only read tools for Drive/Sheets |\n\n### OAuth Mode (required when `GOOGLE_AUTH_MODE=oauth`)\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `GOOGLE_CLIENT_ID` | Yes | OAuth client ID from GCP Console |\n| `GOOGLE_CLIENT_SECRET` | Yes | OAuth client secret from GCP Console |\n| `GOOGLE_AUTH_URL` | Yes | Platform base URL for token management and auth URL generation |\n\n### Service Account Mode (required when `GOOGLE_AUTH_MODE=service_account`)\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `GOOGLE_SERVICE_ACCOUNT_PATH` | Yes | Path to service account JSON key file |\n| `GOOGLE_IMPERSONATE_USER` | Yes | Email address to impersonate (domain-wide delegation) |\n\n## Scope-Aware Auth\n\n### OAuth Mode\n\nEach tool declares required OAuth scopes. Before executing, the MCP verifies the stored token covers those scopes. If not:\n\n```json\n{\n  \"error\": \"AUTH_REQUIRED\",\n  \"auth_url\": \"https://accounts.google.com/o/oauth2/v2/auth?...\",\n  \"missing_scopes\": [\"https://www.googleapis.com/auth/gmail.compose\"],\n  \"current_scopes\": [\"https://www.googleapis.com/auth/drive\"],\n  \"message\": \"Google Workspace access required. Missing scopes: ...\"\n}\n```\n\nScopes are requested for all configured services upfront (one consent screen). Re-auth is only required if `GOOGLE_SERVICES` is expanded to include a new service.\n\n### Service Account Mode\n\nOn first tool call, the MCP verifies granted scopes against requested scopes via Google's tokeninfo endpoint. If the Workspace admin didn't delegate a required scope:\n\n```\nError: Service account (sa-name@project.iam.gserviceaccount.com) is missing delegated scopes:\nhttps://www.googleapis.com/auth/gmail.compose. Ask your Workspace admin to grant domain-wide\ndelegation for these scopes in the Admin Console.\n```\n\n### `check_google_auth` Tool\n\nProactively check connection status without triggering an error:\n\n```\nInput: { requested_scopes: \"drive,sheets\" }\nOutput: {\n  \"connected\": true,\n  \"current_scopes\": [\"https://www.googleapis.com/auth/drive\", ...],\n  \"missing_scopes\": [],\n  \"auth_url\": null\n}\n```\n\n## Token Management (OAuth mode only)\n\n- **Fetch**: MCP calls `GET /internal/google/tokens` on first API call\n- **Refresh**: Uses `google-auth-library`'s `OAuth2Client` with 60-second proactive buffer\n- **Persist**: Only persists back to control plane when refresh token rotates (rare)\n- **Re-auth**: After onboarding, MCP re-fetches from control plane — no container restart needed\n\n## Tools (53 total)\n\n### Meta\n\n| Tool | Description |\n|------|-------------|\n| `check_google_auth` | Check connection status, missing scopes, get auth URL |\n\n### Drive (16 tools)\n\n| Tool | R/W | Description |\n|------|-----|-------------|\n| `drive_list_files` | R | List files in folder (paginated) |\n| `drive_list_folders` | R | List only folders in folder |\n| `drive_get_file` | R | Get file metadata |\n| `drive_read_file` | R | Read text file content (truncates at 1MB) |\n| `drive_download` | R | Get download URL for binary files |\n| `drive_search` | R | Search files by name in root tree |\n| `drive_tree` | R | Get folder tree structure |\n| `drive_create_folder` | W | Create folder |\n| `drive_create_file` | W | Create text file |\n| `drive_update_file` | W | Update file content |\n| `drive_move_file` | W | Move file to different folder |\n| `drive_rename_file` | W | Rename file/folder |\n| `drive_delete_file` | W | Trash file/folder |\n| `drive_share_file` | W | Set link sharing (private/anyone/anyone_with_link) |\n| `drive_add_collaborator` | W | Add user as collaborator |\n| `drive_remove_collaborator` | W | Remove collaborator |\n| `drive_get_permissions` | R | Get file permissions and collaborators |\n\n### Sheets (12 tools)\n\n| Tool | R/W | Description |\n|------|-----|-------------|\n| `sheets_list` | R | List all spreadsheets in root folder |\n| `sheets_get_info` | R | Get spreadsheet metadata and sheets |\n| `sheets_get_sheet` | R | Get specific sheet/tab metadata |\n| `sheets_read_cell` | R | Read single cell |\n| `sheets_read_range` | R | Read range (truncates at 10k rows) |\n| `sheets_read_all` | R | Read entire sheet |\n| `sheets_write_cell` | W | Write single cell |\n| `sheets_write_range` | W | Write 2D array to range |\n| `sheets_append_row` | W | Append row to end of sheet |\n| `sheets_clear_range` | W | Clear range values |\n| `sheets_create_sheet` | W | Create new sheet/tab |\n| `sheets_delete_sheet` | W | Delete sheet/tab |\n| `sheets_create_spreadsheet` | W | Create new spreadsheet file |\n\n### Gmail (7 tools)\n\n| Tool | R/W | Description |\n|------|-----|-------------|\n| `gmail_search_messages` | R | Search messages with query |\n| `gmail_read_message` | R | Get full message with decoded body |\n| `gmail_read_thread` | R | Get all messages in thread |\n| `gmail_send_message` | W | Send email (HTML or plain text) |\n| `gmail_create_draft` | W | Create email draft |\n| `gmail_modify_labels` | W | Add/remove labels on message |\n| `gmail_list_labels` | R | List all labels |\n\n### Calendar (8 tools)\n\n| Tool | R/W | Description |\n|------|-----|-------------|\n| `gcal_list_calendars` | R | List all calendars |\n| `gcal_list_events` | R | List events in calendar |\n| `gcal_get_event` | R | Get single event details |\n| `gcal_create_event` | W | Create new event |\n| `gcal_update_event` | W | Update existing event |\n| `gcal_delete_event` | W | Delete event |\n| `gcal_respond_to_event` | W | Accept/decline/tentative response |\n\n### Tasks (8 tools)\n\n| Tool | R/W | Description |\n|------|-----|-------------|\n| `gtasks_list_tasklists` | R | List all task lists |\n| `gtasks_get_tasklist` | R | Get a specific task list |\n| `gtasks_list_tasks` | R | List tasks in a task list (filter by completion/due date) |\n| `gtasks_get_task` | R | Get a specific task |\n| `gtasks_create_task` | W | Create a new task |\n| `gtasks_update_task` | W | Update task (title, notes, status, due date) |\n| `gtasks_delete_task` | W | Delete a task |\n| `gtasks_clear_tasks` | W | Clear all completed tasks from a list |\n\n### Lina (1 tool — composite)\n\n| Tool | R/W | Description |\n|------|-----|-------------|\n| `lina_report` | W | Generate timestamped stock report (low-stock or OOS mailing list) and save as Google Sheet in `lina_reports` folder. Requires Drive + Sheets services. |\n\n### Lab Test (1 tool — composite)\n\n| Tool | R/W | Description |\n|------|-----|-------------|\n| `find_lab_test_pdf` | R | Search Drive root folder for lab test PDF by batch number. Tries multiple search variants (with/without .pdf suffix, stripped hyphens/spaces). Returns webViewLink if found. Requires Drive service. |\n\n## Service Filtering\n\nOnly register tools the agent needs — saves context tokens:\n\n```json\n\"GOOGLE_SERVICES\": \"sheets\"               // Only Sheets tools\n\"GOOGLE_SERVICES\": \"drive,sheets\"         // Drive + Sheets\n\"GOOGLE_SERVICES\": \"drive,sheets,gmail\"   // Drive + Sheets + Gmail\n```\n\n## OAuth Scopes\n\n| Service | Scope URLs |\n|---------|-----------|\n| Drive | `https://www.googleapis.com/auth/drive` |\n| Sheets | `https://www.googleapis.com/auth/spreadsheets` |\n| Gmail | `https://www.googleapis.com/auth/gmail.compose`, `https://www.googleapis.com/auth/gmail.modify` |\n| Calendar | `https://www.googleapis.com/auth/calendar` |\n| Tasks | `https://www.googleapis.com/auth/tasks` |\n\n## Installation\n\n```bash\nnpx -y @cl0ud95/google-workspace-mcp\n```\n\n## Development\n\n```bash\nnpm install\nnpm run build      # Compile TypeScript\nnpm run dev        # Run with tsx\nnpm run typecheck  # Type check only\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}