> ## Documentation Index
> Fetch the complete documentation index at: https://docs.prisme.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Google Workspaces

> Drive, Docs, Sheets, Gmail and Calendar from Agent Factory agents and Builder workflows, with per-user OAuth, service-account or access-token auth

<img src="https://mintcdn.com/prismeai/F02uRm0EmKM1XN6s/images/connectors/google-workspaces.png?fit=max&auto=format&n=F02uRm0EmKM1XN6s&q=85&s=f46c6d14b7a7968997acedd7affe51d8" alt="Google Workspaces" width="96" height="96" noZoom style={{ float: "left", marginRight: "1.25rem", marginBottom: "0.5rem" }} data-path="images/connectors/google-workspaces.png" />

The Google Workspaces app provides read/write access to five [Google Workspace](https://workspace.google.com) APIs — Drive, Docs, Sheets, Gmail and Calendar — through their official REST endpoints. It can be consumed two ways: as a remote MCP server that **Agent Factory** agents call as tools, or as a Builder app whose instructions you call directly from DSUL. The MCP surface groups every operation into **five entity tools** (`drive`, `docs`, `sheets`, `gmail`, `calendar`), each driven by an `action` argument, and runs in the **tenant app-instance context** (it resolves the installing workspace's own credentials). Authentication is per-user and supports several modes:

* **Per-user OAuth2 — central client** (`oauthCentral`, recommended) — one Google OAuth Application is registered once by the platform maintainer; every end user signs in with their own Google account. Nothing to register per tenant: each workspace just installs the app and clicks *Connect*.
* **Per-user OAuth2 — tenant client** (`oauth`) — paste your own Google OAuth client ID/secret in the connector config app. Each user signs in with their own account against your client (PKCE authorization-code flow).
* **Service account — JWT Bearer** (`jwt`) — a Google service-account key, with optional domain-wide delegation (`subject`) to impersonate users across a Workspace domain. No interactive sign-in.
* **Direct access token** (`accessToken`) — a caller-managed Google access token, used as-is with no exchange.

<CardGroup cols={3}>
  <Card title="Drive, Docs & Sheets" icon="folder-open">
    Browse and manage Drive files, folders and sharing permissions, create and edit Docs, read and write Sheets values and structure
  </Card>

  <Card title="Gmail & Calendar" icon="envelope">
    Read, send, label and organize Gmail messages, drafts and threads; list, create and update Calendar events and query free/busy
  </Card>

  <Card title="Flexible per-user auth" icon="key">
    Per-user OAuth (central or tenant client), service-account JWT with optional domain-wide delegation, or a direct access token
  </Card>
</CardGroup>

## Who is this for?

This connector is used by three different roles. Jump to the section that matches yours — each one is self-contained.

<CardGroup cols={3}>
  <Card title="Agent builder" icon="robot">
    You build agents in **Agent Factory** and want them to read and act on Google Workspace. → *Agent builder* tab.
  </Card>

  <Card title="Platform admin" icon="shield-halved">
    You run the platform and set up the shared Google OAuth client once for everyone. → *Platform admin setup* accordion below.
  </Card>

  <Card title="Workspace builder" icon="puzzle-piece">
    You write Builder automations (DSUL) that call Google operations directly. → *Workspace builder* tab.
  </Card>
</CardGroup>

## Prerequisites (Google side)

* A **Google** account (or a Google Workspace domain for service-account / domain-wide delegation).
* The Google APIs you intend to call must be **enabled** in the Cloud project: Drive, Docs, Sheets, Gmail, Calendar.
* An OAuth client or service-account key, depending on the auth mode (see the *Platform admin setup* accordion below and the *Workspace builder* tab).

The OAuth scopes requested by default are:

```text theme={null}
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/documents
https://www.googleapis.com/auth/spreadsheets
https://www.googleapis.com/auth/gmail.modify
https://www.googleapis.com/auth/calendar
openid email
```

<Accordion title="Platform admin (Governance) — one-time platform setup" icon="shield-halved">
  **Goal:** two one-time tasks — (1) configure the shared **central OAuth client** so every workspace lets its users sign in with their own Google account, and (2) expose Google Workspaces as a reusable **capability** in AI Governance so agent builders can pick it without pasting endpoint URLs.

  ## 1. Configure the connector

  <Steps>
    <Step title="Register the OAuth Application at Google">
      In the [Google Cloud Console](https://console.cloud.google.com/apis/credentials), open **APIs & Services > Credentials > Create credentials > OAuth client ID**, type *Web application*. Set the single authorized redirect URI to the core workspace callback:

      ```text theme={null}
      <api-url>/workspaces/slug:google-workspaces/webhooks/oauthCallback
      ```

      (e.g. `https://api.studio.prisme.ai/v2/workspaces/slug:google-workspaces/webhooks/oauthCallback` on production). Enable the Drive, Docs, Sheets, Gmail and Calendar APIs in the same project, and add the scopes listed in *Prerequisites*. Save the **Client ID** + **Client Secret**.
    </Step>

    <Step title="Enter the credentials through the configuration app">
      Open the central `google-workspaces` workspace and launch its **Configuration app** — `<studio>/apps/google-workspaces` (e.g. `https://studio.prisme.ai/apps/google-workspaces`), also linked as `Configuration app` on the installed instance. Follow the in-app instructions to paste the **Client ID** and **Client Secret** — the app stores them in the core workspace's secrets for you. Do not edit Studio's raw Secrets by hand. These credentials stay in the `google-workspaces` workspace and are never exposed to tenants or end users; token exchange is proxied through the core `centralTokenExchange` webhook so the client secret never leaves the core workspace.
    </Step>

    <Step title="Tell workspaces to use the central client">
      Each consuming workspace selects auth mode **`oauthCentral`** in the connector configuration app (no client id/secret to enter on their side). Their users then just click **Connect**.
    </Step>
  </Steps>

  ## 2. Declare the capability in AI Governance

  Generic connectors — broad tool surfaces meant to be shared across many agents, like Google Workspaces — are best exposed as a named **capability** in AI Governance. Agent builders then enable that capability on their agents instead of pasting a raw MCP endpoint.

  <Steps>
    <Step title="Open AI Governance > Capabilities">
      Create (or edit) the **Google Workspaces** capability.
    </Step>

    <Step title="Point it at the MCP endpoint">
      Set the capability's MCP server URL to the connector's **MCP Endpoint**, and set its **Scope** to:

      ```text theme={null}
      context_id,agent_id,user_id
      ```

      The `agent_id` in the scope is what lets the connector identify and authorize the calling agent.
    </Step>

    <Step title="Make it available to agent builders">
      Once created, the capability appears in the capability picker for agent builders in your organization, who enable it on their agents. Access to the catalog follows your organization's existing roles; there is no per-capability role grant.
    </Step>

    <Step title="Smoke-test">
      From an agent that has the capability, in a workspace configured for `oauthCentral`, trigger any tool. The user is prompted to connect once (Google sign-in); subsequent calls reuse the stored token transparently and refresh it automatically.
    </Step>
  </Steps>

  <Warning>
    Declaring the capability makes the connector **available**; it does not by itself authorize a specific agent. This connector follows the **tenant-context model** — which agents may actually call it is gated per-workspace by the **authorized-agents allowlist** in the configuration app (see the *Workspace builder* tab). There is also **no OAuth auth-config JSON** to attach in Governance (unlike GitLab): connect / status / disconnect are handled by the connector's own webhooks, wired automatically.
  </Warning>
</Accordion>

***

<Tabs>
  <Tab title="Agent builder (Agent Factory)">
    ## Agent builder

    **Goal:** let an agent you build in Agent Factory read and act on Google Workspace through MCP tools.

    <Note>
      Before an agent can call the connector, a *Workspace builder* must have installed and configured the Google Workspaces app in a workspace (see the *Workspace builder* tab), and — for the central OAuth mode — a *Platform admin* must have provisioned the shared OAuth client (see the *Platform admin setup* accordion above).
    </Note>

    This connector runs in the **tenant app-instance context**: your agent is authorized two ways at once — it is identified by the `agent_id` that Agent Factory injects through the capability *Scope*, and that agent must appear in the connector's **authorized-agents allowlist** (managed in the configuration app). The Google access token itself is resolved server-side from the configured auth mode.

    There are two ways to wire it up. Pick based on how much isolation you need.

    ## Option A — Enable the shared capability from the catalog

    The fastest path: a *Platform admin* has already published a **Google Workspaces** capability (see the *Platform admin setup* accordion above, §2), so you just pick it from the catalog.

    <Steps>
      <Step title="Open your agent in Agent Factory">
        Open the agent you want to extend and go to its capabilities / tools.
      </Step>

      <Step title="Add the Google Workspaces capability">
        Browse the capability catalog, select **Google Workspaces**, and enable it. The MCP endpoint URL and the *Scope* (`context_id,agent_id,user_id`) are already wired by the admin — nothing to paste, and the shared instance accepts every agent, so there is no allowlist step on your side.
      </Step>

      <Step title="Connect a Google account (OAuth modes)">
        On the first tool call, an unconnected user is prompted to sign in — Agent Factory surfaces a `connect_url`. Service-account (`jwt`) and `accessToken` modes need no per-user sign-in.
      </Step>
    </Steps>

    <Note>
      Convenient, but your agent runs against a **shared, platform-managed instance**: its Google credentials are owned by someone else and the instance accepts every agent that is granted the capability. Prefer Option B for anything beyond quick experiments.
    </Note>

    ## Option B — Run it from your own workspace (recommended)

    For production agents, install the connector in **your own workspace** and point the agent at *that* workspace's MCP endpoint.

    <Warning>
      **Prefer this mode for security.** Because the MCP runs in *your* app-instance context, the Google credentials, the per-user OAuth tokens and the authorized-agents allowlist are all **scoped to your workspace** — not shared platform-wide. You decide exactly which agents may call it and which Google account / auth mode backs them, and a misconfiguration elsewhere can never expose your data. The shared catalog capability (Option A) is a broad surface many agents can reach; your own workspace is an isolated, least-privilege boundary.
    </Warning>

    <Steps>
      <Step title="Install and configure the connector in your workspace">
        Follow the *Workspace builder* tab: install **Google Workspaces** in your workspace, open its **Configuration app**, choose the auth mode and connect a Google account.
      </Step>

      <Step title="Allowlist your agent">
        In that workspace's config app, open **Authorized agents** and tick your agent (the **Install capability** button does this for you).
      </Step>

      <Step title="Add the MCP capability to your agent">
        In your agent, add a capability pointing at **your workspace's MCP Endpoint** URL, and set its **Scope** to:

        ```text theme={null}
        context_id,agent_id,user_id
        ```

        The `agent_id` is what lets the connector identify and authorize your agent — without it, every call is rejected with an explicit "agent could not be identified" message. This *Scope* is separate from the Google OAuth scopes.
      </Step>

      <Step title="Connect a Google account (OAuth modes)">
        On the first tool call, the user is prompted to sign in (or uses **Connect** in the config app).
      </Step>
    </Steps>

    ## Brief the agent in its system prompt

    Whichever option you pick, wiring the capability is not enough — the agent must know the MCP exists and when to use it. Copy-pasteable starter:

    ```text theme={null}
    You have access to the Google Workspaces MCP server (tools: drive, docs, sheets, gmail, calendar). Each tool takes an `action` argument. Use it whenever the user asks about their Google Drive files, Docs, Sheets, Gmail or Calendar — listing, searching, reading, creating or updating. Prefer calling a tool over guessing, and confirm with the user before any destructive action (delete, trash, overwrite, share changes).
    ```

    <Note>
      **Legacy AI Knowledge agents** (no native MCP picker): add the connector under **Advanced > Tools > MCP** and paste the **MCP Endpoint** URL. The agent still has to be allowlisted in the config app and its identity propagated so the connector can read its `agent_id`.
    </Note>

    <Note>
      **Restricting to read-only (least privilege).** Google Workspaces tools cover both reads and writes (edit docs/sheets, modify Gmail, create events). The requested OAuth scopes **are** the grant, so the connector only obtains what the **Scopes** field in the configuration app asks for. To allow only read access, set a read-only scope list, e.g.:

      ```text theme={null}
      https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/documents.readonly https://www.googleapis.com/auth/spreadsheets.readonly https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/calendar.readonly openid email
      ```

      With central OAuth (`oauthCentral`) you do **not** create your own Google client — keep `oauthCentral` and just enter the read-only scopes; your tenant scope overrides the platform default (the central app's consent screen must declare these read scopes). Write calls are then rejected by Google with `403`. Note this is set at the workspace level — a workspace editor can widen it again; a provider-side restriction is the only hard guarantee.
    </Note>

    ## Available Tools

    Each tool takes an `action` argument selecting the concrete operation, plus the per-action parameters.

    | Tool       | Description                                                                                                                                                                |
    | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `drive`    | Google Drive — files & permissions. Actions: `list`, `get`, `create`, `update`, `delete`, `copy`, `export`, `permissionsList`, `permissionsCreate`, `permissionsDelete`.   |
    | `docs`     | Google Docs. Actions: `get`, `create`, `batchUpdate`.                                                                                                                      |
    | `sheets`   | Google Sheets. Actions: `get`, `create`, `valuesGet`, `valuesUpdate`, `valuesAppend`, `valuesClear`, `batchUpdate`.                                                        |
    | `gmail`    | Gmail (current user). Actions: `getProfile`, `messagesList`, `messagesGet`, `messagesSend`, `messagesModify`, `messagesTrash`, `draftsCreate`, `labelsList`, `threadsGet`. |
    | `calendar` | Google Calendar. Actions: `eventsList`, `eventsGet`, `eventsInsert`, `eventsUpdate`, `eventsDelete`, `calendarList`, `freebusy`.                                           |

    ## Output Formats

    Every tool accepts an `outputFormat` argument that controls the MCP response shape:

    * **`verbose`** (default) — human-readable text optimized for LLM consumption
    * **`compact`** — concise machine-readable JSON in `structuredContent`

    ## Tool Details

    ### drive

    ```json theme={null}
    {
      "name": "drive",
      "arguments": {
        "action": "list",
        "q": "name contains 'report' and trashed = false",
        "fields": "files(id,name,mimeType,modifiedTime)"
      }
    }
    ```

    | Parameter  | Required                                        | Description                                                                                                                        |
    | ---------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
    | `action`   | Yes                                             | One of `list`, `get`, `create`, `update`, `delete`, `copy`, `export`, `permissionsList`, `permissionsCreate`, `permissionsDelete`. |
    | `fileId`   | For get/update/delete/copy/export/permissions\* | Drive file id.                                                                                                                     |
    | `q`        | No                                              | Search query (list), e.g. `mimeType='application/vnd.google-apps.folder'`.                                                         |
    | `mimeType` | For export                                      | Target MIME type, e.g. `application/pdf`.                                                                                          |
    | `body`     | For create/update/copy/permissionsCreate        | File metadata, or `{role,type,emailAddress}` for a permission.                                                                     |

    ### sheets

    ```json theme={null}
    {
      "name": "sheets",
      "arguments": {
        "action": "valuesUpdate",
        "spreadsheetId": "1AbcD...",
        "range": "Sheet1!A1:C2",
        "valueInputOption": "USER_ENTERED",
        "body": { "values": [["Name", "Email", "Score"], ["Ada", "ada@x.io", 99]] }
      }
    }
    ```

    | Parameter          | Required                        | Description                                                                                        |
    | ------------------ | ------------------------------- | -------------------------------------------------------------------------------------------------- |
    | `action`           | Yes                             | One of `get`, `create`, `valuesGet`, `valuesUpdate`, `valuesAppend`, `valuesClear`, `batchUpdate`. |
    | `spreadsheetId`    | For all but create              | Target spreadsheet id.                                                                             |
    | `range`            | For values\*                    | A1 notation, e.g. `Sheet1!A1:C10`.                                                                 |
    | `valueInputOption` | For valuesUpdate/valuesAppend   | `RAW` or `USER_ENTERED`.                                                                           |
    | `body`             | For create/values\*/batchUpdate | Spreadsheet resource, `{values:[[...]]}`, or `{requests:[...]}`.                                   |

    ### gmail

    ```json theme={null}
    {
      "name": "gmail",
      "arguments": {
        "action": "messagesSend",
        "body": { "to": "ada@x.io", "subject": "Hello", "text": "Plain body — no base64." }
      }
    }
    ```

    | Parameter | Required                                 | Description                                                                                                                                                                           |
    | --------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `action`  | Yes                                      | One of `getProfile`, `messagesList`, `messagesGet`, `messagesSend`, `messagesModify`, `messagesTrash`, `draftsCreate`, `labelsList`, `threadsGet`.                                    |
    | `id`      | For messagesGet/Modify/Trash, threadsGet | Message or thread id.                                                                                                                                                                 |
    | `q`       | No                                       | Gmail search query (messagesList), e.g. `from:x is:unread`.                                                                                                                           |
    | `body`    | For messagesSend/draftsCreate/Modify     | Send/draft: `{to,subject,text\|html,cc,bcc,replyTo,inReplyTo,threadId}` as plain strings (server-side MIME + base64 — never encode yourself); modify: `{addLabelIds,removeLabelIds}`. |

    <Note>
      Resolve "me" / "my email" with a single `getProfile` call — it returns `{emailAddress, messagesTotal}`. Never list messages to discover the connected address.
    </Note>

    ### calendar

    ```json theme={null}
    {
      "name": "calendar",
      "arguments": {
        "action": "eventsList",
        "calendarId": "primary",
        "timeMin": "2026-07-01T00:00:00Z",
        "timeMax": "2026-07-08T00:00:00Z",
        "singleEvents": true,
        "orderBy": "startTime"
      }
    }
    ```

    | Parameter    | Required                          | Description                                                                                                   |
    | ------------ | --------------------------------- | ------------------------------------------------------------------------------------------------------------- |
    | `action`     | Yes                               | One of `eventsList`, `eventsGet`, `eventsInsert`, `eventsUpdate`, `eventsDelete`, `calendarList`, `freebusy`. |
    | `calendarId` | No                                | Calendar id (defaults to `primary`).                                                                          |
    | `eventId`    | For eventsGet/Update/Delete       | Target event id.                                                                                              |
    | `body`       | For eventsInsert/Update, freebusy | Event resource `{summary,start,end,attendees}`, or freebusy request `{timeMin,timeMax,items}`.                |
  </Tab>

  <Tab title="Workspace builder (DSUL)">
    ## Workspace builder

    **Goal:** install the connector in a workspace, configure authentication and the agent allowlist, and call Google operations from your automations.

    ## Installation

    1. Go to **Apps** in your workspace
    2. Search for **Google Workspaces** and install it
    3. Open the **Configuration app** (the link auto-populated on install) to choose the auth mode, provide credentials, connect, and allow the agents that may call the connector

    ## Configuration

    | Field                 | Description                                                                                                                                                                      |
    | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | **Configuration app** | Auto-populated on install — open this link to configure authentication (mode + credentials), connect a Google account (OAuth modes), and manage the authorized-agents allowlist. |

    The configuration app drives everything; the app instance itself has no per-field credential form. From it you pick one of:

    | Auth mode      | What you provide                                                                                                                         | Best for                                                           |
    | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
    | `oauthCentral` | Nothing — just click **Connect**                                                                                                         | Workspaces on a platform where the admin set up the central client |
    | `oauth`        | Your own Google **Client ID + Secret** (redirect URI `<api-url>/workspaces/slug:<your-workspace>/webhooks/<app-instance>.oauthCallback`) | You manage your own Google OAuth app                               |
    | `jwt`          | A service-account **JSON key** (+ optional `subject` for domain-wide delegation)                                                         | Server-to-server, no interactive sign-in                           |
    | `accessToken`  | A pre-minted Google **access token**                                                                                                     | Short-lived / caller-managed tokens                                |

    <Note>
      Credentials are provisioned into the workspace's Secrets by the `onInstall` flow and resolved server-side. The agent allowlist (**Authorized agents**) gates which Agent Factory agents may call the MCP endpoint — see the *Agent builder* tab.
    </Note>

    ## Available Instructions

    Every instruction resolves credentials from the workspace configuration. Operations are grouped by Google product; the MCP server exposes the same operations behind the five entity tools (see the *Agent builder* tab).

    ### Drive

    | Instruction              | Description                                                                                                                                    | Returns                                                                                |
    | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
    | `driveList`              | List or search files and folders. Filter with `q` (Drive query syntax), paginate with `pageToken`, shape the payload with a `fields` selector. | `{ files: [{ id, name, mimeType, modifiedTime, … }], nextPageToken }`                  |
    | `driveGet`               | Fetch one file's metadata by `fileId`.                                                                                                         | A File resource `{ id, name, mimeType, parents, webViewLink, … }` (fields-selectable). |
    | `driveCreate`            | Create a file or folder from a `body` metadata object (`{ name, mimeType, parents }`).                                                         | The created File resource `{ id, name, mimeType, … }`.                                 |
    | `driveUpdate`            | Update file metadata or move it across folders with `addParents` / `removeParents`.                                                            | The updated File resource.                                                             |
    | `driveDelete`            | Permanently delete a file by `fileId`.                                                                                                         | Empty (HTTP 204).                                                                      |
    | `driveCopy`              | Duplicate a file by `fileId`; override metadata via `body`.                                                                                    | The new (copied) File resource `{ id, name, … }`.                                      |
    | `driveExport`            | Export a Google-native file (Doc/Sheet/Slide) to a `mimeType` (e.g. `application/pdf`).                                                        | The exported file bytes in the requested format.                                       |
    | `drivePermissionsList`   | List the sharing permissions on a file.                                                                                                        | `{ permissions: [{ id, type, role, emailAddress }] }`                                  |
    | `drivePermissionsCreate` | Share a file: `body` = `{ role, type, emailAddress }`.                                                                                         | The created Permission `{ id, type, role }`.                                           |
    | `drivePermissionsDelete` | Revoke a permission by `permissionId`.                                                                                                         | Empty (HTTP 204).                                                                      |

    ### Docs

    | Instruction       | Description                                                                                               | Returns                                               |
    | ----------------- | --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
    | `docsGet`         | Read a document's full content tree by `documentId`.                                                      | A Document resource `{ documentId, title, body, … }`. |
    | `docsCreate`      | Create a blank document; `body` = `{ title }`.                                                            | The created Document `{ documentId, title }`.         |
    | `docsBatchUpdate` | Apply an ordered list of edit requests (`body.requests[]`: insert text, format, tables, …) to a document. | `{ documentId, replies: [...] }`                      |

    ### Sheets

    | Instruction          | Description                                                                                               | Returns                                                                                |
    | -------------------- | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
    | `sheetsGet`          | Read spreadsheet structure and (optionally) grid data by `spreadsheetId`.                                 | A Spreadsheet resource `{ spreadsheetId, properties, sheets: [...], spreadsheetUrl }`. |
    | `sheetsCreate`       | Create a spreadsheet from a `body` resource (e.g. `{ properties: { title } }`).                           | The created Spreadsheet `{ spreadsheetId, spreadsheetUrl, sheets }`.                   |
    | `sheetsValuesGet`    | Read cell values in A1 `range`.                                                                           | `{ range, majorDimension, values: [[ … ]] }`                                           |
    | `sheetsValuesUpdate` | Overwrite cells in `range`; `body` = `{ values: [[ … ]] }`, with `valueInputOption` `RAW`/`USER_ENTERED`. | `{ spreadsheetId, updatedRange, updatedRows, updatedColumns, updatedCells }`           |
    | `sheetsValuesAppend` | Append rows after the last row of a table in `range`.                                                     | `{ spreadsheetId, tableRange, updates: { updatedRange, updatedRows, … } }`             |
    | `sheetsValuesClear`  | Clear cell values in `range` (keeps formatting).                                                          | `{ spreadsheetId, clearedRange }`                                                      |
    | `sheetsBatchUpdate`  | Apply structural edit requests (`body.requests[]`: add sheets, formatting, charts, …).                    | `{ spreadsheetId, replies: [...] }`                                                    |

    ### Gmail

    | Instruction           | Description                                                                                                  | Returns                                                               |
    | --------------------- | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- |
    | `gmailGetProfile`     | Resolve the connected account ("me" / "my email") in one call.                                               | `{ emailAddress, messagesTotal, threadsTotal, historyId }`            |
    | `gmailMessagesList`   | List/search message ids; filter with `q` (Gmail search syntax) and `labelIds`.                               | `{ messages: [{ id, threadId }], nextPageToken, resultSizeEstimate }` |
    | `gmailMessagesGet`    | Fetch one message by `id`; `format` controls verbosity (`minimal`/`full`/`metadata`/`raw`).                  | A Message resource `{ id, threadId, labelIds, snippet, payload, … }`. |
    | `gmailMessagesSend`   | Send an email; `body` = `{ to, subject, text\|html, cc, bcc, … }` as plain strings (server builds the MIME). | The sent Message `{ id, threadId, labelIds }`.                        |
    | `gmailMessagesModify` | Add/remove labels on a message; `body` = `{ addLabelIds, removeLabelIds }`.                                  | The updated Message `{ id, threadId, labelIds }`.                     |
    | `gmailMessagesTrash`  | Move a message to Trash by `id`.                                                                             | The trashed Message `{ id, threadId, labelIds }`.                     |
    | `gmailDraftsCreate`   | Create a draft; `body` like `messagesSend`.                                                                  | `{ id, message: { id, threadId } }`                                   |
    | `gmailLabelsList`     | List all labels in the mailbox.                                                                              | `{ labels: [{ id, name, type }] }`                                    |
    | `gmailThreadsGet`     | Fetch a full conversation thread by `id`.                                                                    | `{ id, historyId, messages: [ Message ] }`                            |

    ### Calendar

    | Instruction            | Description                                                                                                      | Returns                                                                         |
    | ---------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
    | `calendarEventsList`   | List events on `calendarId` (default `primary`) between `timeMin`/`timeMax`; `singleEvents` expands recurrences. | `{ items: [ Event ], nextPageToken, nextSyncToken }`                            |
    | `calendarEventsGet`    | Fetch one event by `eventId`.                                                                                    | An Event resource `{ id, summary, start, end, attendees, … }`.                  |
    | `calendarEventsInsert` | Create an event; `body` = `{ summary, start, end, attendees }`. `sendUpdates` notifies guests.                   | The created Event `{ id, htmlLink, start, end, … }`.                            |
    | `calendarEventsUpdate` | Update an event by `eventId` with a new `body`.                                                                  | The updated Event resource.                                                     |
    | `calendarEventsDelete` | Delete an event by `eventId`.                                                                                    | Empty (HTTP 204).                                                               |
    | `calendarCalendarList` | List the calendars the account can access.                                                                       | `{ items: [{ id, summary, accessRole, primary, … }] }`                          |
    | `calendarFreebusy`     | Query busy intervals; `body` = `{ timeMin, timeMax, items: [{ id }] }`.                                          | `{ timeMin, timeMax, calendars: { <calendarId>: { busy: [{ start, end }] } } }` |

    <Note>
      `Returns` shows the shape of the operation output (the underlying Google API resource). `calendarId` defaults to `primary` when omitted. Gmail send/draft bodies take plain strings (`to`, `subject`, `text`/`html`, optional `cc`, `bcc`, `replyTo`, `inReplyTo`, `threadId`) — the server builds and base64-encodes the MIME message itself.
    </Note>

    ## DSUL Examples

    **List the 10 most recently modified Drive files:**

    ```yaml theme={null}
    - Google Workspaces.driveList:
        q: "trashed = false"
        orderBy: modifiedTime desc
        pageSize: 10
        fields: "files(id,name,mimeType,modifiedTime)"
      output: files
    ```

    **Create a spreadsheet, then write a header row:**

    ```yaml theme={null}
    - Google Workspaces.sheetsCreate:
        body:
          properties:
            title: '{{reportName}}'
      output: sheet
    - Google Workspaces.sheetsValuesUpdate:
        spreadsheetId: '{{sheet.spreadsheetId}}'
        range: "Sheet1!A1:C1"
        valueInputOption: USER_ENTERED
        body:
          values:
            - ["Date", "Customer", "Amount"]
    ```

    **Send an email to the connected account ("send me a summary"):**

    ```yaml theme={null}
    - Google Workspaces.gmailGetProfile: {}
      output: profile
    - Google Workspaces.gmailMessagesSend:
        body:
          to: '{{profile.emailAddress}}'
          subject: 'Daily summary'
          text: '{{summaryText}}'
    ```

    **Create a calendar event with attendees:**

    ```yaml theme={null}
    - Google Workspaces.calendarEventsInsert:
        calendarId: primary
        sendUpdates: all
        body:
          summary: 'Project kickoff'
          start:
            dateTime: '2026-07-01T10:00:00+02:00'
          end:
            dateTime: '2026-07-01T11:00:00+02:00'
          attendees:
            - email: '{{attendeeEmail}}'
      output: event
    ```
  </Tab>
</Tabs>

***

## Error Handling

| HTTP code     | Meaning                                                                                                                                |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `400`         | Bad request — invalid parameters or malformed body (e.g. bad A1 range, invalid file metadata).                                         |
| `401`         | Unauthorized — the Google access token is missing, expired or revoked. The user must reconnect (OAuth modes).                          |
| `403`         | Forbidden — insufficient OAuth scope, the target API is not enabled in the Cloud project, or the account lacks access to the resource. |
| `404`         | Not found — the file, document, spreadsheet, message or event id does not exist or is not visible to the account.                      |
| `429`         | Rate limit / quota exceeded — back off and retry.                                                                                      |
| `500` / `503` | Google service error — transient; retry shortly, no reconnection needed.                                                               |

### Common Issues

**"This agent is not authorized to use this connector"** — The calling agent is not in the allowlist. Open the configuration app → **Authorized agents** → tick this agent (or enable **Allow all agents**) and Save.

**"The calling agent could not be identified"** — The MCP capability *Scope* does not declare `agent_id`, so Agent Factory never injects the agent identity. Set the Scope to `context_id,agent_id,user_id` on the capability, then allow the agent in the config app.

**"Google is not connected for this user"** — No per-user OAuth token. Open the configuration app (OAuth mode) and click **Connect**, or use the agent's connect flow.

**"Google token refresh failed … must reconnect"** — The stored refresh token was revoked or expired (Google invalidated it). The connection is dropped automatically; the user must reconnect from the config app.

**"Google OAuth is not configured"** — Neither a tenant OAuth client nor the central platform client is available. Set the OAuth client ID/secret in the config app, or ask the platform maintainer to provision the central OAuth client.

**Gmail send fails or arrives garbled** — Pass `to`, `subject`, `text`/`html` as plain strings in `body`. The server builds and base64-encodes the MIME message itself — never base64-encode the content yourself.

## External Resources

<CardGroup cols={2}>
  <Card title="Google Workspace APIs" icon="google" href="https://developers.google.com/workspace">
    Official reference for the Drive, Docs, Sheets, Gmail and Calendar REST APIs.
  </Card>

  <Card title="Tool Agents" icon="robot" href="/products/agent-factory/capabilities">
    Learn how Agent Factory agents consume MCP tools in Prisme.ai.
  </Card>
</CardGroup>
