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

# Connect Google Cloud Storage and Logging

> Set up a customer-owned Google service account, grant the right resource roles, and authorize Recursion's organization delegate.

Google Cloud Storage and Google Cloud Logging are separate integrations. You can connect the same user-managed Google service account to both, or use different accounts. **You need the service account email, not its JSON credentials, client ID, or private key.** Recursion uses short-lived credentials through a delegate for your organization.

> [!NOTE]
>
> An organization admin registers the connection in Recursion. A Google Cloud administrator must be able to manage the service account and grant IAM roles on the relevant projects and buckets.

## Prepare a service account

In **Integrations → Add integration**, choose **Google Cloud Storage** or **Google Cloud Logging** and enter an existing service account email, or create an account in a project you control:

```bash theme={"theme":"css-variables"}
gcloud iam service-accounts create recursion-reader --project=ACCOUNT_HOME_PROJECT
```

In the commands below, replace `SERVICE_ACCOUNT_EMAIL` with the exact email you enter in Recursion, whether it belongs to a new or existing account. Replace `ACCOUNT_HOME_PROJECT` with that account's project. The account's home project can differ from the projects containing your buckets or logs. Its Google IAM roles determine which resources it can reach. Review an existing account's roles before connecting it.

### Cloud Logging permissions

For each project whose logs the account should read, enable the API and grant both Logging Viewer and MCP Tool User:

```bash theme={"theme":"css-variables"}
gcloud services enable logging.googleapis.com --project=LOG_PROJECT
gcloud projects add-iam-policy-binding LOG_PROJECT \
  --member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
  --role=roles/logging.viewer --condition=None
gcloud projects add-iam-policy-binding LOG_PROJECT \
  --member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
  --role=roles/mcp.toolUser \
  --condition='title=logging-only,expression=resource.service == "logging.googleapis.com"'
```

The connection requests the `logging.read` OAuth scope. Logging Viewer excludes private Data Access audit logs; granting access to those requires a separate IAM decision.

### Cloud Storage permissions

For each project containing a bucket the account should use, enable the Cloud Storage API and grant MCP Tool User **on the project**. This gives the account `mcp.tools.call`, which Google's hosted MCP checks before Storage object permissions. Grant Storage object roles **on the bucket**:

```bash theme={"theme":"css-variables"}
gcloud services enable storage.googleapis.com --project=BUCKET_PROJECT
gcloud projects add-iam-policy-binding BUCKET_PROJECT \
  --member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
  --role=roles/mcp.toolUser \
  --condition='title=storage-only,expression=resource.service == "storage.googleapis.com"'
```

On each bucket the account should read, grant `roles/storage.objectViewer` to `SERVICE_ACCOUNT_EMAIL`. For a write grant that creates new objects, also grant `roles/storage.objectCreator` on that bucket. Use the [Google Cloud bucket IAM instructions](https://docs.cloud.google.com/storage/docs/access-control/using-iam-permissions) to add these bucket-level bindings.

The condition limits MCP Tool User to Cloud Storage. Overwriting existing objects needs additional object write permission. The Storage integration offers `read` and `write` access levels, requesting `devstorage.read_only` or `devstorage.read_write` respectively. The requested scope and the account's IAM roles both limit access. Grant only the buckets and actions this account needs. See Google's [Cloud Storage MCP permissions](https://docs.cloud.google.com/storage/docs/use-cloud-storage-mcp) and [Storage IAM roles](https://docs.cloud.google.com/storage/docs/access-control/iam-roles).

Bucket-level `roles/storage.objectViewer` lets the account list and read **objects in that bucket**. It does not grant `storage.buckets.list` on the project. To test bucket-level access, ask the agent to list objects in a known bucket by name, not to list every bucket in the project. Project-wide bucket discovery requires a separate project-level role containing `storage.buckets.list`; grant it only if that broader discovery is needed.

## Authorize Recursion's delegate

Register the service account in the console. Recursion prepares a delegate service account for your organization and returns its exact email and a grant command. Run the returned command with your Google Cloud administrator credentials. It has this form for **either** integration:

```bash theme={"theme":"css-variables"}
gcloud iam service-accounts add-iam-policy-binding \
  SERVICE_ACCOUNT_EMAIL \
  --member=serviceAccount:DELEGATE_EMAIL \
  --role=roles/iam.serviceAccountTokenCreator \
  --project=ACCOUNT_HOME_PROJECT --condition=None
```

Copy `DELEGATE_EMAIL` from your registration. Do not guess it or substitute a generic Recursion service account. This binding belongs on **your service account**, not on its project. Recursion's runtime service account has a separate platform-managed Token Creator binding on the delegate:

```text theme={"theme":"css-variables"}
Recursion's runtime service account → organization delegate → your service account → permitted projects and buckets
```

The same delegate can be trusted by the accounts used for both integrations. The IAM Credentials API must be enabled for token minting and Storage URL signing. Organization policies that restrict impersonation may require help from your Google Cloud administrator.

## Check the connection and grant it to an agent

1. In the connection setup, click **Verify trust** for Logging or **Check setup** for Storage to attempt a fresh token mint. The pending connection becomes active when the impersonation grant works. This proves **only** the delegate trust and token minting, not MCP Tool User or access to any log project or bucket. Allow time for Google IAM changes to propagate.
2. Open the agent's **Integrations** section, select the active connection and its access level, and save a new agent version. An existing session keeps its previous version until moved. A vault integration grant is also available when access must vary by session.
3. Start a session that reads a known log project or lists objects in a known bucket. A successful connection check alone does not prove resource access. The project or bucket named in a test does not narrow the account's IAM access.

Storage tools use Google's hosted Storage MCP endpoint for browsing and small operations. For large objects, the integration can issue a signed URL for one GET or PUT, valid for 15 minutes. The URL itself grants temporary access, so handle it as a credential. Uploads use one PUT request; resumable uploads are not supported. Logging and Storage use separate connections and OAuth scopes even when they share a service account.

## If a Storage tool returns HTTP 403

An active connection can still get a 403 from Google's `tools/call`. Check the service account's IAM in this order:

1. Confirm `roles/mcp.toolUser` on the **bucket's project**, with a condition that permits `storage.googleapis.com`, and confirm the Cloud Storage API is enabled there. Without `mcp.tools.call`, every hosted Storage MCP tool can fail even when bucket object roles are present.
2. Confirm the account has the object permission for the requested action on the **target bucket**: `roles/storage.objectViewer` for object listing and reads, or an appropriate write role for uploads.
3. Check which tool failed. Listing all buckets in a project needs `storage.buckets.list` at project scope. A bucket-only object role does not grant it. Test object listing against a known bucket instead.

After an IAM change, allow time for propagation and rerun the agent's Storage call. A generic `tools/call` 403 alone does not identify which of these permissions is missing.
