1. 📖 Introduction
Dans l'atelier de programmation précédent , vous avez appris à concevoir une interaction de données multimodales dans ADK. Nous allons maintenant voir comment concevoir une interaction de données multimodales avec le serveur MCP à l'aide de l'ensemble d'outils MCP. Nous allons étendre les capacités de l'agent de retouche photo de produits développé précédemment pour générer de courtes vidéos à l'aide du modèle Veo et du serveur MCP Veo.
Au cours de cet atelier de programmation, vous allez suivre une approche par étapes :
- Préparer le projet Google Cloud et le répertoire de l'agent de base
- Configurer un serveur MCP qui nécessite des données de fichier en entrée
- Équiper l'agent ADK pour qu'il se connecte au serveur MCP
- Concevoir une stratégie de requête et une fonction de rappel pour modifier la requête d'appel de fonction dans l'ensemble d'outils MCP
- Concevoir une fonction de rappel pour gérer la réponse des données multimodales à partir de MCP Toolset
Présentation de l'architecture
L'interaction globale dans cet atelier de programmation est illustrée dans le schéma suivant.

Prérequis
- Vous êtes à l'aise avec Python.
- (Facultatif) Ateliers de programmation de base sur Agent Development Kit (ADK)
- (Facultatif) Atelier de programmation sur l'outil multimodal ADK, partie 1 : goo.gle/adk-multimodal-tool-1
Points abordés
- Créer une vidéo courte avec Veo 3.1 à l'aide d'un prompt et d'une image de départ
- Développer un serveur MCP multimodal à l'aide de FastMCP
- Configurer ADK pour utiliser MCP Toolset
- Modifier l'appel d'outil vers MCP Toolset via le rappel d'outil
- Modifier la réponse de l'outil à partir de l'ensemble d'outils MCP via le rappel d'outil
Prérequis
- Navigateur Web Chrome
- Un compte Gmail
- Un projet Cloud pour lequel un compte de facturation est activé
Cet atelier de programmation, conçu pour les développeurs de tous niveaux (y compris les débutants), utilise Python dans son exemple d'application. Toutefois, vous n'avez pas besoin de connaître Python pour comprendre les concepts présentés.
2. 🚀 ( Facultatif) Préparer la configuration de développement de l'atelier
Étape 1 : Sélectionnez le projet actif dans la console Cloud
Dans la console Google Cloud, sur la page du sélecteur de projet, sélectionnez ou créez un projet Google Cloud (voir la section en haut à gauche de la console).

Cliquez dessus pour afficher la liste de tous vos projets, comme dans cet exemple :

La valeur indiquée par l'encadré rouge correspond à l'ID du projet. Elle sera utilisée tout au long du tutoriel.
Assurez-vous que la facturation est activée pour votre projet Cloud. Pour vérifier cela, cliquez sur l'icône ☰ en haut à gauche de la barre pour afficher le menu de navigation, puis recherchez le menu "Facturation".

Si vous voyez le compte de facturation de l'essai Google Cloud Platform sous le titre Facturation / Présentation ( en haut à gauche de la console Cloud), votre projet est prêt à être utilisé pour ce tutoriel. Si ce n'est pas le cas, revenez au début de ce tutoriel et utilisez le compte de facturation de l'essai.

Étape 2 : Familiarisez-vous avec Cloud Shell
Vous utiliserez Cloud Shell pour la majeure partie des tutoriels. Cliquez sur "Activer Cloud Shell" en haut de la console Google Cloud. Si vous êtes invité à donner votre autorisation, cliquez sur Autoriser.


Une fois connecté à Cloud Shell, nous devons vérifier si le shell ( ou le terminal) est déjà authentifié avec notre compte.
gcloud auth list
Si votre adresse Gmail personnelle s'affiche comme dans l'exemple ci-dessous, tout est en ordre.
Credentialed Accounts
ACTIVE: *
ACCOUNT: alvinprayuda@gmail.com
To set the active account, run:
$ gcloud config set account `ACCOUNT`
Si ce n'est pas le cas, essayez d'actualiser votre navigateur et assurez-vous de cliquer sur Autoriser lorsque vous y êtes invité ( la connexion peut être interrompue en raison d'un problème de connexion).
Ensuite, nous devons également vérifier si le shell est déjà configuré avec le bon ID DE PROJET. Si une valeur est indiquée entre parenthèses avant l'icône $ dans le terminal (dans la capture d'écran ci-dessous, la valeur est "adk-multimodal-tool"), cela indique le projet configuré pour votre session de shell active.

Si la valeur affichée est déjà correcte, vous pouvez ignorer la commande suivante. Toutefois, si elle est incorrecte ou manquante, exécutez la commande suivante :
gcloud config set project <YOUR_PROJECT_ID>
Ensuite, clonez le répertoire de travail du modèle pour cet atelier de programmation à partir de GitHub en exécutant la commande suivante. Il crée le répertoire de travail dans le répertoire adk-multimodal-tool.
git clone https://github.com/alphinside/adk-mcp-multimodal.git adk-multimodal-tool
Étape 3 : Familiarisez-vous avec l'éditeur Cloud Shell et configurez le répertoire de travail de l'application
Nous pouvons maintenant configurer notre éditeur de code pour effectuer certaines tâches de codage. Pour cela, nous allons utiliser l'éditeur Cloud Shell.
Cliquez sur le bouton Ouvrir l'éditeur pour ouvrir l'éditeur Cloud Shell
.
Ensuite, accédez à la section supérieure de l'éditeur Cloud Shell et cliquez sur File->Open Folder (Fichier > Ouvrir le dossier), recherchez votre répertoire nom d'utilisateur, puis le répertoire adk-multimodal-tool, puis cliquez sur le bouton OK. Le répertoire choisi deviendra le répertoire de travail principal. Dans cet exemple, le nom d'utilisateur est alvinprayuda. Le chemin d'accès au répertoire est donc indiqué ci-dessous.


Votre répertoire de travail de l'éditeur Cloud Shell devrait maintenant ressembler à ceci ( dans adk-multimodal-tool) :

Ouvrez maintenant le terminal de l'éditeur. Pour ce faire, cliquez sur Terminal > Nouveau terminal dans la barre de menu ou utilisez le raccourci clavier Ctrl+Maj+C. Une fenêtre de terminal s'ouvrira en bas du navigateur.

Le terminal actif actuel doit se trouver dans le répertoire de travail adk-multimodal-tool. Dans cet atelier de programmation, nous utiliserons Python 3.12 et le gestionnaire de projets Python uv pour simplifier la création et la gestion de la version Python et de l'environnement virtuel. Le package uv est déjà préinstallé sur Cloud Shell.
Exécutez cette commande pour installer les dépendances requises dans l'environnement virtuel du répertoire .venv.
uv sync --frozen
Consultez le fichier pyproject.toml pour voir les dépendances déclarées pour ce tutoriel, qui sont google-adk, and python-dotenv.
Nous devons maintenant activer les API requises à l'aide de la commande ci-dessous. Cela peut prendre un certain temps.
gcloud services enable aiplatform.googleapis.com
Si la commande s'exécute correctement, un message semblable à celui ci-dessous s'affiche :
Operation "operations/..." finished successfully.
La structure de l'agent de modèle vous est déjà fournie dans le répertoire part2_starter_agent du dépôt cloné. Maintenant, nous devons d'abord le renommer pour être prêt pour ce tutoriel.
mv part1_ckpt_agent product_photo_editor
Ensuite, copiez product_photo_editor/.env.example dans product_photo_editor/.env.
cp product_photo_editor/.env.example product_photo_editor/.env
Lorsque vous ouvrez le fichier product_photo_editor/.env, vous voyez un contenu semblable à celui ci-dessous.
GOOGLE_GENAI_USE_VERTEXAI=1
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=global
Vous devrez ensuite remplacer la valeur your-project-id par l'ID de votre projet. Nous sommes maintenant prêts à passer à l'étape suivante.
3. 🚀 Initialiser le serveur MCP Veo
Commençons par créer le répertoire de services MCP à l'aide de cette commande.
mkdir veo_mcp
Créez ensuite veo_mcp/main.py à l'aide de la commande suivante :
touch veo_mcp/main.py
Copiez ensuite le code suivant dans veo_mcp/main.py.
from fastmcp import FastMCP
from typing import Annotated
from pydantic import Field
import base64
import asyncio
import os
from google import genai
from google.genai import types
from dotenv import load_dotenv
import logging
# Load environment variables from .env file
load_dotenv()
mcp = FastMCP("Veo MCP Server")
@mcp.tool
async def generate_video_with_image(
prompt: Annotated[
str, Field(description="Text description of the video to generate")
],
image_data: Annotated[
str, Field(description="Base64-encoded image data to use as starting frame")
],
negative_prompt: Annotated[
str | None,
Field(description="Things to avoid in the generated video"),
] = None,
) -> dict:
"""Generates a professional product marketing video from text prompt and starting image using Google's Veo API.
This function uses an image as the first frame of the generated video and automatically
enriches your prompt with professional video production quality guidelines to create
high-quality marketing assets suitable for commercial use.
AUTOMATIC ENHANCEMENTS APPLIED:
- 4K cinematic quality with professional color grading
- Smooth, stabilized camera movements
- Professional studio lighting setup
- Shallow depth of field for product focus
- Commercial-grade production quality
- Marketing-focused visual style
PROMPT WRITING TIPS:
Describe what you want to see in the video. Focus on:
- Product actions/movements (e.g., "rotating slowly", "zooming into details")
- Desired camera angles (e.g., "close-up of the product", "wide shot")
- Background/environment (e.g., "minimalist white backdrop", "lifestyle setting")
- Any specific details about the product presentation
The system will automatically enhance your prompt with professional production quality.
Args:
prompt: Description of the video to generate. Focus on the core product presentation
you want. The system will automatically add professional quality enhancements.
image_data: Base64-encoded image data to use as the starting frame
negative_prompt: Optional prompt describing what to avoid in the video
Returns:
dict: A dictionary containing:
- status: 'success' or 'error'
- message: Description of the result
- video_data: Base64-encoded video data (on success only)
"""
try:
# Initialize the Gemini client
client = genai.Client(
vertexai=True,
project=os.getenv("GOOGLE_CLOUD_PROJECT"),
location=os.getenv("GOOGLE_CLOUD_LOCATION"),
)
# Decode the image
image_bytes = base64.b64decode(image_data)
print(f"Successfully decoded image data: {len(image_bytes)} bytes")
# Create image object
image = types.Image(image_bytes=image_bytes, mime_type="image/png")
# Prepare the config
config = types.GenerateVideosConfig(
duration_seconds=8,
number_of_videos=1,
)
if negative_prompt:
config.negative_prompt = negative_prompt
# Enrich the prompt for professional marketing quality
enriched_prompt = enrich_prompt_for_marketing(prompt)
# Generate the video (async operation)
operation = client.models.generate_videos(
model="veo-3.1-generate-preview",
prompt=enriched_prompt,
image=image,
config=config,
)
# Poll until the operation is complete
poll_count = 0
while not operation.done:
poll_count += 1
print(f"Waiting for video generation to complete... (poll {poll_count})")
await asyncio.sleep(5)
operation = client.operations.get(operation)
# Download the video and convert to base64
video = operation.response.generated_videos[0]
# Get video bytes and encode to base64
video_bytes = video.video.video_bytes
video_base64 = base64.b64encode(video_bytes).decode("utf-8")
print(f"Video generated successfully: {len(video_bytes)} bytes")
return {
"status": "success",
"message": f"Video with image generated successfully after {poll_count * 5} seconds",
"complete_prompt": enriched_prompt,
"video_data": video_base64,
}
except Exception as e:
logging.error(e)
return {
"status": "error",
"message": f"Error generating video with image: {str(e)}",
}
def enrich_prompt_for_marketing(user_prompt: str) -> str:
"""Enriches user prompt with professional video production quality enhancements.
Adds cinematic quality, professional lighting, smooth camera work, and marketing-focused
elements to ensure high-quality product marketing videos.
"""
enhancement_prefix = """Create a high-quality, professional product marketing video with the following characteristics:
TECHNICAL SPECIFICATIONS:
- 4K cinematic quality with professional color grading
- Smooth, stabilized camera movements
- Professional studio lighting setup with soft, even illumination
- Shallow depth of field for product focus
- High dynamic range (HDR) for vibrant colors
VISUAL STYLE:
- Clean, minimalist aesthetic suitable for premium brand marketing
- Elegant and sophisticated presentation
- Commercial-grade production quality
- Attention to detail in product showcase
USER'S SPECIFIC REQUIREMENTS:
"""
enhancement_suffix = """
ADDITIONAL QUALITY GUIDELINES:
- Ensure smooth transitions and natural motion
- Maintain consistent lighting throughout
- Keep the product as the clear focal point
- Use professional camera techniques (slow pans, tracking shots, or dolly movements)
- Apply subtle motion blur for cinematic feel
- Ensure brand-appropriate tone and style"""
return f"{enhancement_prefix}{user_prompt}{enhancement_suffix}"
if __name__ == "__main__":
mcp.run()
Le code suivant effectue les opérations suivantes :
- Crée un serveur FastMCP qui expose un outil de génération de vidéos Veo 3.1 aux agents ADK
- Accepte les images encodées en base64, les requêtes textuelles et les requêtes négatives en entrée
- Génère des vidéos de huit secondes de manière asynchrone en envoyant des requêtes à l'API Veo 3.1 et en interrogeant le service toutes les cinq secondes jusqu'à ce que la tâche soit terminée.
- Renvoie les données vidéo encodées en base64 ainsi que le prompt enrichi
Cet outil Veo MCP nécessitera la même variable d'environnement que notre agent. Nous pouvons donc simplement copier-coller le fichier .env. Pour ce faire, exécutez la commande suivante :
cp product_photo_editor/.env veo_mcp/
Nous pouvons maintenant vérifier si le serveur MCP fonctionne correctement en exécutant cette commande.
uv run veo_mcp/main.py
Le journal de la console s'affichera comme suit :
╭────────────────────────────────────────────────────────────────────────────╮
│ │
│ _ __ ___ _____ __ __ _____________ ____ ____ │
│ _ __ ___ .'____/___ ______/ /_/ |/ / ____/ __ \ |___ \ / __ \ │
│ _ __ ___ / /_ / __ `/ ___/ __/ /|_/ / / / /_/ / ___/ / / / / / │
│ _ __ ___ / __/ / /_/ (__ ) /_/ / / / /___/ ____/ / __/_/ /_/ / │
│ _ __ ___ /_/ \____/____/\__/_/ /_/\____/_/ /_____(*)____/ │
│ │
│ │
│ FastMCP 2.0 │
│ │
│ │
│ 🖥️ Server name: Veo MCP Server │
│ 📦 Transport: STDIO │
│ │
│ 🏎️ FastMCP version: 2.12.5 │
│ 🤝 MCP SDK version: 1.16.0 │
│ │
│ 📚 Docs: https://gofastmcp.com │
│ 🚀 Deploy: https://fastmcp.cloud │
│ │
╰────────────────────────────────────────────────────────────────────────────╯
[10/22/25 08:28:53] INFO Starting MCP server 'Veo MCP Server' with server.py:1502
transport 'stdio'
Arrêtez maintenant le processus du service MCP à l'aide de CTRL+C. Cette commande sera appelée ultérieurement à partir de l'ensemble d'outils ADK MCP. Nous pouvons passer à l'étape suivante pour permettre à notre agent d'utiliser ces outils MCP.
4. 🚀 Connecter le serveur MCP Veo à l'agent ADK
Connectons maintenant le serveur MCP Veo pour qu'il puisse être utilisé par notre agent. Commençons par créer un script différent pour contenir l'ensemble d'outils. Pour ce faire, exécutez la commande suivante :
touch product_photo_editor/mcp_tools.py
Copiez ensuite le code suivant dans product_photo_editor/mcp_tools.py.
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
from mcp import StdioServerParameters
mcp_toolset = MCPToolset(
connection_params=StdioConnectionParams(
server_params=StdioServerParameters(
command="uv",
args=[
"run",
"veo_mcp/main.py",
],
),
timeout=120, # seconds
),
)
# Option to connect to remote MCP server
# from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
# mcp_toolset = MCPToolset(
# connection_params=StreamableHTTPConnectionParams(
# url="http://localhost:8000/mcp",
# timeout=120,
# ),
# )
Le code ci-dessus montre comment se connecter à un serveur MCP à l'aide d'ADK MCPToolset. Dans cet exemple, nous nous connectons au serveur MCP à l'aide du canal de communication STDIO. Dans la commande, nous spécifions comment exécuter le serveur MCP et définir le paramètre de délai avant expiration.
5. 🚀 Modification des paramètres d'appel d'outil
Dans la déclaration de l'outil du serveur MCP, nous avons conçu l'outil generate_video_with_image qui spécifie la chaîne base64 comme paramètres de l'outil. Nous ne pouvons pas demander au LLM de le faire pour nous. Nous devons donc concevoir une stratégie spécifique pour gérer cela.
Dans l'atelier précédent, nous avons géré l'image importée par l'utilisateur et la réponse de l'outil dans before_model_callback pour qu'elle soit enregistrée en tant qu'artefact, ce qui se reflète également dans le modèle d'agent préparé précédemment. Nous allons utiliser ces informations et appliquer les stratégies suivantes :
- Demandez au LLM d'envoyer systématiquement la valeur artifact_id si des paramètres d'outil spécifiques nécessitent l'envoi de données de chaîne base64.
- Interceptez l'appel d'outil dans
before_tool_callbacket transformez le paramètre de l'artifact_id en son contenu d'octets en chargeant l'artefact et en écrasant les arguments de l'outil.
L'image ci-dessous montre la partie que nous allons intercepter.

Commençons par préparer la fonction before_tool_callback. Pour ce faire, créez un fichier product_photo_editor/tool_callbacks.py en exécutant la commande suivante :
touch product_photo_editor/tool_callbacks.py
Ensuite, copiez le code suivant dans le fichier.
# product_photo_editor/tool_callbacks.py
from google.genai.types import Part
from typing import Any
from google.adk.tools.tool_context import ToolContext
from google.adk.tools.base_tool import BaseTool
from google.adk.tools.mcp_tool.mcp_tool import McpTool
import base64
import logging
import json
from mcp.types import CallToolResult
async def before_tool_modifier(
tool: BaseTool, args: dict[str, Any], tool_context: ToolContext
):
# Identify which tool input should be modified
if isinstance(tool, McpTool) and tool.name == "generate_video_with_image":
logging.info("Modify tool args for artifact: %s", args["image_data"])
# Get the artifact filename from the tool input argument
artifact_filename = args["image_data"]
artifact = await tool_context.load_artifact(filename=artifact_filename)
file_data = artifact.inline_data.data
# Convert byte data to base64 string
base64_data = base64.b64encode(file_data).decode("utf-8")
# Then modify the tool input argument
args["image_data"] = base64_data
Le code ci-dessus montre les étapes suivantes :
- Vérifiez si l'outil appelé est un objet McpTool et s'il s'agit de l'appel d'outil cible que nous souhaitons modifier.
- Obtenez la valeur des arguments
image_datadans lesquels l'argument est demandé au format base64, mais nous demandons au LLM de renvoyer artifact_id. - Chargez l'artefact en utilisant le service d'artefact sur
tool_context. - Remplacez les arguments
image_datapar les données base64.
Nous devons maintenant ajouter ce rappel à l'agent et modifier légèrement les instructions afin que l'agent remplisse toujours les arguments de l'outil base64 avec l'ID de l'artefact.
Ouvrez product_photo_editor/agent.py et modifiez le contenu avec le code suivant.
# product_photo_editor/agent.py
from google.adk.agents.llm_agent import Agent
from product_photo_editor.custom_tools import edit_product_asset
from product_photo_editor.mcp_tools import mcp_toolset
from product_photo_editor.model_callbacks import before_model_modifier
from product_photo_editor.tool_callbacks import before_tool_modifier
from product_photo_editor.prompt import AGENT_INSTRUCTION
root_agent = Agent(
model="gemini-2.5-flash",
name="product_photo_editor",
description="""A friendly product photo editor assistant that helps small business
owners edit and enhance their product photos. Perfect for improving photos of handmade
goods, food products, crafts, and small retail items""",
instruction=AGENT_INSTRUCTION
+ """
**IMPORTANT: Base64 Argument Rule on Tool Call**
If you found any tool call arguments that requires base64 data,
ALWAYS provide the artifact_id of the referenced file to
the tool call. NEVER ask user to provide base64 data.
Base64 data encoding process is out of your
responsibility and will be handled in another part of the system.
""",
tools=[
edit_product_asset,
mcp_toolset,
],
before_model_callback=before_model_modifier,
before_tool_callback=before_tool_modifier,
)
Très bien, essayons maintenant d'interagir avec l'agent pour tester cette modification. Exécutez la commande suivante pour exécuter l'interface utilisateur de développement Web :
uv run adk web --port 8080
Il générera une sortie semblable à l'exemple suivant, ce qui signifie que nous pouvons déjà accéder à l'interface Web.
INFO: Started server process [xxxx] INFO: Waiting for application startup. +-----------------------------------------------------------------------------+ | ADK Web Server started | | | | For local testing, access at http://127.0.0.1:8080. | +-----------------------------------------------------------------------------+ INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit)
Pour le vérifier, vous pouvez Ctrl+cliquer sur l'URL ou cliquer sur le bouton Aperçu sur le Web en haut de l'éditeur Cloud Shell, puis sélectionner Prévisualiser sur le port 8080.

La page Web suivante s'affiche. Vous pouvez y sélectionner les agents disponibles dans le menu déroulant en haut à gauche ( dans notre cas, il s'agit de product_photo_editor) et interagir avec le bot.
Ensuite, importez l'image suivante et demandez à l'agent de générer un extrait promotionnel à partir de celle-ci.
Generate a slow zoom in and moving from left and right animation

L'erreur suivante s'affiche :

Pourquoi ? Étant donné que l'outil renvoyait également des résultats directement sous la forme d'une chaîne base64, cela dépassera le nombre maximal de jetons. Nous allons maintenant traiter cette erreur dans la section suivante.
6. 🚀 Modification des réponses de l'outil
Dans cette section, nous allons gérer la réponse de l'outil à partir de la réponse MCP. Nous allons effectuer les actions suivantes :
- Stocker la réponse vidéo de l'outil dans le service d'artefacts
- Renvoyez plutôt l'identifiant de l'artefact à l'agent.
Pour rappel, nous allons appuyer sur le runtime de l'agent suivant.

Commençons par implémenter la fonction de rappel. Ouvrez product_photo_editor/tool_callbacks.py et modifiez-le pour implémenter after_tool_modifier.
# product_photo_editor/tool_callbacks.py
from google.genai.types import Part
from typing import Any
from google.adk.tools.tool_context import ToolContext
from google.adk.tools.base_tool import BaseTool
from google.adk.tools.mcp_tool.mcp_tool import McpTool
import base64
import logging
import json
from mcp.types import CallToolResult
async def before_tool_modifier(
tool: BaseTool, args: dict[str, Any], tool_context: ToolContext
):
# Identify which tool input should be modified
if isinstance(tool, McpTool) and tool.name == "generate_video_with_image":
logging.info("Modify tool args for artifact: %s", args["image_data"])
# Get the artifact filename from the tool input argument
artifact_filename = args["image_data"]
artifact = await tool_context.load_artifact(filename=artifact_filename)
file_data = artifact.inline_data.data
# Convert byte data to base64 string
base64_data = base64.b64encode(file_data).decode("utf-8")
# Then modify the tool input argument
args["image_data"] = base64_data
async def after_tool_modifier(
tool: BaseTool,
args: dict[str, Any],
tool_context: ToolContext,
tool_response: dict | CallToolResult,
):
if isinstance(tool, McpTool) and tool.name == "generate_video_with_image":
tool_result = json.loads(tool_response.content[0].text)
# Get the expected response field which contains the video data
video_data = tool_result["video_data"]
artifact_filename = f"video_{tool_context.function_call_id}.mp4"
# Convert base64 string to byte data
video_bytes = base64.b64decode(video_data)
# Save the video as artifact
await tool_context.save_artifact(
filename=artifact_filename,
artifact=Part(inline_data={"mime_type": "video/mp4", "data": video_bytes}),
)
# Remove the video data from the tool response
tool_result.pop("video_data")
# Then modify the tool response to include the artifact filename and remove the base64 string
tool_result["video_artifact_id"] = artifact_filename
logging.info(
"Modify tool response for artifact: %s", tool_result["video_artifact_id"]
)
return tool_result
Ensuite, nous devons équiper notre agent de cette fonction. Ouvrez product_photo_editor/agent.py et modifiez-le en y insérant le code suivant :
# product_photo_editor/agent.py
from google.adk.agents.llm_agent import Agent
from product_photo_editor.custom_tools import edit_product_asset
from product_photo_editor.mcp_tools import mcp_toolset
from product_photo_editor.model_callbacks import before_model_modifier
from product_photo_editor.tool_callbacks import (
before_tool_modifier,
after_tool_modifier,
)
from product_photo_editor.prompt import AGENT_INSTRUCTION
root_agent = Agent(
model="gemini-2.5-flash",
name="product_photo_editor",
description="""A friendly product photo editor assistant that helps small business
owners edit and enhance their product photos. Perfect for improving photos of handmade
goods, food products, crafts, and small retail items""",
instruction=AGENT_INSTRUCTION
+ """
**IMPORTANT: Base64 Argument Rule on Tool Call**
If you found any tool call arguments that requires base64 data,
ALWAYS provide the artifact_id of the referenced file to
the tool call. NEVER ask user to provide base64 data.
Base64 data encoding process is out of your
responsibility and will be handled in another part of the system.
""",
tools=[
edit_product_asset,
mcp_toolset,
],
before_model_callback=before_model_modifier,
before_tool_callback=before_tool_modifier,
after_tool_callback=after_tool_modifier,
)
Voilà, vous pouvez maintenant demander à l'agent de vous aider à retoucher la photo, mais aussi à générer une vidéo pour vous ! Exécutez à nouveau la commande suivante :
uv run adk web --port 8080
Ensuite, essayez de créer une vidéo à partir de cette image.
Generate a slow zoom in and moving from left and right animation

La vidéo générée s'affiche, comme dans l'exemple ci-dessous, et est déjà enregistrée en tant qu'artefact.

7. ⭐ Résumé
Passons en revue ce que nous avons déjà fait au cours de cet atelier de programmation. Voici le point clé à retenir :
- Gestion des données multimodales (E/S des outils) : renforcement de la stratégie de gestion des données multimodales (comme les images et les vidéos) pour les entrées et sorties des outils en utilisant le service Artifacts de l'ADK et des rappels spécialisés au lieu de transmettre directement les données brutes en octets.
- Intégration de l'ensemble d'outils MCP : nous avons développé et intégré un serveur MCP Veo externe à l'aide de FastMCP via l'ensemble d'outils MCP ADK pour ajouter des fonctionnalités de génération de vidéos à l'agent.
- Modification de l'entrée de l'outil (before_tool_callback) : implémentation d'un rappel pour intercepter l'appel de l'outil generate_video_with_image, en transformant l'artifact_id du fichier (sélectionné par le LLM) en données d'image encodées en base64 requises pour l'entrée du serveur MCP.
- Modification de la sortie de l'outil (after_tool_callback) : implémentation d'un rappel pour intercepter la réponse vidéo volumineuse encodée en base64 du serveur MCP, enregistrer la vidéo en tant que nouvel artefact et renvoyer une référence video_artifact_id propre au LLM.
8. 🧹 Nettoyer
Pour éviter que les ressources utilisées dans cet atelier de programmation soient facturées sur votre compte Google Cloud :
- Dans la console Google Cloud, accédez à la page Gérer les ressources.
- Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
- Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.