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.
autorisationetajouter-appdemandent une app Gemini Enterprise : ils n'ont pas été lancés. Ils envoient le format validé au projet 09.
Sommaire
- Avant de commencer
- La configuration
verifier: lecture seulepreparer: API et comptesmcp: le serveur MCPagentetagent-runtime: l'agentregistre: Agent Registryfiche: ce qu'on saisit dans Gemini Enterprisedroits-app,autorisation,ajouter-app: côté apptesternettoyer- Les mêmes étapes, commande par commande
0. Avant de commencer
| Il faut | Comment 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 droits | verifier 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 3 | python3 --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.
| Ligne | Valeur | Où la trouver |
|---|---|---|
PROJET / NUM_PROJET | aiml-gemini-ent-exp-0zga / 433175138344 | Console → sélecteur de projet |
REGION | europe-west1 | App en eu → région europe-* |
OAUTH_CLIENT_IDS | …apps.googleusercontent.com | Le client OAuth créé en 10-5, étape 1 |
ALLOWED_DOMAINS | acme.example | Les comptes acceptés |
PROJET_APP, NUM_APP, APP_ID | vide pour l'instant | Seulement pour les actions « côté app » |
Puis, dans le terminal, dans le dossier du projet 10 :
source scripts/config.sh config/10-mcp.envRé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.env2. verifier : lecture seule
./scripts/deployer.sh verifierNe 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.logWriter | Cloud 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ôle | Le serveur n'agit qu'avec le jeton de l'utilisateur |
sheets-agent-sa + aiplatform.user, logging.logWriter | L'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 --quietgcloud builds submit mcp_server: le dossier est envoyé à Cloud Build, qui construit l'image avec leDockerfile, comme au projet 09. Vous n'avez pas besoin de Docker sur votre poste.cloudbuild.yamlenvoie les journaux vers Cloud Logging, ce qui est obligatoire avec un compte de construction dédié.--no-allow-unauthenticated: le service est privé. Il fautroles/run.invokerpour l'appeler.- Les variables passent par un fichier (
--env-vars-file), parce queOAUTH_CLIENT_IDSpeut 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-agentreçoit ses variables :MCP_URL,AGENT_URL,AUTH_ID,MODEL,GOOGLE_CLOUD_PROJECT; - le script donne ensuite à
sheets-agent-sale droit d'appeler le serveur MCP (run.invokersursheets-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 comptesheets-agent-sa; AUTH_ID=acces-sheets-runtime: sur Agent Runtime, l'autorisation contient en plus la portéecloud-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 registrescripts/gen_toolspec.pyfabriqueterraform/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).gcloud agent-registry services create sheets-mcp --mcp-server-spec-type=tool-spec --interfaces=url=$MCP_URL,protocolBinding=jsonrpc ….- 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 ficheAffiche, 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.
| Action | Fait | Confirmation |
|---|---|---|
droits-app | Affiche 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 testerLe script fait 4 tests :
- Sans jeton, il vérifie que Cloud Run répond
403. - 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). - L'agent A2A reçoit une question, comme le ferait Gemini Enterprise.
- 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- Affiche l'inventaire : services, agent Agent Runtime, entrée Agent Registry, comptes.
- Demande de taper l'ID du projet.
- 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