Leçon 3 — Guides pas à pas

10-2. Tout déployer avec le script (`deployer.sh`), pas à pas

12 min de lecture

Ce guide répond à : comment déployer le serveur MCP et l'agent depuis un terminal Mac ou Linux, sans Docker, une étape à la fois, en sachant à chaque fois ce qui est créé et ce qu'on doit voir ?

Équivalents : Terraform 10-3, console 10-4. Branchement sur Gemini Enterprise : 10-5 (connecteur) et 10-6 (agent).

Testé en vrai (14 octobre 2026), sur deux projets neufs (agents et app), dans cet ordre : verifier, preparer, mcp, agent, agent-runtime, registre, droits-app, tester, nettoyer. Résultats réels dans chaque partie.

autorisation et ajouter-app demandent une app Gemini Enterprise : ils n'ont pas été lancés. Ils envoient le format validé au projet 09.


Sommaire

  1. Avant de commencer
  2. La configuration
  3. verifier : lecture seule
  4. preparer : API et comptes
  5. mcp : le serveur MCP
  6. agent et agent-runtime : l'agent
  7. registre : Agent Registry
  8. fiche : ce qu'on saisit dans Gemini Enterprise
  9. droits-app, autorisation, ajouter-app : côté app
  10. tester
  11. nettoyer
  12. Les mêmes étapes, commande par commande

0. Avant de commencer

Il fautComment vérifier
gcloud connectégcloud auth login puis gcloud auth list (une étoile sur votre compte)
Le projet des agents avec facturation./scripts/deployer.sh verifier (partie 2)
Vos droitsverifier les liste ; à défaut, demander les rôles affichés
Le client OAuth déjà créé (son ID)10-5, étape 1 : le serveur refuse de démarrer sans
Python 3python3 --version (pour la fiche et Agent Runtime : bibliothèque standard seulement)

1. La configuration

Ouvrez config/10-mcp.env. Les valeurs du projet des agents Acme y sont déjà ; l'app peut rester vide.

LigneValeurOù la trouver
PROJET / NUM_PROJETaiml-gemini-ent-exp-0zga / 433175138344Console → sélecteur de projet
REGIONeurope-west1App en eu → région europe-*
OAUTH_CLIENT_IDS…apps.googleusercontent.comLe client OAuth créé en 10-5, étape 1
ALLOWED_DOMAINSacme.exampleLes comptes acceptés
PROJET_APP, NUM_APP, APP_IDvide pour l'instantSeulement pour les actions « côté app »

Puis, dans le terminal, dans le dossier du projet 10 :

source scripts/config.sh config/10-mcp.env

Résultat obtenu :

== Configuration chargée : config/10-mcp.env
   Projet (MCP + agent)  : aiml-gemini-ent-exp-0zga (n° 433175138344), région europe-west1
   Serveur MCP           : https://sheets-mcp-433175138344.europe-west1.run.app/mcp
   Agent A2A             : https://sheets-agent-433175138344.europe-west1.run.app
   App Gemini Enterprise : (pas encore)
   Clients OAuth acceptés: (AUCUN : le serveur MCP refusera de démarrer ; docs/10-5, étape 1)
   Domaines acceptés     : acme.example

Les adresses sont connues d'avance : Cloud Run les forme avec le numéro du projet et la région.

Sans toucher au fichier (par exemple pour les valeurs de prod de l'app), donnez-les devant la commande :

PROJET_APP=acme-gemini-prod NUM_APP=523307489860 APP_ID=gemini-enterprise-app \
  source scripts/config.sh config/10-mcp.env

2. verifier : lecture seule

./scripts/deployer.sh verifier

Ne change rien. Il vérifie :

  • le compte connecté ;
  • la facturation du projet ;
  • les API ;
  • vos droits (en comptant ceux reçus par un groupe) ;
  • ce qui est déjà déployé.

Résultat obtenu (projet de test, facturation fermée) :

== Facturation de second-pr-511015 : DÉSACTIVÉE (False)
   !! Sans facturation : Cloud Run, Cloud Build, Vertex AI et Agent Runtime refusent.
== API
   OK       run
   …
== Vos droits sur second-pr-511015 (groupes compris)
   OK       activer les API
   OK       créer les comptes de service
   …
   OK       Agent Registry (facultatif)
== Déjà là
   (pas de service sheets-mcp)
   (pas de service sheets-agent)
   Agent Runtime : (aucun)
!! OAUTH_CLIENT_IDS vide : créez le client OAuth (docs/10-5, étape 1) avant « mcp ».

Une ligne MANQUANT … -> demander roles/… dit précisément quel rôle demander.

3. preparer : API et comptes

./scripts/deployer.sh preparer
CrééPourquoi
API : Cloud Run, Cloud Build, Artifact Registry, IAM, Logging, Sheets, Drive, Vertex AI (+ Agent Registry si autorisé)Sheets et Drive sont appelées au nom des utilisateurs ; leurs quotas comptent sur ce projet
sheets-build-sa + storage.objectViewer, artifactregistry.writer, logging.logWriterCloud Build construit les images avec ce compte (le compte par défaut n'a souvent pas ces droits, vu au projet 09)
sheets-mcp-sa, sans aucun rôleLe serveur n'agit qu'avec le jeton de l'utilisateur
sheets-agent-sa + aiplatform.user, logging.logWriterL'agent appelle Gemini et écrit ses journaux

Résultat obtenu (projet neuf, extrait) :

▶ gcloud services enable cloudresourcemanager.googleapis.com serviceusage.googleapis.com run.googleapis.com … --project=second-project-511608
Operation "operations/acf.p2-872505552973-…" finished successfully.
▶ gcloud iam service-accounts create sheets-build-sa …
  sheets-build-sa : roles/storage.objectViewer
  sheets-build-sa : roles/artifactregistry.writer
  sheets-build-sa : roles/logging.logWriter
▶ gcloud iam service-accounts create sheets-mcp-sa …
▶ gcloud iam service-accounts create sheets-agent-sa …
  sheets-agent-sa : roles/aiplatform.user
  sheets-agent-sa : roles/logging.logWriter
Prêt. Attendez 1 à 2 minutes (droits des nouveaux comptes), puis : ./scripts/deployer.sh mcp
``` Relancer est sans danger : vous verrez `compte … : existe déjà`.

## 4. `mcp` : le serveur MCP

> **Sheets et Slides.** `./scripts/deployer.sh mcp` construit **une** image et déploie **deux** services :
> `sheets-mcp` et `slides-mcp` (variable `PRODUIT`). `./scripts/deployer.sh mcp sheets` : seulement Sheets.
> Slides : [10-13](10-13-serveur-mcp-google-slides.md). Ci-dessous, l'exemple de Sheets.

```bash
./scripts/deployer.sh mcp

Le script lance :

gcloud artifacts repositories create sheets-mcp --repository-format=docker --location=europe-west1 …   # 1re fois
gcloud builds submit mcp_server --config=cloudbuild.yaml --substitutions=_IMAGE=europe-west1-docker.pkg.dev/…/sheets-mcp/sheets-mcp:<date> \
  --region=europe-west1 --project=… --service-account=projects/…/serviceAccounts/sheets-build-sa@…
gcloud run deploy sheets-mcp --image=<la même image> --region=europe-west1 --project=… --service-account=sheets-mcp-sa@… \
  --no-allow-unauthenticated --env-vars-file=<OAUTH_CLIENT_IDS, ALLOWED_DOMAINS> \
  --memory=512Mi --cpu=1 --min-instances=0 --max-instances=5 --timeout=120 --quiet
  • gcloud builds submit mcp_server : le dossier est envoyé à Cloud Build, qui construit l'image avec le Dockerfile, comme au projet 09. Vous n'avez pas besoin de Docker sur votre poste. cloudbuild.yaml envoie les journaux vers Cloud Logging, ce qui est obligatoire avec un compte de construction dédié.
  • --no-allow-unauthenticated : le service est privé. Il faut roles/run.invoker pour l'appeler.
  • Les variables passent par un fichier (--env-vars-file), parce que OAUTH_CLIENT_IDS peut contenir des virgules.

Résultat obtenu (2 minutes en tout ; construction : 39 s) :

ID                                    CREATE_TIME                DURATION  …  IMAGES                                                                       STATUS
043e5fa0-…                            2026-10-14T08:09:41+00:00  39S       …  europe-west1-docker.pkg.dev/second-project-511608/sheets-mcp/sheets-mcp:…   SUCCESS
Service [sheets-mcp] revision [sheets-mcp-00001-brp] has been deployed and is serving 100 percent of traffic.
Service URL: https://sheets-mcp-872505552973.europe-west1.run.app
Serveur MCP : https://sheets-mcp-872505552973.europe-west1.run.app/mcp (privé : sans droit run.invoker, Cloud Run répond 403).

Chez Acme, l'adresse sera https://sheets-mcp-433175138344.europe-west1.run.app/mcp. Le premier déploiement crée aussi le dépôt d'images sheets-mcp (Artifact Registry).

Vérifier tout de suite :

curl -s -o /dev/null -w '%{http_code}\n' -X POST $MCP_URL     # 403 attendu : privé

Changer les clients OAuth acceptés (par exemple pour ajouter celui de l'agent) : modifiez OAUTH_CLIENT_IDS, rechargez la configuration, relancez mcp. Cela crée une nouvelle révision, à la même adresse.

5. agent et agent-runtime : l'agent

Sur Cloud Run (A2A) :

./scripts/deployer.sh agent
  • Cloud Build construit l'image de agent/ ;
  • le service sheets-agent reçoit ses variables : MCP_URL, AGENT_URL, AUTH_ID, MODEL, GOOGLE_CLOUD_PROJECT ;
  • le script donne ensuite à sheets-agent-sa le droit d'appeler le serveur MCP (run.invoker sur sheets-mcp).

Résultat obtenu (construction : 1 min 06) :

… europe-west1-docker.pkg.dev/second-project-511608/sheets-mcp/sheets-agent:…  SUCCESS
Service URL: https://sheets-agent-872505552973.europe-west1.run.app
  serviceAccount:sheets-agent-sa@second-project-511608.iam.gserviceaccount.com : roles/run.invoker sur sheets-mcp
Agent A2A : https://sheets-agent-872505552973.europe-west1.run.app   carte : ./scripts/deployer.sh fiche

Au 1er essai, le conteneur ne démarrait pas : ImportError: cannot import name 'McpToolset'. google-adk n'installe pas le client mcp tout seul. Il est maintenant dans agent/requirements.txt. Si vous voyez « container failed to start », lisez les journaux du service (Cloud Run → sheets-agent → Logs).

Sur Agent Runtime :

./scripts/deployer.sh agent-runtime
  • Envoie le code de agent/ à Agent Runtime (pas d'image), avec le même compte sheets-agent-sa ;
  • AUTH_ID=acces-sheets-runtime : sur Agent Runtime, l'autorisation contient en plus la portée cloud-platform (10-6).

Résultat obtenu (3 min 40) :

opération : projects/100000000004/locations/europe-west1/reasoningEngines/3950050498366668800/operations/…
  en cours… 0 s
  …
  en cours… 220 s
déployé : projects/100000000004/locations/europe-west1/reasoningEngines/3950050498366668800

C'est le chemin à coller dans l'app.

Pas de doublon : relancé, le script affiche déjà déployé : …. Pour une nouvelle version : nettoyer, puis relancer.

6. registre : Agent Registry

./scripts/deployer.sh registre
  1. scripts/gen_toolspec.py fabrique terraform/toolspec.json, la liste des 17 outils, depuis le code. Résultat obtenu : terraform/toolspec.json : 17 outils, 6917 octets (maximum Agent Registry : 10 Ko).
  2. gcloud agent-registry services create sheets-mcp --mcp-server-spec-type=tool-spec --interfaces=url=$MCP_URL,protocolBinding=jsonrpc ….
  3. La liste des serveurs MCP du registre.

Résultat obtenu :

Created service [sheets-mcp].
DISPLAY_NAME         NAME
Google Sheets (MCP)  agentregistry-00000000-0000-0000-54c7-0952cef8d6eb

Au 1er essai, Agent Registry a refusé : invalid MCP tool spec content: tools.0: inputSchema is required. Le schéma des paramètres est maintenant inclus, en compact, sous la limite de 10 Ko.

Détails : 10-7. Si l'organisation bloque Agent Registry, l'étape est facultative.

7. fiche : ce qu'on saisit dans Gemini Enterprise

./scripts/deployer.sh fiche

Affiche, pour chaque modalité, tous les champs de la console :

  • le connecteur natif (URL, OAuth, PKCE, portées, domaines de sortie, droit) ;
  • l'agent A2A (la carte sur une ligne, l'autorisation) ;
  • l'agent Agent Runtime (le chemin, l'autorisation avec cloud-platform).

Elle ne crée rien.

Résultat obtenu (extrait) :

================ Modalité 1 : connecteur natif « Custom MCP Server » (docs/10-5) ================
Console : Gemini Enterprise → Data stores → Create data store → « Custom MCP Server » → Add MCP server
     Authentication        : OAuth 2.0
     MCP Server URL        : https://sheets-mcp-433175138344.europe-west1.run.app/mcp
     Authorization URL     : https://accounts.google.com/o/oauth2/v2/auth
     Auth URL parameters   : access_type=offline&prompt=consent&hd=acme.example
     Token URL             : https://oauth2.googleapis.com/token
     Enable PKCE           : coché
     Scopes                : openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive.metadata.readonly
     …
================ Modalité 2 : agent A2A sur Cloud Run (docs/10-6) ================
  1. Carte, TOUTE la ligne :
     {"protocolVersion": "0.3", "name": "sheets_agent", …}
  2. Nom : Assistant Google Sheets (A2A)
  3. Authentication (ne PAS cliquer Skip) :
     Nom de l'autorisation : acces-sheets
     Authorization URL     : https://accounts.google.com/o/oauth2/auth?client_id=…&access_type=offline&prompt=consent
     …

8. droits-app, autorisation, ajouter-app : côté app

Ces actions demandent les valeurs de l'app : NUM_APP, et pour les deux dernières PROJET_APP et APP_ID.

ActionFaitConfirmation
droits-appAffiche le plan, puis donne au compte de l'app : ① run.invoker sur sheets-mcp (et sheets-agent s'il existe), ② discoveryengine.serviceAgent sur le projet (si un agent Agent Runtime existe)Taper l'ID du projet (ou --oui)
autorisation client_secret.json [a2a|runtime]Crée l'autorisation OAuth de l'agent dans l'app, avec le nom affiché « Google Sheets » et les bonnes portées–
ajouter-app [a2a|runtime]Ajoute l'agent à l'app avec son autorisation, les questions proposées et la langue fr. Ne crée pas de doublon–

Résultat obtenu (droits-app --oui, compte d'un autre projet, celui de l'app) :

Plan, pour le compte de l'app service-100000000005@gcp-sa-discoveryengine.iam.gserviceaccount.com :
  ① roles/run.invoker sur sheets-mcp        (connecteur « Custom MCP Server »)
  ① roles/run.invoker sur sheets-agent      (agent A2A)
  ② roles/discoveryengine.serviceAgent sur le projet second-project-511608 (agent Agent Runtime)
  serviceAccount:service-100000000005@… : roles/run.invoker sur sheets-mcp
  serviceAccount:service-100000000005@… : roles/run.invoker sur sheets-agent
  service-100000000005 : roles/discoveryengine.serviceAgent

Le compte de l'app n'existe qu'une fois Gemini Enterprise activé dans le projet de l'app. C'est le cas chez Acme. Sur un projet de test : gcloud services enable discoveryengine.googleapis.com puis gcloud beta services identity create --service=discoveryengine.googleapis.com --project=<projet de l'app>.

Le connecteur natif (chemin 1) n'a pas d'API publique : il se crée dans la console (10-5).

9. tester

export USER_TOKEN=<jeton utilisateur avec la portée Sheets>   # 10-8, partie 2
export SPREADSHEET_ID=<classeur que ce compte peut modifier>
./scripts/deployer.sh tester

Le script fait 4 tests :

  1. Sans jeton, il vérifie que Cloud Run répond 403.
  2. Le serveur MCP est appelé avec les deux en-têtes du connecteur, et les 17 outils sont lancés sur le vrai classeur (tests/test_reel.py).
  3. L'agent A2A reçoit une question, comme le ferait Gemini Enterprise.
  4. L'agent Agent Runtime reçoit une question, avec le jeton dans authorizations.

Le serveur doit accepter le client OAuth qui a émis le jeton de test (10-8).

Résultat obtenu (Cloud Run, 14 octobre 2026) :

== 1. Sans aucun jeton : Cloud Run doit refuser (403)
   403
== 2. Le serveur MCP, comme le connecteur de Gemini Enterprise (2 en-têtes), les 17 outils sur le vrai classeur
tools/list : 17 outils
whoami                : sheets-utilisateur-test@second-project-511608.iam.gserviceaccount.com
…
batch_update (tri)    : [['Vélo', 299, 358.8], ['Tente', 149, 178.8], ['Sac', 39, 46.8]]
…
delete_sheet          : test-mcp-101100-r (classeur rendu intact)
OK : test réel terminé
== 3. L'agent A2A, comme Gemini Enterprise
état : completed
Le classeur se nomme « MCP Sheets - test Acme (projet 10) ». Liste des onglets : Untitled.
3 premières lignes : Produit, Prix, Stock / Vélo, 299, 12 / Tente, 149, 30
== 4. L'agent Agent Runtime, comme Gemini Enterprise
Le stock du Vélo est de 12 unités (au prix de 299 €).

L'écriture par l'agent, sur plusieurs tours de conversation : 10-8, partie 4.

10. nettoyer

./scripts/deployer.sh nettoyer
  1. Affiche l'inventaire : services, agent Agent Runtime, entrée Agent Registry, comptes.
  2. Demande de taper l'ID du projet.
  3. Supprime tout (y compris le dépôt d'images sheets-mcp), en retirant d'abord les rôles des comptes et le droit ② du compte de l'app.

Résultat obtenu (extrait) :

▶ gcloud run services delete sheets-mcp … Deleted service [sheets-mcp].
▶ gcloud run services delete sheets-agent … Deleted service [sheets-agent].
▶ … deployer_agent_runtime.py --supprimer projects/100000000004/…/reasoningEngines/3950050498366668800
supprimé : projects/100000000004/locations/europe-west1/reasoningEngines/3950050498366668800
▶ gcloud agent-registry services delete sheets-mcp … Deleted service [sheets-mcp].
  retiré : roles/aiplatform.user de sheets-agent-sa@…
  …
deleted service account [sheets-build-sa@…]
Deleted repository [sheets-mcp].
Terminé.

Les agents et le connecteur ajoutés dans l'app se retirent dans la console de l'app (10-9).

11. Les mêmes étapes, commande par commande

Pour voir chaque commande sans le script (configuration chargée) :

# preparer
gcloud services enable run.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com iam.googleapis.com \
  logging.googleapis.com sheets.googleapis.com drive.googleapis.com aiplatform.googleapis.com --project=$PROJET
gcloud iam service-accounts create sheets-build-sa --project=$PROJET
for r in storage.objectViewer artifactregistry.writer logging.logWriter; do
  gcloud projects add-iam-policy-binding $PROJET --role=roles/$r --member=serviceAccount:$BUILD_SA --condition=None; done
gcloud iam service-accounts create sheets-mcp-sa --project=$PROJET
gcloud iam service-accounts create sheets-agent-sa --project=$PROJET
for r in aiplatform.user logging.logWriter; do
  gcloud projects add-iam-policy-binding $PROJET --role=roles/$r --member=serviceAccount:$AGENT_SA --condition=None; done

# mcp (image construite par Cloud Build, puis service)
gcloud artifacts repositories create sheets-mcp --repository-format=docker --location=$REGION --project=$PROJET
IMG=$REGION-docker.pkg.dev/$PROJET/sheets-mcp
gcloud builds submit mcp_server --config=cloudbuild.yaml --substitutions=_IMAGE=$IMG/sheets-mcp:v1 \
  --region=$REGION --project=$PROJET --service-account=projects/$PROJET/serviceAccounts/$BUILD_SA
printf 'OAUTH_CLIENT_IDS: "%s"\nALLOWED_DOMAINS: "%s"\n' "$OAUTH_CLIENT_IDS" "$ALLOWED_DOMAINS" > env-mcp.yaml
gcloud run deploy sheets-mcp --image=$IMG/sheets-mcp:v1 --region=$REGION --project=$PROJET --service-account=$MCP_SA \
  --no-allow-unauthenticated --env-vars-file=env-mcp.yaml

# agent (A2A)
gcloud builds submit agent --config=cloudbuild.yaml --substitutions=_IMAGE=$IMG/sheets-agent:v1 \
  --region=$REGION --project=$PROJET --service-account=projects/$PROJET/serviceAccounts/$BUILD_SA
printf 'MCP_URL: "%s"\nAGENT_URL: "%s"\nAUTH_ID: "%s"\nMODEL: "%s"\nGOOGLE_CLOUD_PROJECT: "%s"\n' \
  "$MCP_URL" "$AGENT_URL" "$AUTH_ID" "$MODEL" "$PROJET" > env-agent.yaml
gcloud run deploy sheets-agent --image=$IMG/sheets-agent:v1 --region=$REGION --project=$PROJET --service-account=$AGENT_SA \
  --no-allow-unauthenticated --env-vars-file=env-agent.yaml --max-instances=1 --memory=1Gi --timeout=300
gcloud run services add-iam-policy-binding sheets-mcp --region=$REGION --project=$PROJET \
  --role=roles/run.invoker --member=serviceAccount:$AGENT_SA

# la carte de l'agent (à coller dans l'app)
python3 agent/carte.py $AGENT_URL
Suivant