google-workspace

Google Workspace APIs

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "google-workspace" with this command: npx skills add jezweb/claude-skills/jezweb-claude-skills-google-workspace

Google Workspace APIs

Status: Production Ready Last Updated: 2026-01-09 Dependencies: Cloudflare Workers (recommended), Google Cloud Project Skill Version: 1.0.0

Quick Reference

API Common Use Cases Reference

Gmail Email automation, inbox management gmail-api.md

Calendar Event management, scheduling calendar-api.md

Drive File storage, sharing drive-api.md

Sheets Spreadsheet data, reporting sheets-api.md

Docs Document generation docs-api.md

Chat Bots, webhooks, spaces chat-api.md

Meet Video conferencing meet-api.md

Forms Form responses, creation forms-api.md

Tasks Task management tasks-api.md

Admin SDK User/group management admin-sdk.md

People Contacts management people-api.md

Shared Authentication Patterns

All Google Workspace APIs use the same authentication mechanisms. Choose based on your use case.

Option 1: OAuth 2.0 (User Context)

Best for: Acting on behalf of a user, accessing user-specific data.

// Authorization URL const authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth') authUrl.searchParams.set('client_id', env.GOOGLE_CLIENT_ID) authUrl.searchParams.set('redirect_uri', ${env.BASE_URL}/callback) authUrl.searchParams.set('response_type', 'code') authUrl.searchParams.set('scope', SCOPES.join(' ')) authUrl.searchParams.set('access_type', 'offline') // For refresh tokens authUrl.searchParams.set('prompt', 'consent') // Force consent for refresh token

// Token exchange async function exchangeCode(code: string): Promise<TokenResponse> { const response = await fetch('https://oauth2.googleapis.com/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ code, client_id: env.GOOGLE_CLIENT_ID, client_secret: env.GOOGLE_CLIENT_SECRET, redirect_uri: ${env.BASE_URL}/callback, grant_type: 'authorization_code', }), }) return response.json() }

// Refresh token async function refreshToken(refresh_token: string): Promise<TokenResponse> { const response = await fetch('https://oauth2.googleapis.com/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ refresh_token, client_id: env.GOOGLE_CLIENT_ID, client_secret: env.GOOGLE_CLIENT_SECRET, grant_type: 'refresh_token', }), }) return response.json() }

Critical:

  • Always request access_type=offline for refresh tokens

  • Use prompt=consent to ensure refresh token is returned

  • Store refresh tokens securely (Cloudflare KV or D1)

  • Access tokens expire in ~1 hour

Option 2: Service Account (Server-to-Server)

Best for: Backend automation, no user interaction, domain-wide delegation.

import { SignJWT } from 'jose'

async function getServiceAccountToken( serviceAccount: ServiceAccountKey, scopes: string[] ): Promise<string> { const now = Math.floor(Date.now() / 1000)

// Create JWT const jwt = await new SignJWT({ iss: serviceAccount.client_email, scope: scopes.join(' '), aud: 'https://oauth2.googleapis.com/token', iat: now, exp: now + 3600, }) .setProtectedHeader({ alg: 'RS256', typ: 'JWT' }) .sign(await importPKCS8(serviceAccount.private_key, 'RS256'))

// Exchange JWT for access token const response = await fetch('https://oauth2.googleapis.com/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', assertion: jwt, }), })

const data = await response.json() return data.access_token }

Domain-Wide Delegation (impersonate users):

const jwt = await new SignJWT({ iss: serviceAccount.client_email, sub: 'user@domain.com', // User to impersonate scope: scopes.join(' '), aud: 'https://oauth2.googleapis.com/token', iat: now, exp: now + 3600, })

Setup Required:

  • Create service account in Google Cloud Console

  • Download JSON key file

  • Enable domain-wide delegation in Admin Console (if impersonating)

  • Store key as Cloudflare secret (JSON stringified)

Common Rate Limits

All Google Workspace APIs enforce quotas. These are approximate - check each API's specific limits.

Per-User Limits (OAuth)

API Reads Writes Notes

Gmail 250/user/sec 250/user/sec Aggregate across all methods

Calendar 500/user/100sec 500/user/100sec Per calendar

Drive 1000/user/100sec 1000/user/100sec

Sheets 100/user/100sec 100/user/100sec Lower than others

Per-Project Limits

API Daily Quota Per-Minute Notes

Gmail 1B units Varies Unit-based (send = 100 units)

Calendar 1M queries 500/sec

Drive 1B queries 1000/sec

Sheets Unlimited 500/user/100sec

Handling Rate Limits

async function withRetry<T>( fn: () => Promise<T>, maxRetries = 5 ): Promise<T> { for (let i = 0; i < maxRetries; i++) { try { return await fn() } catch (error: any) { const status = error.status || error.code

  if (status === 429 || status === 503) {
    // Rate limited or service unavailable
    const retryAfter = error.headers?.get('Retry-After') || Math.pow(2, i)
    await new Promise(r => setTimeout(r, retryAfter * 1000))
    continue
  }

  if (status === 403 &#x26;&#x26; error.message?.includes('rateLimitExceeded')) {
    // Quota exceeded - exponential backoff
    await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000))
    continue
  }

  throw error
}

} throw new Error('Max retries exceeded') }

Batch Requests

Most Google APIs support batching multiple requests into one HTTP call.

async function batchRequest( accessToken: string, requests: BatchRequestItem[] ): Promise<BatchResponse[]> { const boundary = 'batch_boundary'

let body = '' requests.forEach((req, i) => { body += --${boundary}\r\n body += 'Content-Type: application/http\r\n' body += Content-ID: &#x3C;item${i}>\r\n\r\n body += ${req.method} ${req.path} HTTP/1.1\r\n body += 'Content-Type: application/json\r\n\r\n' if (req.body) body += JSON.stringify(req.body) body += '\r\n' }) body += --${boundary}--

const response = await fetch('https://www.googleapis.com/batch/v1', { method: 'POST', headers: { 'Authorization': Bearer ${accessToken}, 'Content-Type': multipart/mixed; boundary=${boundary}, }, body, })

// Parse multipart response... return parseBatchResponse(await response.text()) }

Limits:

  • Max 100 requests per batch (most APIs)

  • Max 1000 requests per batch (some APIs like Drive)

  • Each request in batch counts toward quota

Cloudflare Workers Configuration

// wrangler.jsonc { "name": "google-workspace-mcp", "main": "src/index.ts", "compatibility_date": "2026-01-03", "compatibility_flags": ["nodejs_compat"],

// Store OAuth tokens "kv_namespaces": [ { "binding": "TOKENS", "id": "xxx" } ],

// Or use D1 for structured storage "d1_databases": [ { "binding": "DB", "database_name": "workspace-mcp", "database_id": "xxx" } ] }

Secrets to set:

echo "your-client-id" | npx wrangler secret put GOOGLE_CLIENT_ID echo "your-client-secret" | npx wrangler secret put GOOGLE_CLIENT_SECRET

For service accounts:

cat service-account.json | npx wrangler secret put GOOGLE_SERVICE_ACCOUNT

Common Errors

Error: "invalid_grant" on Token Refresh

Cause: Refresh token revoked or expired (6 months of inactivity) Fix: Re-authenticate user, request new refresh token

Error: "access_denied" on OAuth

Cause: App not verified, or user not in test users list Fix: Add user to OAuth consent screen test users, or complete app verification

Error: "insufficientPermissions" (403)

Cause: Missing required scope Fix: Check scopes in authorization URL, re-authenticate with correct scopes

Error: "rateLimitExceeded" (403)

Cause: Quota exceeded Fix: Implement exponential backoff, reduce request frequency, request quota increase

Error: "notFound" (404) on Known Resource

Cause: Using wrong API version, or resource in trash Fix: Check API version in URL, check trash for deleted items

API-Specific Guides

Detailed patterns for each API are in the references/ directory. Load these when working with specific APIs.

Gmail API

See references/gmail-api.md

  • Message CRUD, labels, threads

  • MIME handling, attachments

  • Push notifications (Pub/Sub)

Calendar API

See references/calendar-api.md

  • Events CRUD, recurring events

  • Free/busy queries

  • Calendar sharing

Drive API

See references/drive-api.md

  • File upload/download

  • Permissions, sharing

  • Search queries

Sheets API

See references/sheets-api.md

  • Reading/writing cells

  • A1 notation, ranges

  • Batch updates

Chat API

See references/chat-api.md

  • Bots, webhooks

  • Cards v2, interactive forms

  • Spaces, members, reactions

(Additional API references added as MCP servers are built)

Package Versions (Verified 2026-01-09)

{ "devDependencies": { "@cloudflare/workers-types": "^4.20260109.0", "wrangler": "^4.58.0", "jose": "^6.1.3" } }

Official Documentation

Skill Roadmap

APIs documented as MCP servers are built:

  • Gmail API

  • Calendar API

  • Drive API

  • Sheets API

  • Docs API

  • Chat API (migrated from google-chat-api skill)

  • Meet API

  • Forms API

  • Tasks API

  • Admin SDK

  • People API

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

tailwind-v4-shadcn

No summary provided by upstream source.

Repository SourceNeeds Review
-2.7K
jezweb
General

tanstack-query

No summary provided by upstream source.

Repository SourceNeeds Review
-2.5K
jezweb
General

fastapi

No summary provided by upstream source.

Repository SourceNeeds Review