1. Introduzione
Panoramica
In questo lab creerai e implementerai un server Model Context Protocol (MCP). I server MCP sono utili per fornire agli LLM l'accesso a strumenti e servizi esterni. Lo configurerai come servizio sicuro e pronto per la produzione su Cloud Run, a cui è possibile accedere da più client. A questo punto, ti connetterai al server MCP remoto dalla CLI Gemini.
In questo lab proverai a:
Utilizzeremo FastMCP per creare un server MCP zoo con due strumenti: get_animals_by_species
e get_animal_details
. FastMCP fornisce un modo rapido e Pythonico per creare server e client MCP.
Obiettivi didattici
- Esegui il deployment del server MCP in Cloud Run.
- Proteggi l'endpoint del server richiedendo l'autenticazione per tutte le richieste, in modo che solo i client e gli agenti autorizzati possano comunicare con esso.
- Connettiti all'endpoint del server MCP sicuro da Gemini CLI
2. Configurazione del progetto
- Se non hai ancora un Account Google, devi crearne uno.
- Utilizza un account personale anziché un account di lavoro o della scuola. Gli account di lavoro e della scuola potrebbero avere limitazioni che impediscono l'attivazione delle API necessarie per questo lab.
- Accedi a Google Cloud Console.
- Abilita la fatturazione in Cloud Console.
- Il completamento di questo lab dovrebbe costare meno di 1 $in risorse cloud.
- Per evitare ulteriori addebiti, puoi seguire i passaggi alla fine di questo lab per eliminare le risorse.
- I nuovi utenti hanno diritto alla prova senza costi di 300$.
- Crea un nuovo progetto o scegli di riutilizzarne uno esistente.
3. Apri editor di Cloud Shell
- Fai clic su questo link per andare direttamente all'editor di Cloud Shell.
- Se ti viene richiesto di autorizzare in qualsiasi momento della giornata, fai clic su Autorizza per continuare.
- Se il terminale non viene visualizzato nella parte inferiore dello schermo, aprilo:
- Fai clic su Visualizza.
- Fai clic su Terminale
.
- Nel terminale, imposta il progetto con questo comando:
- Formato:
gcloud config set project [PROJECT_ID]
- Esempio:
gcloud config set project lab-project-id-example
- Se non ricordi l'ID progetto:
- Puoi elencare tutti gli ID progetto con:
gcloud projects list | awk '/PROJECT_ID/{print $2}'
- Puoi elencare tutti gli ID progetto con:
- Formato:
- Dovresti vedere questo messaggio:
Se visualizzi unUpdated property [core/project].
WARNING
e ti viene chiestoDo you want to continue (Y/n)?
, probabilmente hai inserito l'ID progetto in modo errato. Premin
, premiEnter
e prova a eseguire di nuovo il comandogcloud config set project
.
4. Abilita API
Nel terminale, abilita le API:
gcloud services enable \
run.googleapis.com \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com
Se ti viene richiesto di concedere l'autorizzazione, fai clic su Autorizza per continuare.
Il completamento di questo comando potrebbe richiedere alcuni minuti, ma alla fine dovrebbe essere visualizzato un messaggio di operazione riuscita simile a questo:
Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.
5. Prepara il progetto Python
- Crea una cartella denominata
mcp-on-cloudrun
per archiviare il codice sorgente per il deployment:mkdir mcp-on-cloudrun && cd mcp-on-cloudrun
- Crea un progetto Python con lo strumento
uv
per generare un filepyproject.toml
: Il comandouv init --description "Example of deploying an MCP server on Cloud Run" --bare --python 3.13
uv init
crea un filepyproject.toml
per il tuo progetto.Per visualizzare i contenuti del file, esegui questo comando: L'output dovrebbe essere simile al seguente:cat pyproject.toml
[project] name = "mcp-on-cloudrun" version = "0.1.0" description = "Example of deploying an MCP server on Cloud Run" requires-python = ">=3.13" dependencies = []
6. Crea il server MCP dello zoo
Per fornire un contesto prezioso per migliorare l'utilizzo degli LLM con MCP, configura un server MCP zoo con FastMCP, un framework standard per lavorare con il Model Context Protocol. FastMCP offre un modo rapido per creare server e client MCP con Python. Questo server MCP fornisce dati sugli animali di uno zoo fittizio. Per semplicità, archiviamo i dati in memoria. Per un server MCP di produzione, probabilmente vorrai fornire dati da origini come database o API.
- Esegui questo comando per aggiungere FastMCP come dipendenza nel file
pyproject.toml
: Verrà aggiunto un fileuv add fastmcp==2.11.1 --no-sync
uv.lock
al progetto. - Crea e apri un nuovo file
server.py
per il codice sorgente del server MCP: Il comandocloudshell edit server.py
cloudshell edit
aprirà il fileserver.py
nell'editor sopra il terminale. - Aggiungi il seguente codice sorgente del server MCP zoo nel file
server.py
:import asyncio import logging import os from typing import List, Dict, Any from fastmcp import FastMCP logger = logging.getLogger(__name__) logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO) mcp = FastMCP("Zoo Animal MCP Server 🦁🐧🐻") # Dictionary of animals at the zoo ZOO_ANIMALS = [ { "species": "lion", "name": "Leo", "age": 7, "enclosure": "The Big Cat Plains", "trail": "Savannah Heights" }, { "species": "lion", "name": "Nala", "age": 6, "enclosure": "The Big Cat Plains", "trail": "Savannah Heights" }, { "species": "lion", "name": "Simba", "age": 3, "enclosure": "The Big Cat Plains", "trail": "Savannah Heights" }, { "species": "lion", "name": "King", "age": 8, "enclosure": "The Big Cat Plains", "trail": "Savannah Heights" }, { "species": "penguin", "name": "Waddles", "age": 2, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "penguin", "name": "Pip", "age": 4, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "penguin", "name": "Skipper", "age": 5, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "penguin", "name": "Chilly", "age": 3, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "penguin", "name": "Pingu", "age": 6, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "penguin", "name": "Noot", "age": 1, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "elephant", "name": "Ellie", "age": 15, "enclosure": "The Pachyderm Sanctuary", "trail": "Savannah Heights" }, { "species": "elephant", "name": "Peanut", "age": 12, "enclosure": "The Pachyderm Sanctuary", "trail": "Savannah Heights" }, { "species": "elephant", "name": "Dumbo", "age": 5, "enclosure": "The Pachyderm Sanctuary", "trail": "Savannah Heights" }, { "species": "elephant", "name": "Trunkers", "age": 10, "enclosure": "The Pachyderm Sanctuary", "trail": "Savannah Heights" }, { "species": "bear", "name": "Smokey", "age": 10, "enclosure": "The Grizzly Gulch", "trail": "Polar Path" }, { "species": "bear", "name": "Grizzly", "age": 8, "enclosure": "The Grizzly Gulch", "trail": "Polar Path" }, { "species": "bear", "name": "Barnaby", "age": 6, "enclosure": "The Grizzly Gulch", "trail": "Polar Path" }, { "species": "bear", "name": "Bruin", "age": 12, "enclosure": "The Grizzly Gulch", "trail": "Polar Path" }, { "species": "giraffe", "name": "Gerald", "age": 4, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "giraffe", "name": "Longneck", "age": 5, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "giraffe", "name": "Patches", "age": 3, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "giraffe", "name": "Stretch", "age": 6, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "antelope", "name": "Speedy", "age": 2, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "antelope", "name": "Dash", "age": 3, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "antelope", "name": "Gazelle", "age": 4, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "antelope", "name": "Swift", "age": 5, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "polar bear", "name": "Snowflake", "age": 7, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "polar bear", "name": "Blizzard", "age": 5, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "polar bear", "name": "Iceberg", "age": 9, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "walrus", "name": "Wally", "age": 10, "enclosure": "The Walrus Cove", "trail": "Polar Path" }, { "species": "walrus", "name": "Tusker", "age": 12, "enclosure": "The Walrus Cove", "trail": "Polar Path" }, { "species": "walrus", "name": "Moby", "age": 8, "enclosure": "The Walrus Cove", "trail": "Polar Path" }, { "species": "walrus", "name": "Flippers", "age": 9, "enclosure": "The Walrus Cove", "trail": "Polar Path" } ] @mcp.tool() def get_animals_by_species(species: str) -> List[Dict[str, Any]]: """ Retrieves all animals of a specific species from the zoo. Can also be used to collect the base data for aggregate queries of animals of a specific species - like counting the number of penguins or finding the oldest lion. Args: species: The species of the animal (e.g., 'lion', 'penguin'). Returns: A list of dictionaries, where each dictionary represents an animal and contains details like name, age, enclosure, and trail. """ logger.info(f">>> 🛠️ Tool: 'get_animals_by_species' called for '{species}'") return [animal for animal in ZOO_ANIMALS if animal["species"].lower() == species.lower()] @mcp.tool() def get_animal_details(name: str) -> Dict[str, Any]: """ Retrieves the details of a specific animal by its name. Args: name: The name of the animal. Returns: A dictionary with the animal's details (species, name, age, enclosure, trail) or an empty dictionary if the animal is not found. """ logger.info(f">>> 🛠️ Tool: 'get_animal_details' called for '{name}'") for animal in ZOO_ANIMALS: if animal["name"].lower() == name.lower(): return animal return {} if __name__ == "__main__": logger.info(f"🚀 MCP server started on port {os.getenv('PORT', 8080)}") asyncio.run( mcp.run_async( transport="http", host="0.0.0.0", port=os.getenv("PORT", 8080), ) )
Il tuo codice è completo. È il momento di eseguire il deployment del server MCP in Cloud Run.
7. Deployment in Cloud Run
Ora esegui il deployment di un server MCP in Cloud Run direttamente dal codice sorgente.
- Crea e apri un nuovo
Dockerfile
per il deployment in Cloud Run:cloudshell edit Dockerfile
- Includi il seguente codice nel Dockerfile per utilizzare lo strumento
uv
per eseguire il fileserver.py
:# Use the official Python image FROM python:3.13-slim # Install uv COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ # Install the project into /app COPY . /app WORKDIR /app # Allow statements and log messages to immediately appear in the logs ENV PYTHONUNBUFFERED=1 # Install dependencies RUN uv sync EXPOSE $PORT # Run the FastMCP server CMD ["uv", "run", "server.py"]
- Esegui il comando
gcloud
per eseguire il deployment dell'applicazione in Cloud Run. Utilizza il flaggcloud run deploy zoo-mcp-server \ --no-allow-unauthenticated \ --region=europe-west1 \ --source=. \ --labels=dev-tutorial=codelab-mcp
--no-allow-unauthenticated
per richiedere l'autenticazione. Questo è importante per motivi di sicurezza. Se non richiedi l'autenticazione, chiunque può chiamare il tuo server MCP e potenzialmente causare danni al tuo sistema. - Conferma la creazione di un nuovo repository Artifact Registry. Poiché è la prima volta che esegui il deployment in Cloud Run dal codice sorgente, vedrai:
DigitaDeploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [europe-west1] will be created. Do you want to continue (Y/n)?
Y
e premiEnter
per creare un repository Artifact Registry per il deployment. È necessario per archiviare il container Docker del server MCP per il servizio Cloud Run. - Dopo alcuni minuti, vedrai un messaggio simile a questo:
Service [zoo-mcp-server] revision [zoo-mcp-server-12345-abc] has been deployed and is serving 100 percent of traffic.
Hai eseguito il deployment del server MCP. Ora puoi utilizzarlo.
8. Aggiungere il server MCP remoto all'interfaccia a riga di comando di Gemini
Ora che hai eseguito il deployment di un server MCP remoto, puoi connetterti utilizzando varie applicazioni come Google Code Assist o l'interfaccia a riga di comando di Gemini. In questa sezione, stabiliremo una connessione al nuovo server MCP remoto utilizzando Gemini CLI.
- Concedere al tuo account utente l'autorizzazione a chiamare il server MCP remoto
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \ --member=user:$(gcloud config get-value account) \ --role='roles/run.invoker'
- Salva le credenziali Google Cloud e il numero di progetto nelle variabili di ambiente da utilizzare nel file delle impostazioni di Gemini:
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)") export ID_TOKEN=$(gcloud auth print-identity-token)
- Apri il file delle impostazioni della CLI Gemini
cloudshell edit ~/.gemini/settings.json
- Sostituisci il file delle impostazioni della CLI Gemini per aggiungere il server MCP di Cloud Run
{ "mcpServers": { "zoo-remote": { "httpUrl": "https://zoo-mcp-server-$PROJECT_NUMBER.europe-west1.run.app/mcp/", "headers": { "Authorization": "Bearer $ID_TOKEN" } } }, "selectedAuthType": "cloud-shell", "hasSeenIdeIntegrationNudge": true }
- Avvia l'interfaccia a riga di comando di Gemini in Cloud Shell
Potresti dover premeregemini
Enter
per accettare alcune impostazioni predefinite. - Chiedere a Gemini di elencare gli strumenti MCP a sua disposizione nel contesto
/mcp
- Chiedi a Gemini di trovare qualcosa nello zoo
La CLI Gemini dovrebbe sapere di utilizzare il server MCPWhere can I find penguins?
zoo-remote
e ti chiederà se vuoi consentire l'esecuzione di MCP. - Utilizza la freccia giù, quindi premi
Enter
per selezionare.Yes, always allow all tools from server "zoo-remote"
L'output deve mostrare la risposta corretta e una casella di visualizzazione che indica che è stato utilizzato il server MCP.
Ce l'hai fatta. Hai eseguito il deployment di un server MCP remoto in Cloud Run e lo hai testato utilizzando Gemini CLI.
Quando è tutto pronto per terminare la sessione, digita /quit
e poi premi Enter
per uscire da Gemini CLI.
Debug
Se viene visualizzato un errore simile al seguente:
🔍 Attempting OAuth discovery for 'zoo-remote'... ❌ 'zoo-remote' requires authentication but no OAuth configuration found Error connecting to MCP server 'zoo-remote': MCP server 'zoo-remote' requires authentication. Please configure OAuth or check server settings.
È probabile che il token ID sia scaduto e richieda di impostare nuovamente ID_TOKEN
.
- Digita
/quit
e poi premiEnter
per uscire dalla CLI Gemini. - Imposta il progetto nel terminale
gcloud config set project [PROJECT_ID]
- Riavvia dal passaggio 2 riportato sopra
9. (Facoltativo) Verifica le chiamate agli strumenti nei log del server
Per verificare che il server MCP di Cloud Run sia stato chiamato, controlla i log del servizio.
gcloud run services logs read zoo-mcp-server --region europe-west1 --limit=5
Dovresti visualizzare un log di output che conferma l'esecuzione di una chiamata allo strumento. 🛠️
2025-08-05 19:50:31 INFO: 169.254.169.126:39444 - "POST /mcp/ HTTP/1.1" 200 OK 2025-08-05 19:50:31 [INFO]: Processing request of type CallToolRequest 2025-08-05 19:50:31 [INFO]: >>> 🛠️ Tool: 'get_animals_by_species' called for 'penguin'
10. (Facoltativo) Aggiungi il prompt MCP al server
Un prompt MCP può velocizzare il flusso di lavoro per i prompt che esegui spesso creando un'abbreviazione per un prompt più lungo.
Gemini CLI converte automaticamente i prompt MCP in comandi slash personalizzati in modo che tu possa richiamare un prompt MCP digitando /prompt_name
, dove prompt_name
è il nome del prompt MCP.
Crea un prompt MCP per trovare rapidamente un animale nello zoo digitando /find animal
in Gemini CLI.
- Aggiungi questo codice al file
server.py
sopra la guardia principale (if __name__ == "__main__":
)@mcp.prompt() def find(animal: str) -> str: """ Find which exhibit and trail a specific animal might be located. """ return ( f"Please find the exhibit and trail information for {animal} in the zoo. " f"Respond with '[animal] can be found in the [exhibit] on the [trail].'" f"Example: Penguins can be found in The Arctic Exhibit on the Polar Path." )
- Esegui di nuovo il deployment dell'applicazione in Cloud Run
gcloud run deploy zoo-mcp-server \ --no-allow-unauthenticated \ --region=europe-west1 \ --source=. \ --labels=dev-tutorial=codelab-mcp
- Aggiorna ID_TOKEN per il server MCP remoto
export ID_TOKEN=$(gcloud auth print-identity-token)
- Dopo aver eseguito il deployment della nuova versione dell'applicazione, avvia Gemini CLI.
gemini
- Nel prompt, utilizza il nuovo comando personalizzato che hai creato:
/find --animal="lions"
Dovresti vedere che la CLI Gemini chiama lo strumento get_animals_by_species
e formatta la risposta come indicato dal prompt MCP.
╭───────────────────────────╮ │ > /find --animal="lion" │ ╰───────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮ │ ✔ get_animals_by_species (zoo-remote MCP Server) get_animals_by_species (zoo-remote MCP Server) │ │ │ │ [{"species":"lion","name":"Leo","age":7,"enclosure":"The Big Cat │ │ Plains","trail":"Savannah │ │ Heights"},{"species":"lion","name":"Nala","age":6,"enclosure":"The Big Cat │ │ Plains","trail":"Savannah │ │ Heights"},{"species":"lion","name":"Simba","age":3,"enclosure":"The Big Cat │ │ Plains","trail":"Savannah │ │ Heights"},{"species":"lion","name":"King","age":8,"enclosure":"The Big Cat │ │ Plains","trail":"Savannah Heights"}] │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────╯ ✦ Lions can be found in The Big Cat Plains on the Savannah Heights.
Obiettivi ambiziosi per metterti alla prova
Per una sfida in più, prova a seguire gli stessi passaggi per creare un prompt che restituisca curiosità su specie animali specifiche dello zoo.
In alternativa, per mettere alla prova le tue conoscenze, puoi ideare uno strumento che utilizzeresti spesso e implementare un secondo server MCP remoto. Poi aggiungilo alle impostazioni dell'interfaccia a riga di comando di Gemini per verificare se funziona.
11. Conclusione
Complimenti! Hai eseguito il deployment e la connessione a un server MCP remoto sicuro.
Continua con il lab successivo
Questo lab è il primo di una serie di tre. Nel secondo lab, utilizzerai il server MCP che hai creato con un agente ADK.
Utilizza un server MCP su Cloud Run con un agente ADK
(Facoltativo) Pulizia
Se non continui con il lab successivo e vuoi fare pulizia di ciò che hai creato, puoi eliminare il tuo progetto Cloud per evitare addebiti aggiuntivi.
Sebbene non siano previsti addebiti per Cloud Run quando il servizio non è in uso, ti potrebbero comunque essere addebitati i costi di archiviazione dell'immagine container in Artifact Registry. L'eliminazione del progetto Cloud interrompe la fatturazione per tutte le risorse utilizzate al suo interno.
Se vuoi, elimina il progetto:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
Potresti anche voler eliminare le risorse non necessarie dal disco Cloud Shell. Puoi:
- Elimina la directory del progetto codelab:
rm -rf ~/mcp-on-cloudrun
- Attenzione. La prossima azione non può essere annullata. Se vuoi eliminare tutto ciò che è presente in Cloud Shell per liberare spazio, puoi eliminare l'intera home directory. Fai attenzione che tutto ciò che vuoi conservare sia salvato altrove.
sudo rm -rf $HOME