1. Introducción
En este codelab, se explica cómo compilar un servidor de MCP (protocolo de contexto del modelo) personalizado con Python, implementarlo en Google Cloud Run y conectarlo con la CLI de Gemini para ejecutar operaciones reales de Google Cloud Storage con lenguaje natural.
Flujo de arquitectura: Gemini CLI → Cloud Run → MCP

Imagina lo siguiente: abres la terminal y escribes una instrucción simple en un agente de IA, como las que se muestran a continuación:
List my GCS bucketsCreate a GCS bucket named <bucket-name>Tell me about the metadata of my GCS object
En cuestión de segundos, la nube escucha y ejecuta. No hay comandos complicados. No tendrás que cambiar de pestaña sin parar. Solo lenguaje simple que se convierte en acciones reales en la nube.
Actividades
Crearás e implementarás un servidor de MCP personalizado que conecte la CLI de Gemini con Google Cloud Storage.
Harás lo siguiente:
- Crea un servidor de MCP basado en Python
- Organiza la aplicación en contenedores
- Implementa en Cloud Run
- Cómo protegerlo con IAM y tokens de identidad
- Conéctala con Gemini CLI
- Ejecuta operaciones de GCS en vivo con lenguaje natural
Qué aprenderás
- Qué es el MCP (Protocolo de contexto del modelo) y cómo funciona
- Cómo compilar capacidades de llamadas a herramientas con Python
- Cómo implementar aplicaciones alojadas en contenedores en Cloud Run
- Cómo se integra Gemini CLI con servidores de MCP externos
- Cómo autenticar de forma segura los servicios de Cloud Run
- Cómo ejecutar operaciones reales de Google Cloud Storage con IA
Requisitos
- Navegador web Chrome
- Una cuenta de Gmail
- Un proyecto de Google Cloud con la facturación habilitada
- Gemini CLI (viene preinstalada con Google Cloud Shell)
- Conocimientos básicos sobre Python y Google Cloud
En este codelab, se espera que el usuario tenga conocimientos básicos de Python.
2. Antes de comenzar
Crea un proyecto
- En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.
- Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Obtén información para verificar si la facturación está habilitada en un proyecto .
- Usarás Cloud Shell, un entorno de línea de comandos que se ejecuta en Google Cloud y que viene precargado con bq. Haz clic en Activar Cloud Shell en la parte superior de la consola de Google Cloud.

- Una vez que te conectes a Cloud Shell, verifica que ya te autenticaste y que el proyecto se configuró con tu ID del proyecto usando el siguiente comando:
gcloud auth list
- En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto.
gcloud config list project
- Si tu proyecto no está configurado, usa el siguiente comando para hacerlo:
gcloud config set project <YOUR_PROJECT_ID>
- Habilita las APIs requeridas con el comando que se muestra a continuación. Este proceso puede tardar unos minutos, así que ten paciencia.
gcloud services enable \
run.googleapis.com \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com
Si se te solicita autorización, haz clic en Autorizar para continuar.

Cuando el comando se ejecute correctamente, deberías ver un mensaje similar al que se muestra a continuación:
Operation "operations/..." finished successfully.
Si olvidas alguna API, siempre puedes habilitarla durante el curso de la implementación.
Consulta la documentación para ver los comandos y el uso de gcloud.
Prepara tu proyecto de Python
En esta sección, crearás el proyecto de Python que alojará tu servidor de MCP y configurarás sus dependencias para la implementación en Cloud Run.
Crea el directorio del proyecto
Comienza por crear una carpeta nueva llamada mcp-on-cloudrun para almacenar tu código fuente:
mkdir gcs-mcp-server && cd gcs-mcp-server
Crea el archivo requirements.txt
touch requirements.txt
cloudshell edit ~/gcs-mcp-server/requirements.txt
Agrega el siguiente contenido al archivo:
fastmcp
google-cloud-storage
google-api-core
pydantic
Guarda el archivo.
3. Crea el servidor de MCP
En esta sección, crearás el servidor de MCP que expone las operaciones de Google Cloud Storage como herramientas invocables.
Este servidor hará lo siguiente:
- Registra herramientas de MCP
- Conéctate a Google Cloud Storage
- Ejecutar a través de HTTP
- Debe poder implementarse en Cloud Run
Ahora, creemos nuestra lógica principal del MCP dentro de main.py.
A continuación, se muestra el código completo que define varias herramientas para administrar Google Cloud Storage, desde la creación y la enumeración de buckets hasta la carga, la descarga y la administración de BLOBs.
Crea el archivo principal de la aplicación
Dentro del directorio mcp-on-cloudrun, crea un archivo nuevo llamado main.py:
touch main.py
Abre el archivo con el editor de Cloud Shell:
cloudshell edit ~/gcs-mcp-server/main.py
Agrega la siguiente fuente al contenido del archivo main.py:
import asyncio
import logging
import os
from datetime import timedelta
from typing import List, Dict, Any
from fastmcp import FastMCP
from google.cloud import storage
from google.api_core import exceptions
# ---------------------------------------------------------
# 🌐 Initialize MCP
# ---------------------------------------------------------
logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)
logger = logging.getLogger(__name__)
mcp = FastMCP(name="MyEnhancedGCSMCPServer")
# ---------------------------------------------------------
# 1️⃣ Simple Greeting
# ---------------------------------------------------------
@mcp.tool
def sayhi(name: str) -> str:
"""Returns a friendly greetings"""
return f"Hello {name}! It's a pleasure to connect from your enhanced MCP Server."
# ---------------------------------------------------------
# 2️⃣ List all GCS buckets
# ---------------------------------------------------------
@mcp.tool
def list_gcs_buckets() -> List[str]:
"""Lists all GCS buckets in the project."""
try:
storage_client = storage.Client()
buckets = storage_client.list_buckets()
return [bucket.name for bucket in buckets]
except exceptions.Forbidden as e:
return [f"Error: Permission denied to list buckets. Details: {e}"]
except Exception as e:
return [f"An unexpected error occurred: {e}"]
# ---------------------------------------------------------
# 3️⃣ Create a new bucket
# ---------------------------------------------------------
@mcp.tool
def create_bucket(bucket_name: str, location: str = "US") -> str:
"""Creates a new GCS bucket. Bucket names must be globally unique."""
try:
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
bucket.location = location
storage_client.create_bucket(bucket)
return f"✅ Bucket '{bucket_name}' created successfully in '{location}'."
except exceptions.Conflict:
return f"⚠️ Error: Bucket '{bucket_name}' already exists."
except exceptions.Forbidden as e:
return f"❌ Error: Permission denied to create bucket. Details: {e}"
except Exception as e:
return f"❌ Unexpected error: {e}"
# ---------------------------------------------------------
# 4️⃣ Delete a bucket
# ---------------------------------------------------------
@mcp.tool
def delete_bucket(bucket_name: str) -> str:
"""Deletes a GCS bucket."""
try:
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
bucket.delete(force=True)
return f"🗑️ Bucket '{bucket_name}' deleted successfully."
except exceptions.NotFound:
return f"⚠️ Error: Bucket '{bucket_name}' not found."
except exceptions.Forbidden as e:
return f"❌ Error: Permission denied to delete bucket. Details: {e}"
except Exception as e:
return f"❌ Unexpected error: {e}"
# ---------------------------------------------------------
# 5️⃣ List objects in a bucket
# ---------------------------------------------------------
@mcp.tool
def list_objects(bucket_name: str) -> List[str]:
"""Lists all objects in a specified GCS bucket."""
try:
storage_client = storage.Client()
blobs = storage_client.list_blobs(bucket_name)
return [blob.name for blob in blobs]
except exceptions.NotFound:
return [f"⚠️ Error: Bucket '{bucket_name}' not found."]
except Exception as e:
return [f"❌ Unexpected error: {e}"]
# ---------------------------------------------------------
# Delete file from a bucket
# ---------------------------------------------------------
@mcp.tool
def delete_blob(bucket_name: str, blob_name: str) -> str:
"""Deletes a blob from a GCS bucket."""
try:
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
blob = bucket.blob(blob_name)
blob.delete()
return f"🗑️ Blob '{blob_name}' deleted from bucket '{bucket_name}'."
except exceptions.NotFound:
return f"⚠️ Error: Bucket '{bucket_name}' or blob '{blob_name}' not found."
except exceptions.Forbidden as e:
return f" Permission denied. Details: {e}"
except Exception as e:
return f" Unexpected error: {e}"
# ---------------------------------------------------------
# Get bucket metadata
# ---------------------------------------------------------
@mcp.tool
def get_bucket_metadata(bucket_name: str) -> Dict[str, Any]:
"""Retrieves metadata for a GCS bucket."""
try:
storage_client = storage.Client()
bucket = storage_client.get_bucket(bucket_name)
return {
"id": bucket.id,
"name": bucket.name,
"location": bucket.location,
"storage_class": bucket.storage_class,
"created": bucket.time_created.isoformat() if bucket.time_created else None,
"updated": bucket.updated.isoformat() if bucket.updated else None,
"versioning_enabled": bucket.versioning_enabled,
}
except exceptions.NotFound:
return {"error": f" Bucket '{bucket_name}' not found."}
except Exception as e:
return {"error": f" Unexpected error: {e}"}
# ---------------------------------------------------------
# Get object metadata
# ---------------------------------------------------------
@mcp.tool
def get_blob_metadata(bucket_name: str, blob_name: str) -> Dict[str, Any]:
"""Retrieves metadata for a specific blob."""
try:
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
blob = bucket.get_blob(blob_name)
if not blob:
return {"error": f" Blob '{blob_name}' not found in '{bucket_name}'."}
return {
"name": blob.name,
"bucket": blob.bucket.name,
"size": blob.size,
"content_type": blob.content_type,
"updated": blob.updated.isoformat() if blob.updated else None,
"storage_class": blob.storage_class,
"crc32c": blob.crc32c,
"md5_hash": blob.md5_hash,
}
except exceptions.NotFound:
return {"error": f" Bucket '{bucket_name}' not found."}
except Exception as e:
return {"error": f" Unexpected error: {e}"}
# ---------------------------------------------------------
# 🚀 Entry Point
# ---------------------------------------------------------
if __name__ == "__main__":
port = int(os.getenv("PORT", 8080))
logger.info(f"🚀 Starting Enhanced GCS MCP Server on port {port}")
asyncio.run(
mcp.run_async(
transport="http",
host="0.0.0.0",
port=port,
)
)
Guarda el archivo después de agregar el código.
La estructura de tu proyecto ahora debería verse así:
gcs-mcp-server/
├── requirements.txt
└── main.py
Comprendamos el código brevemente:
Importaciones y configuración:
El código comienza con la importación de las bibliotecas necesarias.
- Bibliotecas estándar:
asynciopara la ejecución asíncrona,loggingpara generar mensajes de estado yospara variables de entorno. - FastMCP: Es el framework principal que se usa para crear el servidor del Protocolo de contexto del modelo.
- Google Cloud Storage: Se importa la biblioteca
google.cloud.storagepara interactuar con GCS, junto conexceptionspara el control de errores.
Inicialización:
Configuramos el formato de registro para ayudar a depurar y hacer un seguimiento de la identidad del servidor. Además, configuramos una instancia de FastMCP llamada MyEnhancedGCSMCPServer. Este objeto (mcp) se usará para registrar todas las herramientas (funciones) que expone el servidor. Definimos las siguientes herramientas:
list_gcs_buckets: Recupera una lista de todos los buckets de almacenamiento en el proyecto de Google Cloud asociado.create_bucket: Crea un bucket nuevo con un nombre y una ubicación específicos.delete_bucket: Borra un bucket existente.list_objects: Enumera todos los archivos (blobs) dentro de un bucket específico.delete_blob: Borra un solo archivo específico de un bucket.get_bucket_metadata: Devuelve detalles técnicos sobre un bucket (ubicación, clase de almacenamiento, estado del control de versiones y hora de creación).get_blob_metadata: Muestra detalles técnicos sobre un archivo específico (tamaño, tipo de contenido, hash MD5 y fecha de última actualización).
Punto de entrada:
Esto configura el puerto, que se establece en 8080 de forma predeterminada si no se configura. Luego, usa asyncio.run() para iniciar el servidor de forma asíncrona con mcp.run_async. Por último, configura el servidor para que se ejecute a través de HTTP (host 0.0.0.0), lo que lo hace accesible para las solicitudes de red entrantes.
4. Crea un contenedor para el servidor de MCP
En esta sección, crearás un Dockerfile para que tu servidor de MCP se pueda implementar en Cloud Run.
Cloud Run requiere una aplicación alojada en contenedores. Definirás cómo se compila y se inicia tu aplicación.
Crea el Dockerfile
Crea un archivo nuevo llamado Dockerfile:
touch Dockerfile
Ábrelo en el editor de Cloud Shell:
cloudshell edit ~/gcs-mcp-server/Dockerfile
Agrega la configuración de Docker
Pega el siguiente contenido en Dockerfile:
FROM python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
RUN apt-get update && apt-get install -y \
build-essential \
gcc \
&& rm -rf /var/lib/apt/lists/*
RUN pip install --upgrade pip
COPY . .
RUN pip install -r requirements.txt
ENV PORT=8080
EXPOSE 8080
CMD ["python", "main.py"]
Guarda el archivo después de agregar el contenido. La estructura de tu proyecto ahora debería verse así:
gcs-mcp-server/
├── requirements.txt
├── main.py
└── Dockerfile
5. Implementa en Cloud Run
Ahora implementa tu servidor de MCP directamente desde la fuente.
Ejecuta el siguiente comando en Cloud Shell:
gcloud run deploy gcs-mcp-server \
--no-allow-unauthenticated \
--region=us-central1 \
--source=. \
--labels=session=buildersdayblr
Cuando se te solicite
- ¿Permitir invocaciones sin autenticación? → No
Cloud Build hará lo siguiente:
- Compila la imagen del contenedor
- Envía el contenedor a Artifact Registry
- Implementa en Cloud Run
Ingresa Y para confirmar que se puede crear el repositorio de Artifact Registry.
Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [us-central1] will be created.
Do you want to continue (Y/n)? Y
Después de la implementación correcta, verás un mensaje de éxito con la URL del servicio de Cloud Run.
También puedes verificar la implementación desde la consola de Google Cloud en Cloud Run → Services.

6. Configuración de Gemini CLI
Hasta ahora, compilamos e implementamos nuestro servidor de MCP en Cloud Run.
Ahora es el momento de la parte divertida: conectarla con Gemini CLI y convertir tus instrucciones en lenguaje natural en acciones reales en la nube.
Otorga permiso de invocador de Cloud Run
Dado que nuestro servicio de Cloud Run es privado, nos autenticaremos con un token de identidad y asignaremos los permisos de IAM correctos.
Implementamos el servicio con --no-allow-unauthenticated, por lo que debes otorgar permiso para invocarlo.
Determina tu ID del proyecto:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
Otórgate el rol de Invocador de Cloud Run:
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
--member=user:$(gcloud config get-value account) \
--role='roles/run.invoker'
Esto permite que tu cuenta invoque de forma segura el servicio de Cloud Run.
Genera un token de identidad
Cloud Run requiere un token de identidad para el acceso autenticado.
Generar uno:
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
export ID_TOKEN=$(gcloud auth print-identity-token)
Verifícalo:
echo $PROJECT_NUMBER
echo $ID_TOKEN
Usarás este token en la configuración de Gemini CLI.
Configura el servidor de MCP en Gemini CLI
Abre el archivo de configuración de Gemini CLI:
cloudshell edit ~/.gemini/settings.json
Agrega la siguiente configuración:
{
"ide": {
"enabled": true,
"hasSeenNudge": true
},
"mcpServers": {
"my-cloudrun-server": {
"httpUrl": "https://gcs-mcp-server-$PROJECT_NUMBER.asia-south1.run.app/mcp",
"headers": {
"Authorization": "Bearer $ID_TOKEN"
}
}
},
"security": {
"auth": {
"selectedType": "cloud-shell"
}
}
}
Valida los servidores de MCP configurados en Gemini CLI
Inicia Gemini CLI en la terminal de Cloud Shell con el siguiente comando:
gemini
Verás el siguiente resultado:

Dentro de Gemini CLI, ejecuta el siguiente comando:
/mcp refresh
/mcp list
Ahora deberías ver tu gcs-cloudrun-serve registrado. A continuación, se muestra una captura de pantalla de ejemplo:

7. Invoca operaciones de Google Cloud Storage a través del lenguaje natural
Crear bucket
Create a bucket named my-ai-bucket in asia-south1 region
Aparecerá un mensaje en el que se te pedirá permiso para invocar la herramienta create_bucket desde el servidor de MCP.

Haz clic en Permitir una vez y, luego, se creará correctamente tu bucket en la región específica que solicitaste.
Enumerar buckets
Para enumerar los buckets, ingresa la siguiente instrucción:
List all my GCS buckets
Borrar bucket
Para borrar un bucket, ingresa la siguiente instrucción (reemplaza <your_bucket_name> por el nombre de tu bucket):
Delete the bucket <your_bucket_name>
Obtén los metadatos del bucket
Para obtener los metadatos de un bucket, ingresa la siguiente instrucción (sustituye <your_bucket_name> por el nombre de tu bucket):
Give me metadata of the <your_bucket_name>
8. Limpia
Antes de decidir borrar el proyecto de Google Cloud, lee toda esta sección, ya que esta acción no se puede revertir.
Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que usaste en este codelab:
- En la consola de Google Cloud, ve a la página Administrar recursos.
- En la lista de proyectos, selecciona el proyecto que quieres borrar.
- Haz clic en Borrar.
En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto de forma permanente.
Si borras el proyecto, se detendrá la facturación de todos los recursos que se usaron en él, incluidos los servicios de Cloud Run y las imágenes de contenedor almacenadas en Artifact Registry.
Como alternativa, si deseas conservar el proyecto, pero quitar el servicio implementado, haz lo siguiente:
- Ve a Cloud Run en la consola de Google Cloud.
- Selecciona el servicio gcs-mcp-server.
- Haz clic en Borrar para quitar el servicio.
o bien, ejecuta el siguiente comando gcloud en la terminal de Cloud Shell.
gcloud run services delete gcs-mcp-server --region=us-central1
9. Conclusión
🎉 ¡Felicitaciones! Acabas de compilar tu primer flujo de trabajo en la nube potenciado por IA.
Implementaste lo siguiente:
- Un servidor de MCP personalizado basado en Python
- Capacidades de llamada a herramientas para Google Cloud Storage
- Creación de contenedores con Docker
- Implementación segura en Cloud Run
- Autenticación basada en la identidad
- Integración con Gemini CLI
Ahora puedes extender esta arquitectura para admitir servicios adicionales de Google Cloud, como BigQuery, Pub/Sub o Compute Engine.
Este patrón muestra cómo los sistemas de IA pueden interactuar de forma segura con la infraestructura de la nube a través de la invocación estructurada de herramientas.