
<!-- Created: Friday, July 17, 2026, 4:26 PM -->
<!-- Updated: Saturday, July 18, 2026, 1:19 PM -->

Connecting **Google Workspace** to your terminal via the **Model Context Protocol (MCP)** is a significant shift in developer ergonomics. Following the deprecation of `gemini-cli` and your transition to the [Go-powered Antigravity CLI](/posts/gemini-cli-is-dead/), your local AI agent transforms from an isolated shell helper into a deeply context-aware partner. By enabling a direct line between large language models and your Workspace APIs, it can seamlessly read your `Calendar`, draft `Gmail` messages, search `Drive` files, coordinate `Chat` updates, and query `People` directories.

However, moving from a basic local script to an **enterprise-grade, declarative setup** introduces several complex architectural choices and quiet security traps, especially when managing developer workstations with macOS and Nix. 

This guide details how to establish a centralized GCP gateway, safely distribute credentials using **SOPS-nix**, and dodge the silent authorization failures that commonly block Workspace integrations.

<div class="important-callout">
  <strong>⚠️ Who is eligible for the Developer Preview?</strong>
  <ul>
    <li><b>Eligible Custom Domains</b>: Google Workspace accounts on custom-managed domains, such as <code>username@yourdomain.com</code>.</li>
    <li><b>Ineligible Consumer Accounts</b>: Standard personal Google accounts, such as <code>username@gmail.com</code>.</li>
  </ul>
  <p>If your active Google identity ends in <code>@gmail.com</code>, you <b>cannot</b> enroll in Google's Workspace Developer Preview program, and Google will block your MCP requests with a <code>403 Forbidden</code> error.</p>
</div>

---

## Multi-User Architecture

When deploying Google Workspace MCP across an engineering team, there is no need to configure unique Google Cloud Platform, or GCP, projects for every team member. A single, centralized project is both easier to govern and functionally isolated out of the box.

By using a single GCP project, such as `cwrk-workspace-ai-hub`, you can support your entire domain with a streamlined posture:

* **Shared Client ID**: Set up a single OAuth Web Application Client ID and Client Secret, configured with the authorized redirect URI `https://antigravity.google/oauth-callback`. Every developer machine will use these same credentials.
* **Internal Domain Restriction**: Configure your OAuth Consent Screen to **Internal**. This restricts authorization strictly to identities within your managed Workspace domain, such as `@cwrk.ai`, automatically turning away external users.
* **Decentralized Token Isolation**: Although developers share the same Client ID, the actual OAuth handshake is fully delegated. When a developer runs the CLI, the browser redirect captures a user-specific refresh token. This token is cached locally on their machine, ensuring complete privacy and context isolation between team members.

This design gives administrators centralized visibility and control over API scopes, while engineers retain total privacy and operational independence.

```mermaid
graph TD
    subgraph GCP ["Central GCP Project (cwrk-workspace-ai-hub)"]
        A["OAuth Consent (Internal Only)"]
        B["Shared Client ID & Client Secret"]
    end
    subgraph Local ["Employee Workstations"]
        C["Developer 1"] -->|Uses Shared Client ID| B
        D["Developer 2"] -->|Uses Shared Client ID| B
        E["User-Specific Refresh Tokens (Cached Locally)"]
    end
    B -->|Browser Auth Handoff| E
```

---

## Secrets with SOPS-nix

Committing plain Client Secrets to public or private git-tracked Nix dotfiles is a major security risk. To maintain a declarative machine setup without compromising credentials, we use Mozilla SOPS to encrypt the Workspace secrets, and Nix-darwin to mount them securely during system rebuilds.

### Step A: Encrypted Secrets (secrets.yaml)

Encrypt your Workspace client secret locally using SOPS. This file is safe to commit to your version control repository:

```yaml
gws_client_secret: ENC[AES256_GCM,data:...==,iv:...]
```

### Step B: Declarative Nix Config (configuration.nix)

Rather than staging plaintext JSON configuration templates, use `sops.templates` in Nix-darwin to dynamically assemble `$HOME/.gemini/config/mcp_config.json` at build time, securely inserting the decrypted secret during evaluation. 

Because Nix-darwin system evaluations run prior to shell initialization, the Nix template requires absolute path definitions rather than relative environment variables. In this example, the template safely maps the decrypted placeholder secret directly into our target user directory:

```nix
sops.secrets."gws_client_secret" = {
  owner = config.users.users.username.name;
};

sops.templates."mcp_config" = {
  owner = config.users.users.username.name;
  path = "/Users/username/.gemini/config/mcp_config.json";
  content = ''
    {
      "mcpServers": {
        "gws-calendar": {
          "serverUrl": "https://calendarmcp.googleapis.com/mcp/v1",
          "oauth": {
            "clientId": "812812457358-md23v9mj6nu3vu3m5utb4mvhdbe5t1nt.apps.googleusercontent.com",
            "clientSecret": "${config.sops.placeholder.gws_client_secret}"
          }
        },
        "gws-chat": {
          "serverUrl": "https://chatmcp.googleapis.com/mcp/v1",
          "oauth": {
            "clientId": "812812457358-md23v9mj6nu3vu3m5utb4mvhdbe5t1nt.apps.googleusercontent.com",
            "clientSecret": "${config.sops.placeholder.gws_client_secret}"
          }
        },
        "gws-drive": {
          "serverUrl": "https://drivemcp.googleapis.com/mcp/v1",
          "oauth": {
            "clientId": "812812457358-md23v9mj6nu3vu3m5utb4mvhdbe5t1nt.apps.googleusercontent.com",
            "clientSecret": "${config.sops.placeholder.gws_client_secret}"
          }
        },
        "gws-gmail": {
          "serverUrl": "https://gmailmcp.googleapis.com/mcp/v1",
          "oauth": {
            "clientId": "812812457358-md23v9mj6nu3vu3m5utb4mvhdbe5t1nt.apps.googleusercontent.com",
            "clientSecret": "${config.sops.placeholder.gws_client_secret}"
          }
        },
        "gws-people": {
          "serverUrl": "https://people.googleapis.com/mcp/v1",
          "oauth": {
            "clientId": "812812457358-md23v9mj6nu3vu3m5utb4mvhdbe5t1nt.apps.googleusercontent.com",
            "clientSecret": "${config.sops.placeholder.gws_client_secret}"
          }
        }
      }
    }
  '';
};
```

---

## Setup Gotchas

Even with clean configurations, Workspace integrations can run into subtle runtime traps. Here are the three most common gotchas and how to resolve them:

### Gotcha #1: The Workspace Developer Preview Restriction
* **Symptom**: All target APIs are enabled in your GCP console, client credentials match, and the browser authentication pass succeeds, yet every single agent tool call fails immediately with a `403 Forbidden` error.
* **The Cause**: Google's Workspace MCP endpoints are currently in Public Developer Preview. Google blocks all API calls unless the authorized user account has been registered in the preview program.
* **The Solution**: Register your custom-domain Workspace account via the official portal before initiating developer connections:  
  👉 [Google Workspace Developer Preview Registration](https://developers.google.com/workspace/preview)

### Gotcha #2: Dual-API Activation and Google Chat App Setup
* **Symptom**: The client compiles and switches cleanly, but the Google Chat or Google Gmail servers fail to authenticate or return data.
* **The Cause**: Several Workspace services have dual requirements. First, enabling the MCP service, such as `chatmcp.googleapis.com` or `gmailmcp.googleapis.com`, will fail unless the underlying standard service API, such as `chat.googleapis.com` or `gmail.googleapis.com`, is also explicitly enabled in your GCP project. Second, to use Google Chat MCP, you must configure a Google Chat App inside GCP and disable interactive features.
* **The Solution**: Enable both the standard and MCP-specific service APIs for your targeted tools. Then, go to the Google Chat API Configuration page, set up your app name as `Chat MCP`, and ensure that you turn off the "Enable interactive features" checkbox before saving.

### Gotcha #3: Nix Flakes and Untracked Files
* **Symptom**: Running `nix darwin-rebuild switch` fails with a cryptic file not found error, even though your new configuration file is clearly sitting in your directory.
* **The Cause**: Nix Flakes isolates evaluations strictly to files currently tracked in the local Git index. If your new `configuration.nix` or SOPS templates are not staged, Nix evaluates the system as if they do not exist.
* **The Solution**: Stage your newly added configuration file inside your repository's Git working tree using `git add` before evaluating. For the example in this guide, run `git add configuration.nix`.

---

## FAQ

### Q: Where are active Workspace OAuth tokens cached?
The Antigravity and Gemini CLIs cache your active credentials at:
```bash
$HOME/.gemini/antigravity-cli/mcp_oauth_tokens.json
```
Delete this file to force a clean authentication pass whenever you alter API permissions or scopes on GCP.

### Q: Why do I still get "The caller does not have permission" (403) immediately after being approved or enabling APIs?
Google operates a massive, globally distributed edge-proxy routing cache to authorize incoming Workspace MCP requests instantly. When your custom Workspace domain is newly approved for the **Developer Preview Program** or you enable new APIs in your GCP project, your authorized state and API configurations do not replicate instantly. 

Google’s edge proxies sync their local permissions tables during scheduled batch cycles, creating a **propagation delay of up to 24 hours** (typically taking 12 to 16 hours to warm up). 

To verify whether your configuration is correct or if you are simply waiting on Google's edge cache, run this diagnostic check in your terminal using Google's Tokeninfo API and your active access token (retrieved from `mcp_oauth_tokens.json`):
```bash
curl -s "https://oauth2.googleapis.com/tokeninfo?access_token=<YOUR_ACCESS_TOKEN>"
```
If the JSON response lists your client ID, corporate email, and all required scopes (e.g., `contacts.readonly`, `drive.readonly`), your local setup, Nix configs, and SOPS keys are **100% correct**. No more troubleshooting is needed—simply sit back, wait for Google's global replication to complete, and your Workspace tools will automatically activate!

<div class="tip-callout">
  <strong>⏱️ Real-World Case Reference:</strong>
  <p>During our team's deployment of a corporate <code>@cwrk.ai</code> Workspace domain, we observed this exact propagation timeline:</p>
  <ul>
    <li><b>Last Access-Denied Failure</b>: 2026-07-17 at 21:09:56 KST</li>
    <li><b>First Successful API Call</b>: 2026-07-18 at 13:11:31 KST</li>
    <li><b>Total Propagation Time</b>: Exactly <b>16 hours, 1 minute, and 35 seconds</b></li>
  </ul>
  <p>Once the backend whitelist synchronization completed, all 5 servers (Gmail, Calendar, Drive, People, Chat) instantly transitioned from 403 authorization failures to seamless, full-functioning data retrieval.</p>
</div>

### Q: Are there limitations when using personal @gmail.com accounts?
Yes. First and foremost, **personal @gmail.com accounts cannot register for the Google Workspace Developer Preview program**, which is a prerequisite for activating Workspace MCP endpoints. Per [Google's Workspace Developer Program Terms](https://developers.google.com/workspace/preview), participation is strictly restricted to Google Workspace customer accounts on a custom domain, such as `username@yourdomain.com`. Consumer `@gmail.com` accounts do not have access to the Google Admin console or domain administrative controls required for developer preview API access. Furthermore, Workspace-exclusive features, including searching corporate user directories in `gws-people` or initiating Chat rooms via `gws-chat`, are fundamentally restricted to corporate domains and will return permission exceptions if called from consumer `@gmail.com` accounts.

### Q: How do multiple employees safely share a single encrypted client secret?
Mozilla SOPS solves this organizational challenge through two primary distribution architectures:
*   **Multi-Key Encryption**: In your repository configuration file, such as `.sops.yaml`, you can list the individual public [age](https://github.com/filosottile/age) keys or PGP fingerprints of every engineer on your team. When you save your secrets file, SOPS encrypts it against all of these keys. Any developer with a corresponding private key on their local machine can decrypt the file, allowing you to check the encrypted payload directly into Git.
*   **Centralized Cloud KMS**: For larger departments, you can route decryption permissions to a cloud-managed key registry, such as Google Cloud KMS. Instead of managing individual developer keys in Git, you configure `.sops.yaml` to point to a central KMS key. System rebuilds will use local authenticated developer credentials to request decryption on the fly, allowing you to manage access policies through corporate identity management.

---

## Conclusion

By routing your Google Workspace MCP integration through a centralized GCP gateway and securing your local client config via SOPS-nix, you achieve a clean, enterprise-grade, and reproducible development setup. Your Antigravity CLI is no longer an isolated terminal loop—it is an intelligent agent fully plugged into your day-to-day work context.

Happy hacking!

---

## References

*   **Google Workspace Developer Preview Program**: [Official Registration Portal](https://developers.google.com/workspace/preview) and [Program Policy Guidelines](https://developers.google.com/workspace/terms/api-services-user-data-policy).
*   **Model Context Protocol (MCP)**: [Official Model Context Protocol Specification](https://modelcontextprotocol.io).
*   **SOPS (Secrets Operations)**: [Mozilla SOPS Encryption Engine](https://github.com/getsops/sops).
*   **sops-nix**: [Declarative secrets for NixOS and nix-darwin](https://github.com/Mic92/sops-nix).

---

## Glossary

<dl>
  <dt><strong><a href="https://github.com/filosottile/age">age (Actually Good Encryption)</a></strong></dt>
  <dd>A simple, modern, and secure file encryption tool, format, and Go library featuring small, explicit keys, no configuration, and fast cryptographic operations.</dd>

  <dt><strong>Model Context Protocol (MCP)</strong></dt>
  <dd>An open-standard protocol designed to facilitate secure, bi-directional tool execution and context injection between Large Language Models (LLMs) and local/remote APIs.</dd>
  
  <dt><strong>SOPS (Secrets Operations)</strong></dt>
  <dd>A cryptographic file editor that encrypts specific values inside YAML, JSON, or ENV formats using <a href="https://github.com/filosottile/age">age</a>, PGP, or cloud KMS keys, keeping files safe to commit to Git.</dd>
  
  <dt><strong>sops-nix</strong></dt>
  <dd>A specialized helper library providing native, declarative secret decryption capabilities during NixOS or nix-darwin system evaluation.</dd>
  
  <dt><strong>OAuth 2.0 Consent Screen</strong></dt>
  <dd>The user interface where Google Workspace users must explicitly approve or deny access permissions requested by a GCP application Client ID.</dd>
  
  <dt><strong>Nix-darwin</strong></dt>
  <dd>A declarative macOS system configuration framework that utilizes the Nix package manager to manage system state, launch daemons, and application settings.</dd>
</dl>

