From 2aadcbd530864df4f574edabf0ad0e1b5b09e710 Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 11:17:59 -0500 Subject: [PATCH 01/12] docs(mcp): complete the Gemini Enterprise guide from end-to-end testing The merged guide stops short of a working setup. Running it against a live Gemini Enterprise app and the C1 gateway surfaced two required steps it never mentions, and a full review of the page found contradictions between sections written before and after that testing. The two missing steps: - Each user authorizes the connector themselves, from the Connectors menu in the web app message box. Enabling actions as an administrator authorizes nobody, and until a user authorizes there the assistant answers that it has no C1 integration while the connector reads Active. This was the last blocker and it is invisible from the admin console. - Reload custom actions takes about 30 seconds and holds the request open, so the action table stays empty until it finishes. Leaving early looks like a silent failure. Corrections from the review: - The Agent Registry section pointed at the import flow that this same page says breaks tool discovery. Registering the server in the catalog is now separated from importing it as a connector, with a warning against the import. - The client metadata document is not available on any tenant yet, so the page no longer frames its 404 as a per-tenant rollout lag. A reader hitting it has a real blocker, not a local mistake. - Enabling actions no longer claims users can call them, since they cannot until they authorize. - The stage table claimed creating the data store and enabling APIs depend on nothing, contradicting the roles table two sections down. Both now name the role. - Dropped "in C1 testing" hedging on four established facts, settled the client secret on the single value Google documents, scoped the app location to the optional path that actually uses it, and moved the per-user caveat from Warning to Note, since it is not irreversible. Verified: zero em dashes, no banned words, all anchors and internal links resolve, all component tags balanced, placeholder conventions consistent. Co-Authored-By: Claude Opus 5 --- .../admin/mcp-server/gemini-enterprise.mdx | 66 ++++++++++++++----- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index ce884a26..d9c61cf2 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -21,10 +21,10 @@ Setup spans two products. Two stages depend on someone other than you, so line t | Stage | Where | Depends on | | :--- | :--- | :--- | | [Collect the values you'll reuse](#collect-the-values-youll-reuse) | C1 and Google Cloud | Nothing | -| [Enable the Google Cloud APIs](#enable-the-google-cloud-apis) | Google Cloud | A project editor | +| [Enable the Google Cloud APIs](#enable-the-google-cloud-apis) | Google Cloud | `roles/serviceusage.serviceUsageAdmin` | | [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors) | Google Cloud | An **organization** policy administrator | | [Get the OAuth client ID](#get-the-oauth-client-id) | C1 | Nothing | -| [Create the data store](#create-the-data-store) | Gemini Enterprise | Nothing | +| [Create the data store](#create-the-data-store) | Gemini Enterprise | `roles/discoveryengine.editor` | | [Enable the actions](#enable-the-actions) | Gemini Enterprise | Tool access already granted in C1 | | [Verify the connection](#verify-the-gemini-enterprise-connection) | Gemini Enterprise and C1 | A user with C1 tool access | @@ -35,7 +35,7 @@ Confirm all of these before you start. The organization policy change in particu - AI access management must be enabled for your tenant. See [Enable AI access management](/product/admin/enable-ai-access-management). - **The users who will use Gemini Enterprise need C1 tool access already.** Their access profiles determine which tools they can call, and a user with no toolset sees no tools at all. See [Tools and toolsets](/product/admin/tools-and-toolsets). - A Google Cloud project with a Gemini Enterprise app already created. See Google's [Create a Gemini Enterprise app](https://docs.cloud.google.com/gemini/enterprise/docs/create-app) documentation. -- Someone who holds `roles/orgpolicy.policyAdmin`. Project **Owner** does not include it. In C1 testing, an organization-level grant was needed before the policy change below would apply. +- Someone who holds `roles/orgpolicy.policyAdmin` at the organization level. Project **Owner** does not include it, and a project-level grant is not sufficient for the policy change below. - **Optional.** The [gcloud CLI](https://cloud.google.com/sdk/docs/install), authenticated with `gcloud auth login`, if you prefer the command line for the Google Cloud steps. ### Required roles @@ -67,14 +67,14 @@ gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \ ## Collect the values you'll reuse -Every step below reuses these four values. Collect them once. +The steps below reuse these values. Collect them once. | Value | Where to get it | Example | | :--- | :--- | :--- | | **Tenant** | The subdomain of your C1 URL. It is also the prefix of your MCP server URL. | `acme` | | **MCP server URL** | In C1, open your user profile menu and select **AI & API** > **AI connections**. Copy the URL shown at the top of the page. | `https://acme-mcp.conductor.one/v1` | | **Project ID** | The Google Cloud console project picker, or `gcloud config get-value project`. | `acme-gemini` | -| **App location** | At the top of the Gemini Enterprise **Apps** page, next to **Current location**. | `global` | +| **App location** | At the top of the Gemini Enterprise **Apps** page, next to **Current location**. Needed only for [Optional: Govern the server through Agent Registry](#optional-govern-the-server-through-agent-registry). | `global` | Your OAuth endpoints follow from the tenant. Confirm them against your tenant's published metadata: @@ -103,7 +103,7 @@ Enable all six. In the console, go to **APIs & Services** > **Library**, search | Organization Policy API | `orgpolicy.googleapis.com` | Required to read or change the policy in the next section | -Google's setup documentation for custom MCP servers does not list any APIs. In C1 testing, tool discovery failed until `connectors.googleapis.com`, `integrations.googleapis.com`, and `secretmanager.googleapis.com` were enabled, so enable all six. +Google's setup documentation for custom MCP servers does not list any APIs. Tool discovery fails until `connectors.googleapis.com`, `integrations.googleapis.com`, and `secretmanager.googleapis.com` are enabled, so enable all six. To enable them from the command line instead: @@ -217,7 +217,7 @@ curl -s https://YOUR_TENANT.conductor.one/auth/v1/client-metadata/gemini-enterpr ``` -A `404` means your tenant is not yet running a release that publishes this document. [Contact the C1 support team](mailto:support@c1.ai) to confirm availability for your tenant before continuing. +**This document is not available yet.** Every tenant returns a `404` from this URL until C1 ships it. [Contact the C1 support team](mailto:support@c1.ai) to confirm timing for your tenant before you continue, because the rest of this page depends on having a client ID. @@ -230,10 +230,18 @@ Do not register a client through C1's dynamic registration endpoint for this int Connect the C1 MCP gateway to your Gemini Enterprise app. + +This section and the next have no `gcloud` or REST equivalent. The public Discovery Engine API rejects the parameters the console itself writes for a custom MCP connector, and the method behind **Reload custom actions** is not exposed on the public endpoint. Creating the data store, discovering actions, and enabling actions are console-only. + + The data connector name generates an ID that cannot be changed later. Choose it before you begin, and keep it short and lowercase with hyphens, such as `c1-mcp-gateway`. + +Use the **Custom MCP Server** card, not a server imported from Agent Registry. A connector created from a registry import fails tool discovery with `Failed to reload custom actions` and a `FAILED_PRECONDITION` error, while an otherwise identical connector created from the Custom MCP Server card completes normally. + + In the Google Cloud console, open **Gemini Enterprise** and select your app. @@ -258,7 +266,7 @@ Complete the fields. The third column is where this form most often goes wrong. | **MCP Server URL** | `https://-mcp.conductor.one/v1` | Ends with `/v1`. | | **Authorization URL** | `https://.conductor.one/auth/v1/authorize` | No trailing parameters. | | **Authorization URL Parameters** | `&resource=https://-mcp.conductor.one/v1` | Required. C1 binds tokens to a resource, so omitting this yields a token your MCP endpoint rejects. | -| **Token URL** | `https://.conductor.one/auth/v1/token` | Nothing | +| **Token URL** | `https://.conductor.one/auth/v1/token` | No special handling | | **Client ID** | Your client metadata document URL | The full `https://` URL, not a bare identifier. | | **Client Secret** | `none` | PKCE needs no secret, but the console requires a value in this field, and Google's documentation says to enter `none`. C1 never reads it. | | **Scopes** | `openid profile email offline_access` | Space-separated, not comma-separated. | @@ -283,10 +291,12 @@ The form shows **Successfully logged in** after you authorize, and the connector ## Enable the actions -Gemini Enterprise calls MCP tools *actions*, and imports every one of them turned off. Turn on only the actions your users need: a data store supports a maximum of 100 enabled actions, and a shorter list makes the agent's tool selection more accurate. +Gemini Enterprise calls MCP tools *actions*, and imports every one of them turned off. Enable them on the data connector, not on the app's **Actions** page, which only redirects you here. Turn on only the actions your users need: a data store supports a maximum of 100 enabled actions, and a shorter list makes the agent's tool selection more accurate. Wait for the connector state to reach **Active** before you start. The reload fails while the connector is still creating. + +**Reload custom actions takes about 30 seconds.** Gemini Enterprise calls your MCP server for its tool list and holds the request open while it waits. The table stays empty until it finishes, which looks like a silent failure if you navigate away early. Wait for the **Custom actions reloaded** confirmation. @@ -304,7 +314,7 @@ Select **Enable actions**. -The actions you selected are now available to users in your Gemini Enterprise app. +The actions you selected are now enabled on the connector. No one can call them yet: each user must authorize the connector themselves, which is the first part of [Verify the Gemini Enterprise connection](#verify-the-gemini-enterprise-connection). ## Verify the Gemini Enterprise connection @@ -312,10 +322,23 @@ Seeing actions listed does not confirm your credentials work. You confirm the se -Open your Gemini Enterprise app as an end user who has C1 tool access, and ask a question that needs a C1 tool, such as "Who has access to" followed by an application you have connected to C1. +Open your Gemini Enterprise web app as an end user who has C1 tool access. -Authorize the connection when prompted. Sign in through your identity provider and approve. +In the message box, select the **Connectors** icon. Your connector is listed with an **Authorize** link beside it. + + +Select **Authorize**, sign in through your identity provider, and approve. The connector then shows a toggle, switched on. + + +Every user does this once, for themselves. Enabling actions as an administrator authorizes nobody. Until a user authorizes here, the assistant answers that it has no C1 integration, even though the actions are enabled and the connector is **Active**. + + + +Ask a question that needs a C1 tool, naming the connector, such as "Using the C1 connector, list the access reviews in C1." + + +The assistant names the action it wants to call and waits. Select **Send** to confirm it. In C1, go to **AI access management** > **AI clients**. The Gemini Enterprise client appears, bound to that user. Users can see their own connections under their profile menu at **AI & API** > **AI connections**. @@ -337,13 +360,16 @@ Agent Registry gives your organization a catalog of approved MCP servers, and Ag Adding them does not change how these tool calls are governed. Google's documentation states that traffic to MCP servers added as a data connector does not pass through Agent Gateway, and Agent Gateway policies do not apply to it. C1 governs the tool calls. Use this path when you want the C1 gateway listed in a shared catalog alongside your other approved servers, not to add enforcement. -If you want that catalog entry, follow Google's own documentation, which stays current with the regional rules and command surface: + +Register the server in the catalog, but do not import it as your data connector. Importing from Agent Registry produces a connector whose tool discovery fails. Create the connector from the **Custom MCP Server** card as described in [Create the data store](#create-the-data-store), and treat the catalog entry as a separate, listing-only exercise. + + +For the catalog entry, follow Google's own documentation, which stays current with the regional rules and command surface: - [Register MCP servers in Agent Registry](https://docs.cloud.google.com/agent-registry/register-mcp-servers) - [Set up an Agent Gateway](https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/gateways/set-up-agent-gateway) -- [Import MCP servers from Agent Registry](https://docs.cloud.google.com/gemini/enterprise/docs/connectors/custom-mcp-server/import-govern-mcp-server-agent-registry) -Three things that are easy to miss on that path: +Four things that are easy to miss on that path: - **Your app, gateway, and registry regions must align**, and Google's import documentation has the current table. A `global` or `us` app pairs with a `us-central1` gateway; an `eu` app pairs with `europe-west1`. When they do not align, the server never appears in the data store list and no error explains why. - **Each app must be pointed at the gateway explicitly**, under **Security** > **Configuration** > **Agent Gateway configuration** in the app. Creating a gateway is not enough, and until an app is bound to one, no registered server appears in its data store list. @@ -359,16 +385,20 @@ Three things that are easy to miss on that path: | `PERMISSION_DENIED` on `gcloud services enable` | The caller lacks `roles/serviceusage.serviceUsageAdmin` on the project. | Grant it. See [Required roles](#required-roles). | | `404` on the client metadata URL | Your tenant is not running a release that publishes the Gemini Enterprise client document. | [Contact the C1 support team](mailto:support@c1.ai). | | **We encountered some problems during authentication** | The client ID is wrong, or the sign-in window was closed or blocked. | Confirm the client ID resolves, allow popups for the console, and retry **Verify Auth**. | -| The form will not accept an empty **Client Secret** | The console treats the field as required. | Enter any placeholder. C1 never reads it. | +| The form will not accept an empty **Client Secret** | The console treats the field as required. | Enter `none`, as in [Create the data store](#create-the-data-store). C1 never reads it. | +| **Failed to reload custom actions** on a connector imported from Agent Registry | Registry-imported connectors fail discovery with `FAILED_PRECONDITION`. | Recreate the data store from the **Custom MCP Server** card. See [Create the data store](#create-the-data-store). | | **Failed to reload custom actions** | The connector is still creating, or the tool action APIs are not enabled. | Wait for **Active**, then confirm `connectors.googleapis.com`, `integrations.googleapis.com`, and `secretmanager.googleapis.com` are enabled. | -| **Reload custom actions** succeeds but the list is empty | The authorizing user has no C1 toolset, so C1 exposes no tools to them. | Assign an access profile that includes the tools you expect. See [Tools and toolsets](/product/admin/tools-and-toolsets). | +| **Reload custom actions** shows no error and no actions | Most often the reload is still running. It takes about 30 seconds. | Wait for the **Custom actions reloaded** confirmation, then reload the page. | +| The action list stays empty after the reload finishes | C1 returned an empty tool list for the authorizing user, which happens when that user has no toolset. | Assign the authorizing user an access profile that includes the tools you expect, then reload again. See [Tools and toolsets](/product/admin/tools-and-toolsets). | +| The assistant answers that it has "no ConductorOne integration" | The user has not authorized the connector in the web app. Enabling actions authorizes nobody. | In the message box, open **Connectors** and select **Authorize** beside your connector. See [Verify the Gemini Enterprise connection](#verify-the-gemini-enterprise-connection). | +| The assistant picks a web search instead of a C1 action | No enabled action matches the request, so nothing is callable. | Enable the actions the request needs, and name the connector in the prompt. | | A user's tool calls are denied while another user's succeed | C1 is enforcing that user's access profile. This is expected behavior. | Check the denial reason in the audit log. See [Audit AI tool usage](/product/admin/audit-ai-tool-usage). | | Authorization works, then breaks about an hour later | The connector uses a dynamically registered client whose secret expired. | Use the C1-published client ID. See [Get the OAuth client ID](#get-the-oauth-client-id). | | Tool calls fail immediately after a working **Verify Auth** | The token is not bound to your MCP endpoint. | Set **Authorization URL Parameters** to `&resource=https://-mcp.conductor.one/v1`. | | `failed to fetch client metadata` | C1 fetches its own client metadata document over the public internet, and your tenant hostname does not resolve publicly. | This affects self-hosted installations rather than C1 cloud tenants. [Contact the C1 support team](mailto:support@c1.ai). | -The data connector name cannot be changed after creation. To correct an authentication value, edit the existing connector's settings rather than recreating it. To change the name, create a new data store and remove the old one. +To correct an authentication value, edit the existing connector's settings rather than recreating it. The connector name cannot be changed after creation, as noted in [Create the data store](#create-the-data-store), so changing it means creating a new data store and removing the old one. ## What this integration cannot do From 526aba666e4ace23543dad87cb3209d7d379e293 Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 11:21:48 -0500 Subject: [PATCH 02/12] docs(mcp): say who hosts the client metadata document, and how The guide named a single client ID, the C1-hosted one, which has not shipped. That left the reader with no way to finish and no explanation of why the value has to come from anywhere in particular. State the constraint plainly: Google publishes no client metadata document for Gemini Enterprise. /.well-known/oauth-client-metadata returns 404 on vertexaisearch.cloud.google.com, cloud.google.com, discoveryengine.googleapis.com, and accounts.google.com, and Google's own instructions are to register the MCP server as an OAuth client with your identity provider. Something has to host the document, so the section now presents both options in a table with their status, and the self-hosted path is the one that works today. The self-hosting steps go in an accordion rather than the main flow, since they become unnecessary once C1 hosts the document. A second accordion covers the two organization policies that block publishing it: domain restricted sharing, which rejects allUsers with HTTP 412 and needs an allowAll override rather than an allUsers entry, and public access prevention. The domain restricted sharing override is project-wide rather than bucket-scoped, so it carries a warning to publish from a dedicated project and remove the override once C1 hosts the document. Also moved the outbound-hostname aside into an accordion, since it applies to a minority of organizations and interrupted the org policy procedure. Co-Authored-By: Claude Opus 5 --- .../admin/mcp-server/gemini-enterprise.mdx | 94 ++++++++++++++++--- 1 file changed, 79 insertions(+), 15 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index d9c61cf2..09d296a1 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -189,9 +189,8 @@ Re-run the `describe` command above. The effective policy reports `enforce: fals Allow several minutes for the change to propagate. Until it does, the console returns the same denial message, so a failure immediately after you apply the policy does not mean the policy is wrong. -### Optional: Allow the C1 hostnames - -If your organization restricts which external hosts a data connector may reach, it enforces `constraints/discoveryengine.allowedEgressFqdns`. Check it the same way: + +Some organizations enforce `constraints/discoveryengine.allowedEgressFqdns`, which limits the hosts a data connector may reach. Check it the same way: ```bash gcloud org-policies describe discoveryengine.allowedEgressFqdns \ @@ -199,33 +198,98 @@ gcloud org-policies describe discoveryengine.allowedEgressFqdns \ ``` If it is set, add the two hostnames your tenant uses, `-mcp.conductor.one` and `.conductor.one`. Use hostnames only, not full URLs. + ## Get the OAuth client ID -Gemini Enterprise authenticates each user to C1 with the OAuth 2.0 authorization code flow. It needs an OAuth client that already exists, because it does not register one itself. - -C1 publishes a client metadata document for Gemini Enterprise. Its URL is your client ID: +Gemini Enterprise authenticates each user to C1 with the OAuth 2.0 authorization code flow, and it needs an OAuth client that already exists. It does not register one itself, and it does not publish a client identity you can point at. -```text -https://.conductor.one/auth/v1/client-metadata/gemini-enterprise -``` +Neither does Google. There is no Google-hosted client metadata document for Gemini Enterprise: `/.well-known/oauth-client-metadata` returns `404` on `vertexaisearch.cloud.google.com`, `cloud.google.com`, `discoveryengine.googleapis.com`, and `accounts.google.com`. Google's own instructions are to register the MCP server as an OAuth client with your identity provider and take a client ID from it. -Confirm it resolves before you continue. This returns JSON with a `client_id` field matching the URL you requested: +So the document has to be hosted somewhere. You have two options. -```bash -curl -s https://YOUR_TENANT.conductor.one/auth/v1/client-metadata/gemini-enterprise -``` +| Option | Client ID | Status | +| :--- | :--- | :--- | +| C1 hosts it | `https://.conductor.one/auth/v1/client-metadata/gemini-enterprise` | Not available yet | +| You host it | The URL you publish it at | Works today | -**This document is not available yet.** Every tenant returns a `404` from this URL until C1 ships it. [Contact the C1 support team](mailto:support@c1.ai) to confirm timing for your tenant before you continue, because the rest of this page depends on having a client ID. +The C1-hosted document has not shipped. Every tenant returns a `404` from that URL until it does. [Contact the C1 support team](mailto:support@c1.ai) to confirm timing, and until then host the document yourself. +Whichever you use, confirm the URL resolves before you continue. It returns JSON whose `client_id` matches the URL you requested: + +```bash +curl -s https://YOUR_CLIENT_METADATA_URL +``` + This client has no secret, so nothing expires and nothing needs rotating. Configure it once and it keeps working. -Do not register a client through C1's dynamic registration endpoint for this integration. An unapproved dynamic registration's secret expires one hour after it is issued, and rotating it preserves the original expiry rather than extending it, so the connector fails at its first token refresh. +Do not register a client through C1's dynamic registration endpoint instead. An unapproved dynamic registration's secret expires one hour after it is issued, and rotating it preserves the original expiry rather than extending it, so the connector fails at its first token refresh. + + +Publish this JSON at any public HTTPS URL you control. The `client_id` inside the document must exactly equal the URL it is served from, and `redirect_uris` must contain Google's redirect endpoint verbatim. + +```json +{ + "client_id": "https:///gemini-enterprise-oauth-client.json", + "client_name": "Gemini Enterprise", + "client_uri": "https://cloud.google.com/gemini/enterprise", + "redirect_uris": ["https://vertexaisearch.cloud.google.com/oauth-redirect"], + "grant_types": ["authorization_code", "refresh_token"], + "response_types": ["code"], + "token_endpoint_auth_method": "none" +} +``` + +C1 fetches this document over the public internet, so it must be reachable without authentication. A Cloud Storage bucket works: + +```bash +gcloud storage buckets create gs://YOUR_BUCKET --project=YOUR_PROJECT_ID --location=us-central1 --uniform-bucket-level-access +``` + +```bash +gcloud storage cp gemini-enterprise-oauth-client.json gs://YOUR_BUCKET/ +``` + +```bash +gcloud storage buckets add-iam-policy-binding gs://YOUR_BUCKET --member=allUsers --role=roles/storage.objectViewer +``` + +The object is then served at `https://storage.googleapis.com/YOUR_BUCKET/gemini-enterprise-oauth-client.json`, which is the value you use as the client ID. Confirm it returns your JSON before continuing. + +Two organization policies can block that public binding. See **Allow public access to the document** below. + + + +Both of these are separate from the constraint in [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors), and both need `roles/orgpolicy.policyAdmin`. + +**Domain restricted sharing.** If `constraints/iam.allowedPolicyMemberDomains` is enforced, granting `allUsers` fails with: + +```text +HTTPError 412: One or more users named in the policy do not belong to a permitted customer. +``` + +The constraint does not accept `allUsers` as an allowed value, so the override has to permit all values. Save this as `drs.yaml` and apply it with `gcloud org-policies set-policy drs.yaml`: + +```yaml +name: projects/YOUR_PROJECT_ID/policies/iam.allowedPolicyMemberDomains +spec: + rules: + - allowAll: true +``` + + +This override is project-wide, not bucket-scoped. Any resource in the project can then be shared publicly. Publish the document from a project dedicated to it rather than one holding other data, and remove the override once C1 hosts the document for you. + + +**Public access prevention.** If `constraints/storage.publicAccessPrevention` is enforced, the binding is refused regardless. Check both with `gcloud org-policies describe --project=YOUR_PROJECT_ID --effective`. + + + ## Create the data store Connect the C1 MCP gateway to your Gemini Enterprise app. From 77d5aaef77cefad5c54e002848a4685f2f54feed Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 11:24:21 -0500 Subject: [PATCH 03/12] docs(mcp): name Google as the party that should publish the document The hosting options read as a choice between C1 and the customer, which frames a workaround as the design. A client metadata document describes a client, so the client's own vendor is the party whose publication of it carries weight. Google does not publish one for Gemini Enterprise today, and both of the other options exist only because of that gap. The options table now leads with Google and marks it the outcome to prefer, lists self-hosting as what works today, and lists the C1-hosted document as not yet available. The note says plainly that the C1 document is a stopgap rather than the end state, and tells the reader to switch to Google's URL and retire whatever they were hosting once Google publishes one. Also generalized the domain restricted sharing warning, which told the reader to remove the override once C1 hosts the document. The override should come out whenever they stop hosting, whichever way that happens. Co-Authored-By: Claude Opus 5 --- product/admin/mcp-server/gemini-enterprise.mdx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index 09d296a1..14b08691 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -204,17 +204,20 @@ If it is set, add the two hostnames your tenant uses, `-mcp.conduct Gemini Enterprise authenticates each user to C1 with the OAuth 2.0 authorization code flow, and it needs an OAuth client that already exists. It does not register one itself, and it does not publish a client identity you can point at. -Neither does Google. There is no Google-hosted client metadata document for Gemini Enterprise: `/.well-known/oauth-client-metadata` returns `404` on `vertexaisearch.cloud.google.com`, `cloud.google.com`, `discoveryengine.googleapis.com`, and `accounts.google.com`. Google's own instructions are to register the MCP server as an OAuth client with your identity provider and take a client ID from it. +Google is the party that should publish that document, since Gemini Enterprise is the client it describes. Today it does not: `/.well-known/oauth-client-metadata` returns `404` on `vertexaisearch.cloud.google.com`, `cloud.google.com`, `discoveryengine.googleapis.com`, and `accounts.google.com`. Google's instructions are to register the MCP server as an OAuth client with your identity provider and take a client ID from it. -So the document has to be hosted somewhere. You have two options. +Until Google publishes one, somebody else has to host it on Google's behalf. -| Option | Client ID | Status | +| Who hosts it | Client ID | Status | | :--- | :--- | :--- | -| C1 hosts it | `https://.conductor.one/auth/v1/client-metadata/gemini-enterprise` | Not available yet | -| You host it | The URL you publish it at | Works today | +| Google | A Google-published URL | Not published. This is the outcome to prefer | +| You | The URL you publish it at | Works today | +| C1 | `https://.conductor.one/auth/v1/client-metadata/gemini-enterprise` | Not available yet | -The C1-hosted document has not shipped. Every tenant returns a `404` from that URL until it does. [Contact the C1 support team](mailto:support@c1.ai) to confirm timing, and until then host the document yourself. +Host the document yourself for now. The C1-hosted document has not shipped, so every tenant returns a `404` from that URL, and it is a stopgap rather than the end state: a client identity carries the most weight when the client's own vendor publishes it. [Contact the C1 support team](mailto:support@c1.ai) for timing. + +When Google publishes a client metadata document for Gemini Enterprise, use that URL as the client ID and retire whatever you were hosting. Whichever you use, confirm the URL resolves before you continue. It returns JSON whose `client_id` matches the URL you requested: @@ -283,7 +286,7 @@ spec: ``` -This override is project-wide, not bucket-scoped. Any resource in the project can then be shared publicly. Publish the document from a project dedicated to it rather than one holding other data, and remove the override once C1 hosts the document for you. +This override is project-wide, not bucket-scoped. Any resource in the project can then be shared publicly. Publish the document from a project dedicated to it rather than one holding other data, and remove the override as soon as you stop hosting the document. **Public access prevention.** If `constraints/storage.publicAccessPrevention` is enforced, the binding is refused regardless. Check both with `gcloud org-policies describe --project=YOUR_PROJECT_ID --effective`. From 8f441e08ff09ad6ea930280b9d29811c039b15ab Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 11:57:15 -0500 Subject: [PATCH 04/12] docs(mcp): correct the required APIs and fix the client ID walkthrough Retested the API list from a clean state instead of carrying it forward. Only discoveryengine and orgpolicy are required. With connectors, integrations, secretmanager, and iam all disabled, a new data connector was created, authorized, activated, tool-discovered, and called successfully, and the role commands in the guide still worked. Disabling orgpolicy is the one case that fails, with SERVICE_DISABLED. The self-hosting walkthrough could not be completed as written: the JSON template's client_id used a placeholder domain that the Cloud Storage steps below it never produce, the reader was never told what filename to save the file as before a command referenced that name, and the verification curl came before the steps that create the document. Also documents the pricing step in the create flow, which the console requires and the guide skipped, adds the missing override for storage.publicAccessPrevention, and notes that org policy changes propagate in both directions. Co-Authored-By: Claude Opus 5 --- .../admin/mcp-server/gemini-enterprise.mdx | 97 +++++++++++-------- 1 file changed, 58 insertions(+), 39 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index 14b08691..120f7bee 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -91,19 +91,15 @@ Read two fields from that response: ## Enable the Google Cloud APIs -Enable all six. In the console, go to **APIs & Services** > **Library**, search for the API by the name in the first column, and select **Enable**. The service ID is the identifier you use with the `gcloud` CLI. +Enable both. In the console, go to **APIs & Services** > **Library**, search for the API by the name in the first column, and select **Enable**. The service ID is the identifier you use with the `gcloud` CLI. | API to enable | Service ID | Why | | :--- | :--- | :--- | -| Discovery Engine API | `discoveryengine.googleapis.com` | Backs Gemini Enterprise apps and data stores | -| Connectors API | `connectors.googleapis.com` | Backs the tool actions a data connector exposes | -| Application Integration API | `integrations.googleapis.com` | Backs the tool actions a data connector exposes | -| Secret Manager API | `secretmanager.googleapis.com` | Stores the connector's OAuth credentials | -| Identity and Access Management (IAM) API | `iam.googleapis.com` | Resolves the roles above | +| Discovery Engine API | `discoveryengine.googleapis.com` | Backs Gemini Enterprise apps, data stores, and tool discovery | | Organization Policy API | `orgpolicy.googleapis.com` | Required to read or change the policy in the next section | -Google's setup documentation for custom MCP servers does not list any APIs. Tool discovery fails until `connectors.googleapis.com`, `integrations.googleapis.com`, and `secretmanager.googleapis.com` are enabled, so enable all six. +Google's setup documentation for custom MCP servers does not list any APIs, so this list was established by testing, and it is deliberately short. The Connectors, Application Integration, Secret Manager, and IAM APIs are **not** required. With all four disabled, creating the data connector, authorizing it, discovering tools, calling them, and running the role commands above all succeed. To enable them from the command line instead: @@ -111,10 +107,6 @@ To enable them from the command line instead: ```bash gcloud services enable \ discoveryengine.googleapis.com \ - connectors.googleapis.com \ - integrations.googleapis.com \ - secretmanager.googleapis.com \ - iam.googleapis.com \ orgpolicy.googleapis.com \ --project=YOUR_PROJECT_ID ``` @@ -125,7 +117,7 @@ To confirm which APIs are enabled on the project: gcloud services list --enabled --project=YOUR_PROJECT_ID ``` -Your project can now create data connectors and expose their tool actions. +Your project can now create custom MCP data connectors. ## Allow custom MCP data connectors @@ -204,13 +196,13 @@ If it is set, add the two hostnames your tenant uses, `-mcp.conduct Gemini Enterprise authenticates each user to C1 with the OAuth 2.0 authorization code flow, and it needs an OAuth client that already exists. It does not register one itself, and it does not publish a client identity you can point at. -Google is the party that should publish that document, since Gemini Enterprise is the client it describes. Today it does not: `/.well-known/oauth-client-metadata` returns `404` on `vertexaisearch.cloud.google.com`, `cloud.google.com`, `discoveryengine.googleapis.com`, and `accounts.google.com`. Google's instructions are to register the MCP server as an OAuth client with your identity provider and take a client ID from it. +C1 does not hand out an opaque client ID from a registration form. Instead, the client ID **is** a URL: it points at a small public JSON file describing the client, called a *Client ID Metadata Document*. C1 fetches that URL to learn who the client is, which means someone has to host the document. -Until Google publishes one, somebody else has to host it on Google's behalf. +Google is the party that should host it, since Gemini Enterprise is the client it describes. Today it does not, and Google's own instructions are to register the MCP server as an OAuth client with your identity provider and take a client ID from it. Until Google publishes a document, somebody else has to host one on Google's behalf. | Who hosts it | Client ID | Status | | :--- | :--- | :--- | -| Google | A Google-published URL | Not published. This is the outcome to prefer | +| Google | A Google-published URL | Not published. The preferred outcome | | You | The URL you publish it at | Works today | | C1 | `https://.conductor.one/auth/v1/client-metadata/gemini-enterprise` | Not available yet | @@ -220,12 +212,6 @@ Host the document yourself for now. The C1-hosted document has not shipped, so e When Google publishes a client metadata document for Gemini Enterprise, use that URL as the client ID and retire whatever you were hosting. -Whichever you use, confirm the URL resolves before you continue. It returns JSON whose `client_id` matches the URL you requested: - -```bash -curl -s https://YOUR_CLIENT_METADATA_URL -``` - This client has no secret, so nothing expires and nothing needs rotating. Configure it once and it keeps working. @@ -234,11 +220,13 @@ Do not register a client through C1's dynamic registration endpoint instead. An -Publish this JSON at any public HTTPS URL you control. The `client_id` inside the document must exactly equal the URL it is served from, and `redirect_uris` must contain Google's redirect endpoint verbatim. +Publish this JSON at any public HTTPS URL you control. Two fields are unforgiving: `client_id` must exactly equal the URL the document is served from, and `redirect_uris` must contain Google's redirect endpoint verbatim. + +Save the file as `gemini-enterprise-oauth-client.json`. The Cloud Storage commands below serve it at `https://storage.googleapis.com/YOUR_BUCKET/gemini-enterprise-oauth-client.json`, so set `client_id` to exactly that, with your own bucket name: ```json { - "client_id": "https:///gemini-enterprise-oauth-client.json", + "client_id": "https://storage.googleapis.com/YOUR_BUCKET/gemini-enterprise-oauth-client.json", "client_name": "Gemini Enterprise", "client_uri": "https://cloud.google.com/gemini/enterprise", "redirect_uris": ["https://vertexaisearch.cloud.google.com/oauth-redirect"], @@ -248,10 +236,13 @@ Publish this JSON at any public HTTPS URL you control. The `client_id` inside th } ``` -C1 fetches this document over the public internet, so it must be reachable without authentication. A Cloud Storage bucket works: +C1 fetches this document over the public internet, so it must be reachable without authentication. A Cloud Storage bucket works. Replace `YOUR_BUCKET` with a bucket name you choose, which must be globally unique across all of Cloud Storage: ```bash -gcloud storage buckets create gs://YOUR_BUCKET --project=YOUR_PROJECT_ID --location=us-central1 --uniform-bucket-level-access +gcloud storage buckets create gs://YOUR_BUCKET \ + --project=YOUR_PROJECT_ID \ + --location=us-central1 \ + --uniform-bucket-level-access ``` ```bash @@ -259,16 +250,24 @@ gcloud storage cp gemini-enterprise-oauth-client.json gs://YOUR_BUCKET/ ``` ```bash -gcloud storage buckets add-iam-policy-binding gs://YOUR_BUCKET --member=allUsers --role=roles/storage.objectViewer +gcloud storage buckets add-iam-policy-binding gs://YOUR_BUCKET \ + --member=allUsers \ + --role=roles/storage.objectViewer ``` -The object is then served at `https://storage.googleapis.com/YOUR_BUCKET/gemini-enterprise-oauth-client.json`, which is the value you use as the client ID. Confirm it returns your JSON before continuing. - Two organization policies can block that public binding. See **Allow public access to the document** below. + +Confirm the document resolves before you continue. It returns the JSON you published, and its `client_id` matches the URL you requested: + +```bash +curl -s https://storage.googleapis.com/YOUR_BUCKET/gemini-enterprise-oauth-client.json +``` + +That URL is the value you use as the client ID. -Both of these are separate from the constraint in [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors), and both need `roles/orgpolicy.policyAdmin`. +The two constraints below are separate from the constraint in [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors), and both need `roles/orgpolicy.policyAdmin`. **Domain restricted sharing.** If `constraints/iam.allowedPolicyMemberDomains` is enforced, granting `allUsers` fails with: @@ -289,7 +288,25 @@ spec: This override is project-wide, not bucket-scoped. Any resource in the project can then be shared publicly. Publish the document from a project dedicated to it rather than one holding other data, and remove the override as soon as you stop hosting the document. -**Public access prevention.** If `constraints/storage.publicAccessPrevention` is enforced, the binding is refused regardless. Check both with `gcloud org-policies describe --project=YOUR_PROJECT_ID --effective`. +**Public access prevention.** If `constraints/storage.publicAccessPrevention` is enforced, the binding is refused regardless of the constraint above. Save this as `pap.yaml` and apply it with `gcloud org-policies set-policy pap.yaml`: + +```yaml +name: projects/YOUR_PROJECT_ID/policies/storage.publicAccessPrevention +spec: + rules: + - enforce: false +``` + +Check the effective value of either constraint with: + +```bash +gcloud org-policies describe storage.publicAccessPrevention \ + --project=YOUR_PROJECT_ID --effective +``` + + +Organization policy changes take a minute or two to take effect, in both directions. After you apply the override, the binding can still fail with the same `412` for a short while, and `describe --effective` may report the new value before enforcement catches up. Retry the binding rather than assuming the override is wrong, and confirm success by fetching the document URL. + @@ -347,14 +364,16 @@ Select **Verify Auth**. A window opens for you to sign in through your identity Select **Continue**. -Enter your **Data connector name**. +Enter your **Data connector name**, then select **Continue**. + +Leave **Location** as it is, and leave **Sensitive data protection policy** empty unless your organization requires one. -Select **Create**. +On **Select the pricing model**, leave **General pricing** selected unless your organization has chosen a subscription, then select **Create**. -The form shows **Successfully logged in** after you authorize, and the connector reaches the **Active** state a minute or two after you create it. +The form shows **Successfully logged in** after you authorize. The connector is created immediately and reaches the **Active** state within a minute. ## Enable the actions @@ -427,9 +446,9 @@ Agent Registry gives your organization a catalog of approved MCP servers, and Ag Adding them does not change how these tool calls are governed. Google's documentation states that traffic to MCP servers added as a data connector does not pass through Agent Gateway, and Agent Gateway policies do not apply to it. C1 governs the tool calls. Use this path when you want the C1 gateway listed in a shared catalog alongside your other approved servers, not to add enforcement. - + Register the server in the catalog, but do not import it as your data connector. Importing from Agent Registry produces a connector whose tool discovery fails. Create the connector from the **Custom MCP Server** card as described in [Create the data store](#create-the-data-store), and treat the catalog entry as a separate, listing-only exercise. - + For the catalog entry, follow Google's own documentation, which stays current with the regional rules and command surface: @@ -450,19 +469,19 @@ Four things that are easy to miss on that path: | `Operation denied by org policy ... disableCustomMcpServerConnector` | The organization policy blocks custom MCP data connectors, or the override has not propagated. | Turn the constraint off and wait several minutes. See [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors). | | The override is set but the denial persists | An enforced organization- or folder-level policy overrides your project setting. | Re-run the `describe --effective` command. If it still reports `enforce: true`, ask your organization policy administrator to add the project exception. | | `PERMISSION_DENIED` on `gcloud services enable` | The caller lacks `roles/serviceusage.serviceUsageAdmin` on the project. | Grant it. See [Required roles](#required-roles). | -| `404` on the client metadata URL | Your tenant is not running a release that publishes the Gemini Enterprise client document. | [Contact the C1 support team](mailto:support@c1.ai). | +| `404` on the client metadata URL | Nothing is hosting a document at that URL, or the file is not publicly readable. | Confirm you are using a URL you host yourself. The C1-hosted URL is not available yet. See [Get the OAuth client ID](#get-the-oauth-client-id). | | **We encountered some problems during authentication** | The client ID is wrong, or the sign-in window was closed or blocked. | Confirm the client ID resolves, allow popups for the console, and retry **Verify Auth**. | | The form will not accept an empty **Client Secret** | The console treats the field as required. | Enter `none`, as in [Create the data store](#create-the-data-store). C1 never reads it. | | **Failed to reload custom actions** on a connector imported from Agent Registry | Registry-imported connectors fail discovery with `FAILED_PRECONDITION`. | Recreate the data store from the **Custom MCP Server** card. See [Create the data store](#create-the-data-store). | -| **Failed to reload custom actions** | The connector is still creating, or the tool action APIs are not enabled. | Wait for **Active**, then confirm `connectors.googleapis.com`, `integrations.googleapis.com`, and `secretmanager.googleapis.com` are enabled. | +| **Failed to reload custom actions** | The connector is still creating, or `discoveryengine.googleapis.com` is not enabled. | Wait for the connector to reach **Active**, then confirm the API is enabled. See [Enable the Google Cloud APIs](#enable-the-google-cloud-apis). | | **Reload custom actions** shows no error and no actions | Most often the reload is still running. It takes about 30 seconds. | Wait for the **Custom actions reloaded** confirmation, then reload the page. | | The action list stays empty after the reload finishes | C1 returned an empty tool list for the authorizing user, which happens when that user has no toolset. | Assign the authorizing user an access profile that includes the tools you expect, then reload again. See [Tools and toolsets](/product/admin/tools-and-toolsets). | | The assistant answers that it has "no ConductorOne integration" | The user has not authorized the connector in the web app. Enabling actions authorizes nobody. | In the message box, open **Connectors** and select **Authorize** beside your connector. See [Verify the Gemini Enterprise connection](#verify-the-gemini-enterprise-connection). | | The assistant picks a web search instead of a C1 action | No enabled action matches the request, so nothing is callable. | Enable the actions the request needs, and name the connector in the prompt. | | A user's tool calls are denied while another user's succeed | C1 is enforcing that user's access profile. This is expected behavior. | Check the denial reason in the audit log. See [Audit AI tool usage](/product/admin/audit-ai-tool-usage). | -| Authorization works, then breaks about an hour later | The connector uses a dynamically registered client whose secret expired. | Use the C1-published client ID. See [Get the OAuth client ID](#get-the-oauth-client-id). | +| Authorization works, then breaks about an hour later | The connector uses a dynamically registered client whose secret expired. | Host a Client ID Metadata Document and use its URL as the client ID instead of registering dynamically. See [Get the OAuth client ID](#get-the-oauth-client-id). | | Tool calls fail immediately after a working **Verify Auth** | The token is not bound to your MCP endpoint. | Set **Authorization URL Parameters** to `&resource=https://-mcp.conductor.one/v1`. | -| `failed to fetch client metadata` | C1 fetches its own client metadata document over the public internet, and your tenant hostname does not resolve publicly. | This affects self-hosted installations rather than C1 cloud tenants. [Contact the C1 support team](mailto:support@c1.ai). | +| `failed to fetch client metadata` | C1 fetches its own client metadata document over the public internet, and your tenant hostname does not resolve publicly. | This affects self-managed C1 deployments rather than C1 cloud tenants. [Contact the C1 support team](mailto:support@c1.ai). | To correct an authentication value, edit the existing connector's settings rather than recreating it. The connector name cannot be changed after creation, as noted in [Create the data store](#create-the-data-store), so changing it means creating a new data store and removing the old one. From 4e9e08944bad61aa2f0f2d13a38927e97c406ab9 Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 12:55:40 -0500 Subject: [PATCH 05/12] docs(mcp): add the Gemini Enterprise prerequisites a new project needs Ran the guide from scratch against a brand-new Google Cloud project, following only what the page says. Everything through creating the data connector worked, including the domain restricted sharing accordion, which reproduced its 412 verbatim and recovered on the documented override in about ninety seconds. Two required steps were missing. A new Gemini Enterprise app has no identity provider, and the data store form blocks on it with Create greyed out and no hint about where to go. Google's own warning is that changing the provider later means deleting and recreating every access-controlled data store, so this belongs before the first data store exists, not discovered halfway through a wizard. A new app also has a subscription but no licensed users. Both now have their own section ahead of the client ID work. Also drops the pricing step to a conditional aside, since it is a property of which console you are in rather than of the account: the gen-app-builder wizard has four steps and the gemini-enterprise wizard has three. Adds roles/storage.admin, which the self-hosting path needs and the roles table never listed, and notes that a never-set allowedEgressFqdns constraint answers with NOT_FOUND rather than a value. Co-Authored-By: Claude Opus 5 --- .../admin/mcp-server/gemini-enterprise.mdx | 79 ++++++++++++++++++- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index 120f7bee..28fff447 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -16,13 +16,14 @@ Google [Gemini Enterprise](https://cloud.google.com/gemini/enterprise) calls the ## What you'll do -Setup spans two products. Two stages depend on someone other than you, so line those up before you start. +Setup spans two products. Some stages depend on someone other than you, so line those up before you start. | Stage | Where | Depends on | | :--- | :--- | :--- | | [Collect the values you'll reuse](#collect-the-values-youll-reuse) | C1 and Google Cloud | Nothing | | [Enable the Google Cloud APIs](#enable-the-google-cloud-apis) | Google Cloud | `roles/serviceusage.serviceUsageAdmin` | | [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors) | Google Cloud | An **organization** policy administrator | +| [Prepare Gemini Enterprise](#prepare-gemini-enterprise) | Gemini Enterprise | A Gemini Enterprise subscription | | [Get the OAuth client ID](#get-the-oauth-client-id) | C1 | Nothing | | [Create the data store](#create-the-data-store) | Gemini Enterprise | `roles/discoveryengine.editor` | | [Enable the actions](#enable-the-actions) | Gemini Enterprise | Tool access already granted in C1 | @@ -35,6 +36,7 @@ Confirm all of these before you start. The organization policy change in particu - AI access management must be enabled for your tenant. See [Enable AI access management](/product/admin/enable-ai-access-management). - **The users who will use Gemini Enterprise need C1 tool access already.** Their access profiles determine which tools they can call, and a user with no toolset sees no tools at all. See [Tools and toolsets](/product/admin/tools-and-toolsets). - A Google Cloud project with a Gemini Enterprise app already created. See Google's [Create a Gemini Enterprise app](https://docs.cloud.google.com/gemini/enterprise/docs/create-app) documentation. +- A Gemini Enterprise subscription with licenses available to assign. A new app starts with no users licensed, and both steps in [Prepare Gemini Enterprise](#prepare-gemini-enterprise) must be done before you create the data store. - Someone who holds `roles/orgpolicy.policyAdmin` at the organization level. Project **Owner** does not include it, and a project-level grant is not sufficient for the policy change below. - **Optional.** The [gcloud CLI](https://cloud.google.com/sdk/docs/install), authenticated with `gcloud auth login`, if you prefer the command line for the Google Cloud steps. @@ -47,6 +49,7 @@ Grant these on the Google Cloud project, except where noted. | `roles/serviceusage.serviceUsageAdmin` | Project | Enable the required APIs | | `roles/discoveryengine.editor` | Project | Create the data store and authorize the connection | | `roles/orgpolicy.policyAdmin` | **Organization** | Allow custom MCP data connectors. Project **Owner** is not sufficient. | +| `roles/storage.admin` | Project | Create the bucket that serves the client metadata document, and make it public. Needed only if you host the document yourself. | To check what you already hold on the project: @@ -61,7 +64,7 @@ To grant a project role: ```bash gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \ - --member="user:admin@yourdomain.com" \ + --member="user:YOUR_EMAIL" \ --role="roles/discoveryengine.editor" ``` @@ -98,6 +101,8 @@ Enable both. In the console, go to **APIs & Services** > **Library**, search for | Discovery Engine API | `discoveryengine.googleapis.com` | Backs Gemini Enterprise apps, data stores, and tool discovery | | Organization Policy API | `orgpolicy.googleapis.com` | Required to read or change the policy in the next section | +The Cloud Storage API is enabled on new projects by default, so hosting the client metadata document needs no extra API. + Google's setup documentation for custom MCP servers does not list any APIs, so this list was established by testing, and it is deliberately short. The Connectors, Application Integration, Secret Manager, and IAM APIs are **not** required. With all four disabled, creating the data connector, authorizing it, discovering tools, calling them, and running the role commands above all succeed. @@ -189,9 +194,65 @@ gcloud org-policies describe discoveryengine.allowedEgressFqdns \ --project=YOUR_PROJECT_ID --effective ``` +If the constraint has never been set, this command returns `NOT_FOUND: Requested entity was not found`. That is the healthy answer and means nothing is restricting egress. + If it is set, add the two hostnames your tenant uses, `-mcp.conductor.one` and `.conductor.one`. Use hostnames only, not full URLs. +## Prepare Gemini Enterprise + +Two Gemini Enterprise settings must be in place before you create the data store. A new app has neither, and the data store form blocks on the first one with **Create** greyed out. + +### Set the identity provider + +Gemini Enterprise needs an identity provider selected for the location your app runs in. Until one is set, creating a data connector fails with **You must configure your access control settings before you continue**. + + +Set this before you create any data store. Google's own warning on this screen is that changing the identity provider later stops access-controlled data stores working, and that you must delete and recreate every one of them to update their permissions. + + + + +In the Google Cloud console, open **Gemini Enterprise** and select **Settings**, then the **Authentication** tab. + + +Find the row for your app's location, such as `global`, and select the edit icon. + + +Choose **Google Identity** if your users sign in with Google Workspace accounts, or **3rd Party Identity** if you federate through a workforce identity pool. + + +Select **Save**. + + + +The row for your location now names the provider instead of reading **Identity provider is not set up**. + + +This page reports **You don't have permissions to fetch Workforce Pools** unless you hold a role that can read workforce pools at the organization level. The message is harmless if you are choosing **Google Identity**, which does not use them. + + +### Assign Gemini Enterprise licenses + +A new Gemini Enterprise app has a subscription but no licensed users, and the users list reads **No existing users**. Assign a license to yourself and to everyone who will use the connector. + + + +In **Gemini Enterprise**, select **Manage users**. + + +Confirm a subscription is listed and **Active**, and note how many licenses are unassigned. + + +Select **Add users**. + + +Enter the email addresses, choose the subscription, and select **Submit**. + + + +Each address now appears in the users list with a license and an assignment date. + ## Get the OAuth client ID Gemini Enterprise authenticates each user to C1 with the OAuth 2.0 authorization code flow, and it needs an OAuth client that already exists. It does not register one itself, and it does not publish a client identity you can point at. @@ -326,6 +387,10 @@ The data connector name generates an ID that cannot be changed later. Choose it Use the **Custom MCP Server** card, not a server imported from Agent Registry. A connector created from a registry import fails tool discovery with `Failed to reload custom actions` and a `FAILED_PRECONDITION` error, while an otherwise identical connector created from the Custom MCP Server card completes normally. + +Finish [Prepare Gemini Enterprise](#prepare-gemini-enterprise) before you open this form. If you leave the wizard partway through to set the identity provider, you return to a partially reset form and it is easy to submit it incomplete. + + In the Google Cloud console, open **Gemini Enterprise** and select your app. @@ -352,7 +417,7 @@ Complete the fields. The third column is where this form most often goes wrong. | **Authorization URL Parameters** | `&resource=https://-mcp.conductor.one/v1` | Required. C1 binds tokens to a resource, so omitting this yields a token your MCP endpoint rejects. | | **Token URL** | `https://.conductor.one/auth/v1/token` | No special handling | | **Client ID** | Your client metadata document URL | The full `https://` URL, not a bare identifier. | -| **Client Secret** | `none` | PKCE needs no secret, but the console requires a value in this field, and Google's documentation says to enter `none`. C1 never reads it. | +| **Client Secret** | `none` | Proof Key for Code Exchange (PKCE) needs no secret, but the console requires a value in this field, and Google's documentation says to enter `none`. C1 never reads it. | | **Scopes** | `openid profile email offline_access` | Space-separated, not comma-separated. | | **Enable PKCE Support** | Selected | Not selected by default. C1 requires PKCE, so the flow fails without it. | | **Use HTTP Basic Authentication** | Cleared | **Selected by default.** Leaving it selected sends credentials in an `Authorization` header, which does not work for a client with no secret. | @@ -369,7 +434,9 @@ Enter your **Data connector name**, then select **Continue**. Leave **Location** as it is, and leave **Sensitive data protection policy** empty unless your organization requires one. -On **Select the pricing model**, leave **General pricing** selected unless your organization has chosen a subscription, then select **Create**. +Select **Create**. + +Some versions of the console add a **Select the pricing model** step first. If you see it, leave **General pricing** selected unless your organization has chosen a subscription, then select **Create**. @@ -469,11 +536,15 @@ Four things that are easy to miss on that path: | `Operation denied by org policy ... disableCustomMcpServerConnector` | The organization policy blocks custom MCP data connectors, or the override has not propagated. | Turn the constraint off and wait several minutes. See [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors). | | The override is set but the denial persists | An enforced organization- or folder-level policy overrides your project setting. | Re-run the `describe --effective` command. If it still reports `enforce: true`, ask your organization policy administrator to add the project exception. | | `PERMISSION_DENIED` on `gcloud services enable` | The caller lacks `roles/serviceusage.serviceUsageAdmin` on the project. | Grant it. See [Required roles](#required-roles). | +| `PERMISSION_DENIED` on `gcloud storage buckets create` or the `allUsers` binding | The caller lacks `roles/storage.admin` on the project. | Grant it. See [Required roles](#required-roles). | +| **You must configure your access control settings before you continue**, and **Create** is greyed out | No identity provider is set for the app's location. | Set one, then return to the form. See [Set the identity provider](#set-the-identity-provider). | +| **Client ID** and **Client Secret** are blank on the **Re-authenticate** panel | Expected. The console never displays stored credentials, on a working connector or a broken one. | Nothing to fix. To change them, type both in again and select **Verify Auth**. | | `404` on the client metadata URL | Nothing is hosting a document at that URL, or the file is not publicly readable. | Confirm you are using a URL you host yourself. The C1-hosted URL is not available yet. See [Get the OAuth client ID](#get-the-oauth-client-id). | | **We encountered some problems during authentication** | The client ID is wrong, or the sign-in window was closed or blocked. | Confirm the client ID resolves, allow popups for the console, and retry **Verify Auth**. | | The form will not accept an empty **Client Secret** | The console treats the field as required. | Enter `none`, as in [Create the data store](#create-the-data-store). C1 never reads it. | | **Failed to reload custom actions** on a connector imported from Agent Registry | Registry-imported connectors fail discovery with `FAILED_PRECONDITION`. | Recreate the data store from the **Custom MCP Server** card. See [Create the data store](#create-the-data-store). | | **Failed to reload custom actions** | The connector is still creating, or `discoveryengine.googleapis.com` is not enabled. | Wait for the connector to reach **Active**, then confirm the API is enabled. See [Enable the Google Cloud APIs](#enable-the-google-cloud-apis). | +| **Failed to reload custom actions** on a connector that is **Active** | Gemini Enterprise has no usable authorization for the connector. The console request returns `401`, and the app then fails to build a fresh authorization URL. | Confirm [Prepare Gemini Enterprise](#prepare-gemini-enterprise) is complete, since a project with no identity provider or no assigned licenses produces this. Then open the connector, select **Re-authenticate**, enter the client ID and `none`, select **Verify Auth**, and select **Update**. Wait two minutes for the credentials to propagate before you reload again. | | **Reload custom actions** shows no error and no actions | Most often the reload is still running. It takes about 30 seconds. | Wait for the **Custom actions reloaded** confirmation, then reload the page. | | The action list stays empty after the reload finishes | C1 returned an empty tool list for the authorizing user, which happens when that user has no toolset. | Assign the authorizing user an access profile that includes the tools you expect, then reload again. See [Tools and toolsets](/product/admin/tools-and-toolsets). | | The assistant answers that it has "no ConductorOne integration" | The user has not authorized the connector in the web app. Enabling actions authorizes nobody. | In the message box, open **Connectors** and select **Authorize** beside your connector. See [Verify the Gemini Enterprise connection](#verify-the-gemini-enterprise-connection). | From 72dc226eda7f7e17344785efd966ad56e3028e2f Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 17:54:08 -0500 Subject: [PATCH 06/12] docs(mcp): add the sign-in step that makes tool discovery work Built the whole thing again from an empty project, enabling only what the page asks for, and drove every step that has an API from the command line. A live tool call returned real tenant data, so the sequence here is now one that has been walked end to end rather than assembled from parts. The step that was missing is a user opening the Gemini Enterprise web app. Tool discovery runs as the signed-in user and fails until that user has signed in once, and the console never says so: Reload custom actions just reports that it failed, on a connector that reads Active with every setting correct. It cost most of a day to find, so it gets its own section before the reload, plus a userLicenses check for lastLoginTime. Agent Registry and Agent Gateway are not required, and this is now stated from evidence rather than from Google's documentation. A working connector reports use_agent_gateway_egress false, and a setup with no gateway, no registry and no authorization extension discovers tools and serves calls normally. Also adds command-line equivalents for the identity provider and licence assignment, quotes the API error that makes connector creation console-only, and replaces the reload troubleshooting rows, which blamed the API and the credentials for what is almost always a missing sign-in. Co-Authored-By: Claude Opus 5 --- .../admin/mcp-server/gemini-enterprise.mdx | 91 ++++++++++++++++++- 1 file changed, 86 insertions(+), 5 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index 28fff447..3217304b 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -26,6 +26,7 @@ Setup spans two products. Some stages depend on someone other than you, so line | [Prepare Gemini Enterprise](#prepare-gemini-enterprise) | Gemini Enterprise | A Gemini Enterprise subscription | | [Get the OAuth client ID](#get-the-oauth-client-id) | C1 | Nothing | | [Create the data store](#create-the-data-store) | Gemini Enterprise | `roles/discoveryengine.editor` | +| [Sign in to the web app](#sign-in-to-the-web-app) | Gemini Enterprise | A licensed user | | [Enable the actions](#enable-the-actions) | Gemini Enterprise | Tool access already granted in C1 | | [Verify the connection](#verify-the-gemini-enterprise-connection) | Gemini Enterprise and C1 | A user with C1 tool access | @@ -228,6 +229,19 @@ Select **Save**. The row for your location now names the provider instead of reading **Identity provider is not set up**. +To do the same from the command line, for Google Workspace accounts: + +```bash +curl -s -X PATCH \ + -H "Authorization: Bearer $(gcloud auth print-access-token)" \ + -H "X-Goog-User-Project: YOUR_PROJECT_ID" \ + -H "Content-Type: application/json" \ + -d '{"name":"projects/YOUR_PROJECT_ID/locations/global/aclConfig","idpConfig":{"idpType":"GSUITE"}}' \ + "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/aclConfig" +``` + +The response echoes `"idpType": "GSUITE"` once it is set. + This page reports **You don't have permissions to fetch Workforce Pools** unless you hold a role that can read workforce pools at the organization level. The message is harmless if you are choosing **Google Identity**, which does not use them. @@ -253,6 +267,25 @@ Enter the email addresses, choose the subscription, and select **Submit**. Each address now appears in the users list with a license and an assignment date. +To assign licenses from the command line, use the project **number**, not the project ID, inside `licenseConfig`: + +```bash +curl -s -X POST \ + -H "Authorization: Bearer $(gcloud auth print-access-token)" \ + -H "X-Goog-User-Project: YOUR_PROJECT_ID" \ + -H "Content-Type: application/json" \ + -d '{"inlineSource":{"userLicenses":[{"userPrincipal":"YOUR_EMAIL","licenseConfig":"projects/YOUR_PROJECT_NUMBER/locations/global/licenseConfigs/YOUR_SUBSCRIPTION_ID","licenseAssignmentState":"ASSIGNED"}]}}' \ + "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/userStores/default_user_store:batchUpdateUserLicenses" +``` + +To list the subscriptions available to assign: + +```bash +curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \ + -H "X-Goog-User-Project: YOUR_PROJECT_ID" \ + "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/licenseConfigs" +``` + ## Get the OAuth client ID Gemini Enterprise authenticates each user to C1 with the OAuth 2.0 authorization code flow, and it needs an OAuth client that already exists. It does not register one itself, and it does not publish a client identity you can point at. @@ -376,7 +409,13 @@ Organization policy changes take a minute or two to take effect, in both directi Connect the C1 MCP gateway to your Gemini Enterprise app. -This section and the next have no `gcloud` or REST equivalent. The public Discovery Engine API rejects the parameters the console itself writes for a custom MCP connector, and the method behind **Reload custom actions** is not exposed on the public endpoint. Creating the data store, discovering actions, and enabling actions are console-only. +This section and the next are console-only. The public Discovery Engine API refuses to create this connector: + +```text +Data Connector parameters must be one of: oauth_access_token but got: instance_uri +``` + +It accepts only a pre-obtained access token, not the OAuth client configuration, so it cannot run the per-user authorization this integration depends on. The method behind **Reload custom actions** is not on the public endpoint either. Every other step in this guide can be scripted. @@ -442,6 +481,36 @@ Some versions of the console add a **Select the pricing model** step first. If y The form shows **Successfully logged in** after you authorize. The connector is created immediately and reaches the **Active** state within a minute. +## Sign in to the web app + +**Do this before you reload the actions.** Tool discovery runs as the signed-in user, and it fails if that user has never opened the Gemini Enterprise web app. The console gives no hint that this is the cause: **Reload custom actions** simply reports **Failed to reload custom actions**. + + +This is the step most often missed, because nothing in the admin console mentions it and nothing about the connector looks wrong. The connector reads **Active**, every setting is correct, and discovery still fails until a licensed user has signed in once. + + + + +In the Google Cloud console, open **Gemini Enterprise**, select your app, and open **Overview**. + + +Copy the web app URL shown there. It looks like `https://vertexaisearch.cloud.google.com/home/cid/`. + + +Open that URL as a licensed user and select **Get started** on the welcome panel. + + + +To confirm the sign-in registered, check that `lastLoginTime` is present: + +```bash +curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \ + -H "X-Goog-User-Project: YOUR_PROJECT_ID" \ + "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/userStores/default_user_store/userLicenses" +``` + +A user with a license but no `lastLoginTime` has never opened the web app, and tool discovery will fail for them. + ## Enable the actions Gemini Enterprise calls MCP tools *actions*, and imports every one of them turned off. Enable them on the data connector, not on the app's **Actions** page, which only redirects you here. Turn on only the actions your users need: a data store supports a maximum of 100 enabled actions, and a shorter list makes the agent's tool selection more accurate. @@ -469,6 +538,18 @@ Select **Enable actions**. The actions you selected are now enabled on the connector. No one can call them yet: each user must authorize the connector themselves, which is the first part of [Verify the Gemini Enterprise connection](#verify-the-gemini-enterprise-connection). + +The console toast is not a reliable signal. To see whether a reload actually succeeded, read the audit log: + +```bash +gcloud logging read 'protoPayload.methodName:"RefreshDataConnectorTools"' \ + --project=YOUR_PROJECT_ID --limit=5 --freshness=10m \ + --format="value(timestamp,severity,protoPayload.status.message)" +``` + +A `401` entry on its own is normal: the console retries and a successful reload logs an entry with no error a few seconds later. Judge by that later entry, not by the first error. + + ## Verify the Gemini Enterprise connection Seeing actions listed does not confirm your credentials work. You confirm the setup only when a user successfully calls a C1 tool. @@ -507,10 +588,10 @@ If the agent does not call a tool, returns nothing, or reports a denial, see [Tr ## Optional: Govern the server through Agent Registry -Agent Registry gives your organization a catalog of approved MCP servers, and Agent Gateway is the policy enforcement point for agent traffic. Neither is required here, and the setup above works without both. +Agent Registry gives your organization a catalog of approved MCP servers, and Agent Gateway is the policy enforcement point for agent traffic. **Neither is required, and neither changes how these tool calls are governed.** -Adding them does not change how these tool calls are governed. Google's documentation states that traffic to MCP servers added as a data connector does not pass through Agent Gateway, and Agent Gateway policies do not apply to it. C1 governs the tool calls. Use this path when you want the C1 gateway listed in a shared catalog alongside your other approved servers, not to add enforcement. +This was verified rather than assumed. A working connector reports `use_agent_gateway_egress: false`, so its traffic does not pass through Agent Gateway at all, and a complete setup built with no gateway, no registry, and no authorization extension discovers tools and serves live tool calls normally. C1 governs the tool calls. Use this path only when you want the C1 gateway listed in a shared catalog alongside your other approved servers. @@ -543,8 +624,8 @@ Four things that are easy to miss on that path: | **We encountered some problems during authentication** | The client ID is wrong, or the sign-in window was closed or blocked. | Confirm the client ID resolves, allow popups for the console, and retry **Verify Auth**. | | The form will not accept an empty **Client Secret** | The console treats the field as required. | Enter `none`, as in [Create the data store](#create-the-data-store). C1 never reads it. | | **Failed to reload custom actions** on a connector imported from Agent Registry | Registry-imported connectors fail discovery with `FAILED_PRECONDITION`. | Recreate the data store from the **Custom MCP Server** card. See [Create the data store](#create-the-data-store). | -| **Failed to reload custom actions** | The connector is still creating, or `discoveryengine.googleapis.com` is not enabled. | Wait for the connector to reach **Active**, then confirm the API is enabled. See [Enable the Google Cloud APIs](#enable-the-google-cloud-apis). | -| **Failed to reload custom actions** on a connector that is **Active** | Gemini Enterprise has no usable authorization for the connector. The console request returns `401`, and the app then fails to build a fresh authorization URL. | Confirm [Prepare Gemini Enterprise](#prepare-gemini-enterprise) is complete, since a project with no identity provider or no assigned licenses produces this. Then open the connector, select **Re-authenticate**, enter the client ID and `none`, select **Verify Auth**, and select **Update**. Wait two minutes for the credentials to propagate before you reload again. | +| **Failed to reload custom actions** on a connector that is **Active** | The most common cause by far is that the signed-in user has never opened the Gemini Enterprise web app. | Open the web app as that user, then reload again. See [Sign in to the web app](#sign-in-to-the-web-app). | +| **Failed to reload custom actions**, and the user has signed in | The connector is still creating, `discoveryengine.googleapis.com` is not enabled, the user holds no license, or no identity provider is set. | Wait for **Active**, then check each in turn. See [Prepare Gemini Enterprise](#prepare-gemini-enterprise). | | **Reload custom actions** shows no error and no actions | Most often the reload is still running. It takes about 30 seconds. | Wait for the **Custom actions reloaded** confirmation, then reload the page. | | The action list stays empty after the reload finishes | C1 returned an empty tool list for the authorizing user, which happens when that user has no toolset. | Assign the authorizing user an access profile that includes the tools you expect, then reload again. See [Tools and toolsets](/product/admin/tools-and-toolsets). | | The assistant answers that it has "no ConductorOne integration" | The user has not authorized the connector in the web app. Enabling actions authorizes nobody. | In the message box, open **Connectors** and select **Authorize** beside your connector. See [Verify the Gemini Enterprise connection](#verify-the-gemini-enterprise-connection). | From 3ec4df2f502de355ed08ab8b189c36c4ea3faf10 Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 18:08:15 -0500 Subject: [PATCH 07/12] docs(mcp): fix the order a reader actually meets things in Read the page end to end as a customer would, and rendered it locally to check how it behaves rather than how the source looks. Required roles came before the table that explains the placeholders its commands use, and one of those placeholders was never explained at all. Roles now follow the values table, which gained rows for the project number and the email, both of which commands referenced out of nowhere. Licence assignment had the same problem in miniature: it asked for a subscription ID and a project number, and the command that finds the subscription came afterwards. That pair is now the other way round. Hosting the client metadata document was inside a collapsed accordion, which is the one path essentially every reader has to take today. Anyone reading top to bottom could skip the bucket entirely. It is a normal subsection now, and only the conditional org-policy fix stays collapsed. Rendering surfaced its own problems. The JSON payloads were single lines that ran off the edge of their code blocks, and the app-creation command had been squeezed into a bullet. Payloads are multi-line and the command has its own accordion. Also corrects a claim this page kept repeating: licences do not block creating the data store, they block tool discovery later. Adds the console equivalent for granting roles and a worked example for the egress constraint, so no step is command-only where a neighbour got both. Co-Authored-By: Claude Opus 5 --- .../admin/mcp-server/gemini-enterprise.mdx | 163 ++++++++++++------ 1 file changed, 109 insertions(+), 54 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index 3217304b..89bd3717 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -24,7 +24,7 @@ Setup spans two products. Some stages depend on someone other than you, so line | [Enable the Google Cloud APIs](#enable-the-google-cloud-apis) | Google Cloud | `roles/serviceusage.serviceUsageAdmin` | | [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors) | Google Cloud | An **organization** policy administrator | | [Prepare Gemini Enterprise](#prepare-gemini-enterprise) | Gemini Enterprise | A Gemini Enterprise subscription | -| [Get the OAuth client ID](#get-the-oauth-client-id) | C1 | Nothing | +| [Get the OAuth client ID](#get-the-oauth-client-id) | C1 and Google Cloud | `roles/storage.admin`, if you host the document yourself | | [Create the data store](#create-the-data-store) | Gemini Enterprise | `roles/discoveryengine.editor` | | [Sign in to the web app](#sign-in-to-the-web-app) | Gemini Enterprise | A licensed user | | [Enable the actions](#enable-the-actions) | Gemini Enterprise | Tool access already granted in C1 | @@ -36,12 +36,42 @@ Confirm all of these before you start. The organization policy change in particu - AI access management must be enabled for your tenant. See [Enable AI access management](/product/admin/enable-ai-access-management). - **The users who will use Gemini Enterprise need C1 tool access already.** Their access profiles determine which tools they can call, and a user with no toolset sees no tools at all. See [Tools and toolsets](/product/admin/tools-and-toolsets). -- A Google Cloud project with a Gemini Enterprise app already created. See Google's [Create a Gemini Enterprise app](https://docs.cloud.google.com/gemini/enterprise/docs/create-app) documentation. -- A Gemini Enterprise subscription with licenses available to assign. A new app starts with no users licensed, and both steps in [Prepare Gemini Enterprise](#prepare-gemini-enterprise) must be done before you create the data store. +- A Google Cloud project with a Gemini Enterprise app already created. In the console, open **Gemini Enterprise** and select **Create app**, or see Google's [Create a Gemini Enterprise app](https://docs.cloud.google.com/gemini/enterprise/docs/create-app) documentation. There is a command-line alternative in [Enable the Google Cloud APIs](#enable-the-google-cloud-apis). +- A Gemini Enterprise subscription with licenses available to assign. A new app starts with no users licensed. The identity provider must be set before you create the data store, and licenses must be assigned before tool discovery will work. Both are in [Prepare Gemini Enterprise](#prepare-gemini-enterprise). - Someone who holds `roles/orgpolicy.policyAdmin` at the organization level. Project **Owner** does not include it, and a project-level grant is not sufficient for the policy change below. - **Optional.** The [gcloud CLI](https://cloud.google.com/sdk/docs/install), authenticated with `gcloud auth login`, if you prefer the command line for the Google Cloud steps. -### Required roles +## Collect the values you'll reuse + +The steps below reuse these values. Collect them once. + +| Value | Where to get it | Example | +| :--- | :--- | :--- | +| **Tenant** | The subdomain of your C1 URL. It is also the prefix of your MCP server URL. | `acme` | +| **MCP server URL** | In C1, open your user profile menu and select **AI & API** > **AI connections**. Copy the URL shown at the top of the page. | `https://acme-mcp.conductor.one/v1` | +| **Project ID** | The Google Cloud console project picker, or `gcloud config get-value project`. | `acme-gemini` | +| **Project number** | `gcloud projects describe YOUR_PROJECT_ID --format="value(projectNumber)"`. This is not the same as the project ID, and a few API calls need it. | `514280176422` | +| **Your email** | The Google identity you run these commands as, and the first person to be licensed. | `admin@acme.com` | +| **App location** | At the top of the Gemini Enterprise **Apps** page, next to **Current location**. | `global` | + + +The commands in this guide use `global`, which is what most setups run. If your app is in a different location, substitute it everywhere `locations/global` appears. + + +Your OAuth endpoints follow from the tenant. Confirm them against your tenant's published metadata: + +```bash +curl -s https://-mcp.conductor.one/.well-known/oauth-authorization-server +``` + +Read two fields from that response: + +| Field in the response | Value for tenant `acme` | +| :--- | :--- | +| `authorization_endpoint` | `https://acme.conductor.one/auth/v1/authorize` | +| `token_endpoint` | `https://acme.conductor.one/auth/v1/token` | + +## Required roles Grant these on the Google Cloud project, except where noted. @@ -61,7 +91,7 @@ gcloud projects get-iam-policy YOUR_PROJECT_ID \ --format="value(bindings.role)" ``` -To grant a project role: +To grant a role in the console, go to **IAM & Admin** > **IAM**, select **Grant access**, enter the email, and choose the role. To grant one from the command line: ```bash gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \ @@ -69,30 +99,6 @@ gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \ --role="roles/discoveryengine.editor" ``` -## Collect the values you'll reuse - -The steps below reuse these values. Collect them once. - -| Value | Where to get it | Example | -| :--- | :--- | :--- | -| **Tenant** | The subdomain of your C1 URL. It is also the prefix of your MCP server URL. | `acme` | -| **MCP server URL** | In C1, open your user profile menu and select **AI & API** > **AI connections**. Copy the URL shown at the top of the page. | `https://acme-mcp.conductor.one/v1` | -| **Project ID** | The Google Cloud console project picker, or `gcloud config get-value project`. | `acme-gemini` | -| **App location** | At the top of the Gemini Enterprise **Apps** page, next to **Current location**. Needed only for [Optional: Govern the server through Agent Registry](#optional-govern-the-server-through-agent-registry). | `global` | - -Your OAuth endpoints follow from the tenant. Confirm them against your tenant's published metadata: - -```bash -curl -s https://YOUR_TENANT-mcp.conductor.one/.well-known/oauth-authorization-server -``` - -Read two fields from that response: - -| Field in the response | Value for tenant `acme` | -| :--- | :--- | -| `authorization_endpoint` | `https://acme.conductor.one/auth/v1/authorize` | -| `token_endpoint` | `https://acme.conductor.one/auth/v1/token` | - ## Enable the Google Cloud APIs Enable both. In the console, go to **APIs & Services** > **Library**, search for the API by the name in the first column, and select **Enable**. The service ID is the identifier you use with the `gcloud` CLI. @@ -125,6 +131,30 @@ gcloud services list --enabled --project=YOUR_PROJECT_ID Your project can now create custom MCP data connectors. + +If you do not already have an app, create one after the APIs are enabled. There is no `gcloud` surface for this, so call the API directly: + +```bash +curl -s -X POST \ + -H "Authorization: Bearer $(gcloud auth print-access-token)" \ + -H "X-Goog-User-Project: YOUR_PROJECT_ID" \ + -H "Content-Type: application/json" \ + "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/collections/default_collection/engines?engineId=c1-gemini-app" \ + -d '{ + "displayName": "c1-gemini-app", + "solutionType": "SOLUTION_TYPE_SEARCH", + "industryVertical": "GENERIC", + "appType": "APP_TYPE_INTRANET", + "searchEngineConfig": { + "searchTier": "SEARCH_TIER_ENTERPRISE", + "searchAddOns": ["SEARCH_ADD_ON_LLM"] + } + }' +``` + +An app created this way has no subscription attached. Add one under **Manage users** in the console before you assign licenses. + + ## Allow custom MCP data connectors Google Cloud blocks custom MCP data connectors by default through the `constraints/discoveryengine.managed.disableCustomMcpServerConnector` organization policy. Turn it off for this project before you create the data store. @@ -184,7 +214,7 @@ gcloud org-policies set-policy policy.yaml Re-run the `describe` command above. The effective policy reports `enforce: false`, and your project can create custom MCP data connectors. -Allow several minutes for the change to propagate. Until it does, the console returns the same denial message, so a failure immediately after you apply the policy does not mean the policy is wrong. +Organization policy changes take a minute or two to take effect. Until then the console returns the same denial message, so a failure immediately after you apply the policy does not mean the policy is wrong. @@ -197,12 +227,22 @@ gcloud org-policies describe discoveryengine.allowedEgressFqdns \ If the constraint has never been set, this command returns `NOT_FOUND: Requested entity was not found`. That is the healthy answer and means nothing is restricting egress. -If it is set, add the two hostnames your tenant uses, `-mcp.conductor.one` and `.conductor.one`. Use hostnames only, not full URLs. +If it is set, add the two hostnames your tenant uses. Use hostnames only, not full URLs. Save this as `egress.yaml` and apply it with `gcloud org-policies set-policy egress.yaml`, keeping any values your organization already allows: + +```yaml +name: projects/YOUR_PROJECT_ID/policies/discoveryengine.allowedEgressFqdns +spec: + rules: + - values: + allowedValues: + - -mcp.conductor.one + - .conductor.one +``` ## Prepare Gemini Enterprise -Two Gemini Enterprise settings must be in place before you create the data store. A new app has neither, and the data store form blocks on the first one with **Create** greyed out. +A new Gemini Enterprise app has neither of these, and both are needed. The identity provider blocks the data store form itself, with **Create** greyed out. Licenses do not block that form, but tool discovery fails later without them. ### Set the identity provider @@ -236,8 +276,11 @@ curl -s -X PATCH \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "X-Goog-User-Project: YOUR_PROJECT_ID" \ -H "Content-Type: application/json" \ - -d '{"name":"projects/YOUR_PROJECT_ID/locations/global/aclConfig","idpConfig":{"idpType":"GSUITE"}}' \ - "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/aclConfig" + "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/aclConfig" \ + -d '{ + "name": "projects/YOUR_PROJECT_ID/locations/global/aclConfig", + "idpConfig": { "idpType": "GSUITE" } + }' ``` The response echoes `"idpType": "GSUITE"` once it is set. @@ -267,23 +310,33 @@ Enter the email addresses, choose the subscription, and select **Submit**. Each address now appears in the users list with a license and an assignment date. -To assign licenses from the command line, use the project **number**, not the project ID, inside `licenseConfig`: +To do the same from the command line, first list the subscriptions available to assign: ```bash -curl -s -X POST \ - -H "Authorization: Bearer $(gcloud auth print-access-token)" \ +curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "X-Goog-User-Project: YOUR_PROJECT_ID" \ - -H "Content-Type: application/json" \ - -d '{"inlineSource":{"userLicenses":[{"userPrincipal":"YOUR_EMAIL","licenseConfig":"projects/YOUR_PROJECT_NUMBER/locations/global/licenseConfigs/YOUR_SUBSCRIPTION_ID","licenseAssignmentState":"ASSIGNED"}]}}' \ - "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/userStores/default_user_store:batchUpdateUserLicenses" + "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/licenseConfigs" ``` -To list the subscriptions available to assign: +Each returned `name` ends in the subscription ID, such as `free_trial_gemini`. Then assign it, using your project **number** inside `licenseConfig`: ```bash -curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \ +curl -s -X POST \ + -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "X-Goog-User-Project: YOUR_PROJECT_ID" \ - "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/licenseConfigs" + -H "Content-Type: application/json" \ + "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/userStores/default_user_store:batchUpdateUserLicenses" \ + -d '{ + "inlineSource": { + "userLicenses": [ + { + "userPrincipal": "YOUR_EMAIL", + "licenseConfig": "projects/YOUR_PROJECT_NUMBER/locations/global/licenseConfigs/YOUR_SUBSCRIPTION_ID", + "licenseAssignmentState": "ASSIGNED" + } + ] + } + }' ``` ## Get the OAuth client ID @@ -312,8 +365,8 @@ This client has no secret, so nothing expires and nothing needs rotating. Config Do not register a client through C1's dynamic registration endpoint instead. An unapproved dynamic registration's secret expires one hour after it is issued, and rotating it preserves the original expiry rather than extending it, so the connector fails at its first token refresh. - - +### Host the client metadata document yourself + Publish this JSON at any public HTTPS URL you control. Two fields are unforgiving: `client_id` must exactly equal the URL the document is served from, and `redirect_uris` must contain Google's redirect endpoint verbatim. Save the file as `gemini-enterprise-oauth-client.json`. The Cloud Storage commands below serve it at `https://storage.googleapis.com/YOUR_BUCKET/gemini-enterprise-oauth-client.json`, so set `client_id` to exactly that, with your own bucket name: @@ -349,7 +402,7 @@ gcloud storage buckets add-iam-policy-binding gs://YOUR_BUCKET \ --role=roles/storage.objectViewer ``` -Two organization policies can block that public binding. See **Allow public access to the document** below. +Two organization policies can block that public binding. If the next command fails, see **If an organization policy blocks the public binding** below. Confirm the document resolves before you continue. It returns the JSON you published, and its `client_id` matches the URL you requested: @@ -358,10 +411,9 @@ curl -s https://storage.googleapis.com/YOUR_BUCKET/gemini-enterprise-oauth-clien ``` That URL is the value you use as the client ID. - - -The two constraints below are separate from the constraint in [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors), and both need `roles/orgpolicy.policyAdmin`. + +The two constraints below are separate from the constraint in [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors), and both need `roles/orgpolicy.policyAdmin`. To change either in the console, use the same **IAM & Admin** > **Organization policies** flow described there, searching for the constraint name below instead. **Domain restricted sharing.** If `constraints/iam.allowedPolicyMemberDomains` is enforced, granting `allUsers` fails with: @@ -402,7 +454,6 @@ gcloud org-policies describe storage.publicAccessPrevention \ Organization policy changes take a minute or two to take effect, in both directions. After you apply the override, the binding can still fail with the same `412` for a short while, and `describe --effective` may report the new value before enforcement catches up. Retry the binding rather than assuming the override is wrong, and confirm success by fetching the document URL. - ## Create the data store @@ -485,9 +536,11 @@ The form shows **Successfully logged in** after you authorize. The connector is **Do this before you reload the actions.** Tool discovery runs as the signed-in user, and it fails if that user has never opened the Gemini Enterprise web app. The console gives no hint that this is the cause: **Reload custom actions** simply reports **Failed to reload custom actions**. - + This is the step most often missed, because nothing in the admin console mentions it and nothing about the connector looks wrong. The connector reads **Active**, every setting is correct, and discovery still fails until a licensed user has signed in once. - + +Signing in through **Verify Auth** while creating the connector does not count. That authorizes the connector; this is a separate sign-in to the web app itself. + @@ -501,6 +554,8 @@ Open that URL as a licensed user and select **Get started** on the welcome panel +One sign-in by one licensed user unblocks tool discovery for the whole connector. Each user still authorizes the connector separately later, in [Verify the Gemini Enterprise connection](#verify-the-gemini-enterprise-connection); that is a different action, and it cannot happen until the actions are enabled. + To confirm the sign-in registered, check that `lastLoginTime` is present: ```bash @@ -614,7 +669,7 @@ Four things that are easy to miss on that path: | Symptom | Cause | Fix | | :--- | :--- | :--- | -| `Operation denied by org policy ... disableCustomMcpServerConnector` | The organization policy blocks custom MCP data connectors, or the override has not propagated. | Turn the constraint off and wait several minutes. See [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors). | +| **Operation denied by org policy** when you create the data store | The `disableCustomMcpServerConnector` constraint is enforced, or the override has not propagated. | Turn the constraint off and wait several minutes. See [Allow custom MCP data connectors](#allow-custom-mcp-data-connectors). | | The override is set but the denial persists | An enforced organization- or folder-level policy overrides your project setting. | Re-run the `describe --effective` command. If it still reports `enforce: true`, ask your organization policy administrator to add the project exception. | | `PERMISSION_DENIED` on `gcloud services enable` | The caller lacks `roles/serviceusage.serviceUsageAdmin` on the project. | Grant it. See [Required roles](#required-roles). | | `PERMISSION_DENIED` on `gcloud storage buckets create` or the `allUsers` binding | The caller lacks `roles/storage.admin` on the project. | Grant it. See [Required roles](#required-roles). | @@ -661,7 +716,7 @@ The client is a public OAuth client with no secret. Client ID Metadata Document -No. Google's documentation states that traffic to MCP servers added as a data connector does not pass through Agent Gateway, so adding it does not change how these tool calls are governed. C1 governs the tool calls. See [Optional: Govern the server through Agent Registry](#optional-govern-the-server-through-agent-registry). +No. C1 governs the tool calls, and this was tested rather than taken on trust. See [Optional: Govern the server through Agent Registry](#optional-govern-the-server-through-agent-registry) for the evidence. From e85946b71a0aa33515054d200334b015a2cbc5a8 Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 18:23:35 -0500 Subject: [PATCH 08/12] docs(mcp): drop the Agent Registry section Testing showed neither Agent Registry nor Agent Gateway is required, so a section walking through both was inviting readers to build infrastructure that changes nothing about this integration. Its remaining advice was also the oldest material on the page, written before any of the current testing and never re-checked. The two parts worth keeping already lived elsewhere. Not importing the connector from the registry is a Note on the data store section and a troubleshooting row. The evidence that the gateway is unnecessary now sits in the FAQ answer that used to link here, so the answer stands on its own. Twenty-four lines shorter, one fewer heading, no dangling links. Co-Authored-By: Claude Opus 5 --- .../admin/mcp-server/gemini-enterprise.mdx | 30 +++---------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index 89bd3717..470d20d6 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -641,30 +641,6 @@ The connection is working, and every tool call is attributed to the user who mad If the agent does not call a tool, returns nothing, or reports a denial, see [Troubleshoot Gemini Enterprise connection errors](#troubleshoot-gemini-enterprise-connection-errors). A denial that names a missing toolset or access profile is C1 working as configured, not a broken integration. -## Optional: Govern the server through Agent Registry - -Agent Registry gives your organization a catalog of approved MCP servers, and Agent Gateway is the policy enforcement point for agent traffic. **Neither is required, and neither changes how these tool calls are governed.** - - -This was verified rather than assumed. A working connector reports `use_agent_gateway_egress: false`, so its traffic does not pass through Agent Gateway at all, and a complete setup built with no gateway, no registry, and no authorization extension discovers tools and serves live tool calls normally. C1 governs the tool calls. Use this path only when you want the C1 gateway listed in a shared catalog alongside your other approved servers. - - - -Register the server in the catalog, but do not import it as your data connector. Importing from Agent Registry produces a connector whose tool discovery fails. Create the connector from the **Custom MCP Server** card as described in [Create the data store](#create-the-data-store), and treat the catalog entry as a separate, listing-only exercise. - - -For the catalog entry, follow Google's own documentation, which stays current with the regional rules and command surface: - -- [Register MCP servers in Agent Registry](https://docs.cloud.google.com/agent-registry/register-mcp-servers) -- [Set up an Agent Gateway](https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/gateways/set-up-agent-gateway) - -Four things that are easy to miss on that path: - -- **Your app, gateway, and registry regions must align**, and Google's import documentation has the current table. A `global` or `us` app pairs with a `us-central1` gateway; an `eu` app pairs with `europe-west1`. When they do not align, the server never appears in the data store list and no error explains why. -- **Each app must be pointed at the gateway explicitly**, under **Security** > **Configuration** > **Agent Gateway configuration** in the app. Creating a gateway is not enough, and until an app is bound to one, no registered server appears in its data store list. -- **Every tool in a `toolspec.json` needs an `inputSchema`.** Google's published example omits it, and registration fails with `invalid MCP tool spec content: tools.0: inputSchema is required`. -- **The gateway denies egress until you authorize it.** By default it allows traffic only to resources explicitly authorized through IAM, so the identity making the call needs the egress role for each destination it should reach. - ## Troubleshoot Gemini Enterprise connection errors | Symptom | Cause | Fix | @@ -715,8 +691,10 @@ No. The client ID identifies Gemini Enterprise as an application, not as a user. The client is a public OAuth client with no secret. Client ID Metadata Document clients cannot use shared secrets, so C1 never reads the field. Security comes from the authorization code flow with PKCE, which you turn on with **Enable PKCE Support**. - -No. C1 governs the tool calls, and this was tested rather than taken on trust. See [Optional: Govern the server through Agent Registry](#optional-govern-the-server-through-agent-registry) for the evidence. + +No, and this was tested rather than taken on trust. A working connector reports `use_agent_gateway_egress: false`, so its traffic never passes through Agent Gateway, and a setup built with no gateway and no registry discovers tools and serves live tool calls normally. C1 governs the tool calls. + +Agent Registry is a catalog of approved MCP servers. Listing the C1 gateway there is a separate exercise that changes nothing about this integration. If you do list it, still create your data connector from the **Custom MCP Server** card: a connector imported from the registry fails tool discovery. From 6822b833325074a69df6e5a908a3539963bd877b Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 18:30:27 -0500 Subject: [PATCH 09/12] docs(mcp): correct the egress constraint, the C1 paths, and the end-user role Final validation pass against the live lab, checking the claims that had been written from reasoning rather than from running them. The egress constraint was wrong twice over. Its name is discoveryengine.managed.allowedEgressFqdns, not discoveryengine.allowedEgressFqdns, and it is a boolean constraint that takes parameters rather than a list of allowed values, so the YAML on this page could not have applied. Both forms are now what the API accepts, confirmed by applying the corrected policy and removing it again. Its description also now says the constraint only reaches projects with VPC Service Controls or projects an organization has explicitly enrolled, which is most of the reason a reader will never meet it. The C1 navigation was stale. Registered clients live under AI, C1 Gateway, on the AI clients tab, with per-user rows on AI connections. Checking this also turned up something worth saying plainly: the Verified column shows the domain hosting your client metadata document, so a self-hosted one reads storage.googleapis.com and not a Google domain. The roles table only ever covered the administrator. End users need roles/discoveryengine.user to open the web app and call anything, and the Google console warns about exactly this while never naming the role. Verified unchanged: the project number command, the public access prevention policy, and both profile-menu paths, including the MCP server URL sitting at the top of AI connections. Co-Authored-By: Claude Opus 5 --- .../admin/mcp-server/gemini-enterprise.mdx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index 470d20d6..9d25e9b0 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -81,6 +81,7 @@ Grant these on the Google Cloud project, except where noted. | `roles/discoveryengine.editor` | Project | Create the data store and authorize the connection | | `roles/orgpolicy.policyAdmin` | **Organization** | Allow custom MCP data connectors. Project **Owner** is not sufficient. | | `roles/storage.admin` | Project | Create the bucket that serves the client metadata document, and make it public. Needed only if you host the document yourself. | +| `roles/discoveryengine.user` | Project | Use the Gemini Enterprise web app and call the actions. Grant this to **every end user**, not just to whoever runs the setup. | To check what you already hold on the project: @@ -218,23 +219,24 @@ Organization policy changes take a minute or two to take effect. Until then the -Some organizations enforce `constraints/discoveryengine.allowedEgressFqdns`, which limits the hosts a data connector may reach. Check it the same way: +Some organizations enforce `constraints/discoveryengine.managed.allowedEgressFqdns`, which limits the hosts a data connector may reach. It applies only to projects with VPC Service Controls enabled, or to projects your organization has added to the constraint's enforced list, so most setups never meet it. Check it with: ```bash -gcloud org-policies describe discoveryengine.allowedEgressFqdns \ +gcloud org-policies describe discoveryengine.managed.allowedEgressFqdns \ --project=YOUR_PROJECT_ID --effective ``` If the constraint has never been set, this command returns `NOT_FOUND: Requested entity was not found`. That is the healthy answer and means nothing is restricting egress. -If it is set, add the two hostnames your tenant uses. Use hostnames only, not full URLs. Save this as `egress.yaml` and apply it with `gcloud org-policies set-policy egress.yaml`, keeping any values your organization already allows: +If it does apply, allow the two hostnames your tenant uses. Use hostnames only, not full URLs. This is a boolean constraint that takes parameters, not a list of allowed values. Save this as `egress.yaml` and apply it with `gcloud org-policies set-policy egress.yaml`, keeping any hostnames your organization already allows: ```yaml -name: projects/YOUR_PROJECT_ID/policies/discoveryengine.allowedEgressFqdns +name: projects/YOUR_PROJECT_ID/policies/discoveryengine.managed.allowedEgressFqdns spec: rules: - - values: - allowedValues: + - enforce: true + parameters: + allowedEgressFqdns: - -mcp.conductor.one - .conductor.one ``` @@ -630,7 +632,11 @@ Ask a question that needs a C1 tool, naming the connector, such as "Using the C1 The assistant names the action it wants to call and waits. Select **Send** to confirm it. -In C1, go to **AI access management** > **AI clients**. The Gemini Enterprise client appears, bound to that user. Users can see their own connections under their profile menu at **AI & API** > **AI connections**. +In C1, go to **AI** > **C1 Gateway** and select the **AI clients** tab. Gemini Enterprise is listed with a registration type of **CIMD**, and **People connected** counts the users who have authorized it. The **AI connections** tab shows one row per user. Users can see their own connections under their profile menu at **AI & API** > **AI connections**. + + +The **Verified** column shows the domain that serves your client metadata document, so a self-hosted document reads `storage.googleapis.com` rather than a Google domain. That is expected while you host the document yourself. + Confirm the tool call was logged. Every call through C1 MCP records the end user, the tool, the result, and a denial reason when refused. See [Audit AI tool usage](/product/admin/audit-ai-tool-usage). @@ -698,7 +704,7 @@ Agent Registry is a catalog of approved MCP servers. Listing the C1 gateway ther -In C1, open **AI access management** > **AI clients**, find the Gemini Enterprise client, and use its **kill switch**. It revokes all tokens for that client immediately, for every user. See [Manage AI clients](/product/admin/ai-clients). +In C1, open **AI** > **C1 Gateway**, select the **AI clients** tab, find the Gemini Enterprise client, and use its **kill switch**. It revokes all tokens for that client immediately, for every user. To cut off one person instead, use **Revoke** on their row in the **AI connections** tab. See [Manage AI clients](/product/admin/ai-clients). From 63ac8fc61b87014fc005bec56f1d7ab984ebc62a Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 18:45:08 -0500 Subject: [PATCH 10/12] docs(mcp): show how to reach every tool inside the action budget The gateway publishes hundreds of tools and a data store can enable a hundred, which reads as a hard ceiling on what Gemini Enterprise can do. It is not one. Eight of the published tools are the code mode set: search_tools finds any tool the caller is allowed to reach and returns its schema, execute runs a short TypeScript program against them, and the vfs and guide tools give that program somewhere to work and something to read. Enable those eight and everything else stays reachable, so the budget goes on the handful of actions users ask for by name. Enabling actions also turned out to be scriptable, which this page had lumped in with creating the connector as console-only. Only creation and discovery are: enabledActions is an ordinary field, verified by writing a fourteenth action into a working connector and reading it back. Creating the connector stays console-only for the reason already given. Both commands are here, with the caveat that the field replaces rather than merges, and a note that none of this widens anyone's access, since every call is still evaluated against the caller's access profiles. Co-Authored-By: Claude Opus 5 --- .../admin/mcp-server/gemini-enterprise.mdx | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index 9d25e9b0..6a692e73 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -462,13 +462,13 @@ Organization policy changes take a minute or two to take effect, in both directi Connect the C1 MCP gateway to your Gemini Enterprise app. -This section and the next are console-only. The public Discovery Engine API refuses to create this connector: +Creating the connector is the one step you cannot script. The public Discovery Engine API refuses it: ```text Data Connector parameters must be one of: oauth_access_token but got: instance_uri ``` -It accepts only a pre-obtained access token, not the OAuth client configuration, so it cannot run the per-user authorization this integration depends on. The method behind **Reload custom actions** is not on the public endpoint either. Every other step in this guide can be scripted. +It accepts only a pre-obtained access token, not the OAuth client configuration, so it cannot run the per-user authorization this integration depends on. Discovering the tool list is console-only too, because the method behind **Reload custom actions** is not on the public endpoint. Choosing which actions are enabled, however, can be scripted once the tools are discovered. See [Enable the actions](#enable-the-actions). @@ -595,6 +595,59 @@ Select **Enable actions**. The actions you selected are now enabled on the connector. No one can call them yet: each user must authorize the connector themselves, which is the first part of [Verify the Gemini Enterprise connection](#verify-the-gemini-enterprise-connection). +### Set the enabled actions from the command line + +Once the tools are discovered, the enabled set is an ordinary field you can write, which is easier to keep consistent across environments than clicking through the table. Read the current list first: + +```bash +curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \ + -H "X-Goog-User-Project: YOUR_PROJECT_ID" \ + "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/collections/YOUR_COLLECTION_ID/dataConnector" +``` + +`dynamicTools` holds every discovered tool and `bapConfig.enabledActions` holds the enabled ones. Write a new set with a `PATCH`, sending the complete list, since it replaces rather than merges: + +```bash +curl -s -X PATCH \ + -H "Authorization: Bearer $(gcloud auth print-access-token)" \ + -H "X-Goog-User-Project: YOUR_PROJECT_ID" \ + -H "Content-Type: application/json" \ + "https://discoveryengine.googleapis.com/v1alpha/projects/YOUR_PROJECT_ID/locations/global/collections/YOUR_COLLECTION_ID/dataConnector?updateMask=bapConfig.enabledActions" \ + -d '{ + "bapConfig": { + "enabledActions": [ + "search_tools", + "execute", + "list_guides", + "load_guide", + "create_vfs", + "create_vfs_artifact", + "list_vfs_files", + "get_vfs_download_url" + ] + } + }' +``` + +Your collection ID is the one shown as **Collection ID** on the data store's **Details** tab. + +### Reach every tool without spending your action budget + +The C1 gateway publishes far more tools than the 100 a data store can enable. Rather than choosing a hundred of them, enable the eight tools above. They let the agent find and run any tool your access profiles allow: + +| Tool | What it does | +| :--- | :--- | +| `search_tools` | Finds the right tool for a task across everything you can reach, and returns its input and output schema | +| `execute` | Runs a short TypeScript program that calls those tools, so several calls happen in one step | +| `list_guides`, `load_guide` | Fetch usage guides for the more involved flows | +| `create_vfs`, `create_vfs_artifact`, `list_vfs_files`, `get_vfs_download_url` | Give that program a scratch filesystem, and hand results back as files | + +Add whichever named C1 actions your users ask for by name on top of those, and the rest stay reachable through `search_tools`. + + +The enabled set still only decides what is offered. Every call is evaluated against the calling user's access profiles, so this changes what the agent can find, never what a person is allowed to do. + + The console toast is not a reliable signal. To see whether a reload actually succeeded, read the audit log: From 3969f9d77292bf1c396542bc4aed3d2f265eb17c Mon Sep 17 00:00:00 2001 From: Melinda Moreland Date: Tue, 25 Aug 2026 16:57:43 -0700 Subject: [PATCH 11/12] docs: apply style guide fixes Co-Authored-By: Claude Sonnet 4.6 --- .../admin/mcp-server/gemini-enterprise.mdx | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index 6a692e73..e67641f5 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -256,7 +256,10 @@ Set this before you create any data store. Google's own warning on this screen i -In the Google Cloud console, open **Gemini Enterprise** and select **Settings**, then the **Authentication** tab. +In the Google Cloud console, open **Gemini Enterprise**. + + +Select **Settings**, then the **Authentication** tab. Find the row for your app's location, such as `global`, and select the edit icon. @@ -297,7 +300,10 @@ A new Gemini Enterprise app has a subscription but no licensed users, and the us -In **Gemini Enterprise**, select **Manage users**. +Open **Gemini Enterprise**. + + +Select **Manage users**. Confirm a subscription is listed and **Active**, and note how many licenses are unassigned. @@ -485,7 +491,10 @@ Finish [Prepare Gemini Enterprise](#prepare-gemini-enterprise) before you open t -In the Google Cloud console, open **Gemini Enterprise** and select your app. +In the Google Cloud console, open **Gemini Enterprise**. + + +Select your app. Select **Connected data stores**, then select **New data store**. @@ -546,7 +555,10 @@ Signing in through **Verify Auth** while creating the connector does not count. -In the Google Cloud console, open **Gemini Enterprise**, select your app, and open **Overview**. +In the Google Cloud console, open **Gemini Enterprise**. + + +Select your app, then open **Overview**. Copy the web app URL shown there. It looks like `https://vertexaisearch.cloud.google.com/home/cid/`. @@ -580,7 +592,7 @@ Wait for the connector state to reach **Active** before you start. The reload fa -Open the data store and select the **Actions** tab. +Open the data store, then select the **Actions** tab. Select **Reload custom actions**. Gemini Enterprise queries your MCP server for its current tool list. From 4f8298c8902cbbc7ae9fd88fa945f0646d91ad3f Mon Sep 17 00:00:00 2001 From: ltsch <140873092+ltsch@users.noreply.github.com> Date: Tue, 25 Aug 2026 19:22:02 -0500 Subject: [PATCH 12/12] docs(mcp): complete the code mode tool set The list I gave was eight tools and it should have been twelve. I built it by pattern-matching names rather than reading what the gateway actually publishes, and four fell out. get_execution is the one that mattered. execute answers inline only if the program finishes in about twenty five seconds; past that it returns a pending status and an execution id, and get_execution is what collects the result. Enabling execute without it means long runs cannot be recovered and the agent reports a failure for work that in fact succeeded, so that pairing now carries a warning. The other three are find_api_objects, count_api_objects and query_metrics, which answer lookup, count and reporting questions directly and save writing a program for them at all. All twelve are confirmed present in the published tool list and enabled on the reference connector. Co-Authored-By: Claude Opus 5 --- product/admin/mcp-server/gemini-enterprise.mdx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/product/admin/mcp-server/gemini-enterprise.mdx b/product/admin/mcp-server/gemini-enterprise.mdx index e67641f5..ea0c7b18 100644 --- a/product/admin/mcp-server/gemini-enterprise.mdx +++ b/product/admin/mcp-server/gemini-enterprise.mdx @@ -630,12 +630,16 @@ curl -s -X PATCH \ "enabledActions": [ "search_tools", "execute", + "get_execution", "list_guides", "load_guide", "create_vfs", "create_vfs_artifact", "list_vfs_files", - "get_vfs_download_url" + "get_vfs_download_url", + "find_api_objects", + "count_api_objects", + "query_metrics" ] } }' @@ -645,17 +649,24 @@ Your collection ID is the one shown as **Collection ID** on the data store's **D ### Reach every tool without spending your action budget -The C1 gateway publishes far more tools than the 100 a data store can enable. Rather than choosing a hundred of them, enable the eight tools above. They let the agent find and run any tool your access profiles allow: +The C1 gateway publishes far more tools than the 100 a data store can enable. Rather than choosing a hundred of them, enable the twelve tools above. They let the agent find and run any tool your access profiles allow: | Tool | What it does | | :--- | :--- | | `search_tools` | Finds the right tool for a task across everything you can reach, and returns its input and output schema | | `execute` | Runs a short TypeScript program that calls those tools, so several calls happen in one step | +| `get_execution` | Collects the result of a program that ran too long to answer inline | | `list_guides`, `load_guide` | Fetch usage guides for the more involved flows | | `create_vfs`, `create_vfs_artifact`, `list_vfs_files`, `get_vfs_download_url` | Give that program a scratch filesystem, and hand results back as files | +| `find_api_objects`, `count_api_objects` | Look up and count C1 objects such as users, apps, and entitlements, without writing a program | +| `query_metrics` | Return bucketed time series for reporting questions in one call | Add whichever named C1 actions your users ask for by name on top of those, and the rest stay reachable through `search_tools`. + +Enable `get_execution` alongside `execute`. A program that runs longer than about 25 seconds returns a pending status and an execution ID instead of a result, and `get_execution` is what collects it. Without it those runs cannot be recovered and the agent reports a failure for work that actually succeeded. + + The enabled set still only decides what is offered. Every call is evaluated against the calling user's access profiles, so this changes what the agent can find, never what a person is allowed to do.