1. 📖 Introducción
En el codelab anterior , aprendiste a diseñar una interacción de datos multimodal en el ADK. Ahora, daremos un paso más para diseñar una interacción de datos multimodal con el servidor de MCP usando el conjunto de herramientas de MCP. Expandiremos las capacidades del agente editor de fotos de productos desarrollado anteriormente con la capacidad de generar videos cortos con el modelo de Veo utilizando el servidor de MCP de Veo.
En el codelab, seguirás un enfoque paso a paso de la siguiente manera:
- Prepara el proyecto de Google Cloud y el directorio base del agente
- Configura un servidor de MCP que requiera datos de archivos como entrada
- Cómo equipar al agente de ADK para que se conecte con el servidor de MCP
- Diseña una estrategia de instrucciones y una función de devolución de llamada para modificar la solicitud de llamada a función en el conjunto de herramientas de MCP
- Diseña una función de devolución de llamada para controlar la respuesta de datos multimodales del conjunto de herramientas de MCP
Descripción general de la arquitectura
La interacción general en este codelab se muestra en el siguiente diagrama

Requisitos previos
- Comodidad para trabajar con Python
- (Opcional) Codelabs básicos sobre el Kit de desarrollo de agentes (ADK)
- (Opcional) Codelab de la parte 1 de la herramienta multimodal del ADK : goo.gle/adk-multimodal-tool-1
Qué aprenderás
- Cómo crear videos cortos con Veo 3.1 a partir de instrucciones y una imagen inicial
- Cómo desarrollar un servidor de MCP multimodal con FastMCP
- Cómo configurar el ADK para usar MCP Toolset
- Cómo modificar la llamada a la herramienta para MCP Toolset a través de la devolución de llamada de la herramienta
- Cómo modificar la respuesta de la herramienta desde MCP Toolset a través de la devolución de llamada de la herramienta
Requisitos
- Navegador web Chrome
- Una cuenta de Gmail
- Un proyecto de Cloud con una cuenta de facturación habilitada
Este codelab, diseñado para desarrolladores de todos los niveles (incluidos los principiantes), usa Python en su aplicación de ejemplo. Sin embargo, no es necesario tener conocimientos de Python para comprender los conceptos que se presentan.
2. 🚀 ( Opcional) Preparación de la configuración de desarrollo del taller
Paso 1: Selecciona el proyecto activo en la consola de Cloud
En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud (consulta la sección superior izquierda de la consola).

Haz clic en él y verás una lista de todos tus proyectos, como en este ejemplo:

El valor que se indica con el cuadro rojo es el ID DEL PROYECTO, y se usará en todo el instructivo.
Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Para verificarlo, haz clic en el ícono de hamburguesa ☰ en la barra superior izquierda, que muestra el menú de navegación, y busca el menú Facturación.

Si ves "Cuenta de facturación de la prueba de Google Cloud Platform" debajo del título Facturación / Descripción general ( sección superior izquierda de tu consola de Cloud), tu proyecto está listo para usarse en este instructivo. De lo contrario, vuelve al inicio de este instructivo y canjea la cuenta de facturación de prueba.

Paso 2: Familiarízate con Cloud Shell
Usarás Cloud Shell durante la mayor parte de los instructivos. Haz clic en Activar Cloud Shell en la parte superior de la consola de Google Cloud. Si se te solicita autorización, haz clic en Autorizar.


Una vez que te conectes a Cloud Shell, deberemos verificar si el shell ( o la terminal) ya se autenticó con nuestra cuenta.
gcloud auth list
Si ves tu Gmail personal como en el siguiente ejemplo de resultado, todo está bien.
Credentialed Accounts
ACTIVE: *
ACCOUNT: alvinprayuda@gmail.com
To set the active account, run:
$ gcloud config set account `ACCOUNT`
Si no es así, intenta actualizar el navegador y asegúrate de hacer clic en Autorizar cuando se te solicite ( es posible que se interrumpa debido a un problema de conexión).
A continuación, también debemos verificar si la shell ya está configurada con el ID DEL PROYECTO correcto que tienes. Si ves que hay un valor dentro de ( ) antes del ícono $ en la terminal ( en la captura de pantalla a continuación, el valor es "adk-multimodal-tool"), este valor muestra el proyecto configurado para tu sesión de shell activa.

Si el valor que se muestra ya es correcto, puedes omitir el siguiente comando. Sin embargo, si no es correcto o falta, ejecuta el siguiente comando:
gcloud config set project <YOUR_PROJECT_ID>
Luego, clona el directorio de trabajo de la plantilla para este codelab desde GitHub. Para ello, ejecuta el siguiente comando. Se creará el directorio de trabajo en el directorio adk-multimodal-tool.
git clone https://github.com/alphinside/adk-mcp-multimodal.git adk-multimodal-tool
Paso 3: Familiarízate con el editor de Cloud Shell y configura el directorio de trabajo de la aplicación
Ahora, podemos configurar nuestro editor de código para hacer algunas cosas de programación. Usaremos el editor de Cloud Shell para esto.
Haz clic en el botón Abrir editor para abrir un editor de Cloud Shell
.
Después, ve a la sección superior del editor de Cloud Shell y haz clic en File->Open Folder, busca tu directorio username y el directorio adk-multimodal-tool, y, luego, haz clic en el botón Aceptar. Esto convertirá el directorio elegido en el directorio de trabajo principal. En este ejemplo, el nombre de usuario es alvinprayuda, por lo que la ruta de acceso del directorio se muestra a continuación.


Ahora, tu directorio de trabajo del editor de Cloud Shell debería verse de la siguiente manera ( dentro de adk-multimodal-tool):

Ahora, abre la terminal del editor. Para ello, haz clic en Terminal -> New Terminal en la barra de menú o usa Ctrl + Mayúsculas + C. Se abrirá una ventana de terminal en la parte inferior del navegador.

Tu terminal activa actual debe estar dentro del directorio de trabajo adk-multimodal-tool. En este codelab, usaremos Python 3.12 y uv python project manager para simplificar la necesidad de crear y administrar la versión de Python y el entorno virtual. Este paquete uv ya está preinstalado en Cloud Shell.
Ejecuta este comando para instalar las dependencias requeridas en el entorno virtual del directorio .venv.
uv sync --frozen
Consulta el archivo pyproject.toml para ver las dependencias declaradas para este instructivo, que son google-adk, and python-dotenv.
Ahora, deberemos habilitar las APIs requeridas con el siguiente comando. Este proceso podría tardar un poco.
gcloud services enable aiplatform.googleapis.com
Si el comando se ejecuta correctamente, deberías ver un mensaje similar al que se muestra a continuación:
Operation "operations/..." finished successfully.
La estructura del agente de plantilla ya se proporciona dentro del directorio part2_starter_agent en el repositorio clonado. Ahora, primero tendremos que cambiarle el nombre para que esté listo para este instructivo.
mv part1_ckpt_agent product_photo_editor
Después de eso, copia product_photo_editor/.env.example en product_photo_editor/.env.
cp product_photo_editor/.env.example product_photo_editor/.env
Cuando abras el archivo product_photo_editor/.env, verás contenido como el que se muestra a continuación.
GOOGLE_GENAI_USE_VERTEXAI=1
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=global
Luego, deberás actualizar el valor de your-project-id con el ID de tu proyecto correcto. Ahora sí, ya podemos continuar con el siguiente paso.
3. 🚀 Inicializa el servidor de MCP de Veo
Primero, creemos el directorio de servicio de MCP con este comando
mkdir veo_mcp
Luego, crea veo_mcp/main.py con este comando.
touch veo_mcp/main.py
Después, copia el siguiente código en 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()
El siguiente código hace lo siguiente:
- Crea un servidor de FastMCP que expone una herramienta de generación de video de Veo 3.1 a los agentes de ADK
- Acepta imágenes codificadas en base64, instrucciones de texto y mensajes negativos como entrada.
- Genera videos de 8 segundos de forma asíncrona enviando solicitudes a la API de Veo 3.1 y sondeando cada 5 segundos hasta que se complete el proceso.
- Devuelve datos de video codificados en base64 junto con la instrucción enriquecida.
Esta herramienta de MCP de Veo requerirá la misma variable de entorno que nuestro agente, por lo que solo tendremos que copiar y pegar el archivo .env. Ejecuta el siguiente comando para hacerlo:
cp product_photo_editor/.env veo_mcp/
Ahora, podemos probar si el servidor de MCP se ejecuta correctamente con este comando.
uv run veo_mcp/main.py
Y mostrará el registro de la consola de esta manera
╭────────────────────────────────────────────────────────────────────────────╮
│ │
│ _ __ ___ _____ __ __ _____________ ____ ____ │
│ _ __ ___ .'____/___ ______/ /_/ |/ / ____/ __ \ |___ \ / __ \ │
│ _ __ ___ / /_ / __ `/ ___/ __/ /|_/ / / / /_/ / ___/ / / / / / │
│ _ __ ___ / __/ / /_/ (__ ) /_/ / / / /___/ ____/ / __/_/ /_/ / │
│ _ __ ___ /_/ \____/____/\__/_/ /_/\____/_/ /_____(*)____/ │
│ │
│ │
│ 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'
Ahora, finaliza el proceso del servicio de MCP con CTRL + C. Este comando se invocará desde el conjunto de herramientas de MCP del ADK más adelante. Podemos pasar al siguiente paso para permitir que nuestro agente utilice estas herramientas de MCP.
4. 🚀 Conecta el servidor de MCP de Veo al agente del ADK
Ahora, conectemos el servidor de MCP de Veo para que nuestro agente pueda utilizarlo. Primero, creemos una secuencia de comandos diferente para que contenga el conjunto de herramientas. Para ello, ejecuta el siguiente comando:
touch product_photo_editor/mcp_tools.py
Luego, copia el siguiente código en 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,
# ),
# )
El código anterior muestra cómo podemos conectarnos a un servidor de MCP con MCPToolset de ADK. En este ejemplo, nos conectamos al servidor de MCP a través del canal de comunicación STDIO. En el comando, especificamos cómo podemos ejecutar el servidor de MCP y establecer el parámetro de tiempo de espera.
5. 🚀 Modificación de parámetros de llamadas a herramientas
En la declaración de la herramienta del servidor de MCP, diseñamos la herramienta generate_video_with_image, que especifica la cadena en base64 como los parámetros de la herramienta. No podemos pedirle al LLM que lo haga por nosotros, por lo que debemos diseñar una estrategia específica para manejar esto.
En el lab anterior, controlamos la imagen de respuesta de la herramienta y la que subió el usuario en el before_model_callback para que se guarde como un artefacto, lo que también se refleja en la plantilla del agente que se preparó anteriormente. Utilizaremos esta información y aplicaremos las siguientes estrategias:
- Indica al LLM que siempre envíe el valor de artifact_id si un parámetro de herramienta específico requiere que se envíen datos de cadena base64.
- Intercepta la invocación de la llamada a la herramienta en
before_tool_callbacky transforma el parámetro de artifact_id a su contenido de bytes cargando el artefacto y sobrescribiendo los argumentos de la herramienta.
Consulta la siguiente imagen para ver la visualización de la parte que interceptaremos.

Primero, preparemos la función before_tool_callback. Para ello, crea un archivo nuevo product_photo_editor/tool_callbacks.py ejecutando el siguiente comando:
touch product_photo_editor/tool_callbacks.py
Luego, copia el siguiente código en el archivo:
# 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
El código anterior muestra los siguientes pasos:
- Verifica si la herramienta invocada es un objeto McpTool y si es la llamada a la herramienta objetivo que queremos modificar.
- Obtén el valor de los argumentos de
image_data, en el que se solicita el argumento en formato base64, pero le pedimos al LLM que devuelva artifact_id en él. - Carga el artefacto utilizando el servicio de artefactos en
tool_context - Reemplaza los argumentos
image_datacon los datos en base64.
Ahora, tendremos que agregar esta devolución de llamada al agente y también modificar ligeramente las instrucciones para que el agente siempre complete los argumentos de la herramienta en base64 con el ID del artefacto.
Abre product_photo_editor/agent.py y modifica el contenido con el siguiente código:
# 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,
)
Ahora intentemos interactuar con el agente para probar esta modificación. Ejecuta el siguiente comando para ejecutar la IU de desarrollo web
uv run adk web --port 8080
Se generará un resultado similar al siguiente ejemplo, lo que significa que ya podemos acceder a la interfaz 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)
Ahora, para verificarlo, puedes hacer Ctrl + clic en la URL o hacer clic en el botón Vista previa en la Web en la parte superior del editor de Cloud Shell y seleccionar Vista previa en el puerto 8080.

Verás la siguiente página web en la que puedes seleccionar los agentes disponibles en el botón desplegable de la parte superior izquierda ( en nuestro caso, debería ser product_photo_editor) y, luego, interactuar con el bot.
Luego, sube la siguiente imagen y pídele al agente que genere un clip promocional a partir de ella.
Generate a slow zoom in and moving from left and right animation

Aparecerá el siguiente error:

¿Por qué? Como la herramienta también devolvió resultados directamente en forma de cadena base64, se excederá el token máximo. Ahora, controlaremos este error en la siguiente sección.
6. 🚀 Modificación de la respuesta de la herramienta
En esta sección, controlaremos la respuesta de la herramienta a partir de la respuesta del MCP. Haremos lo siguiente:
- Almacenar la respuesta de video de la herramienta en el servicio de artefactos
- Devuelve el identificador del artefacto al agente.
Como recordatorio, aprovecharemos el siguiente tiempo de ejecución del agente

Primero, implementemos la función de devolución de llamada. Para ello, abre product_photo_editor/tool_callbacks.py y modifícalo para implementar 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
Después de eso, debemos equipar a nuestro agente con esta función. Abre product_photo_editor/agent.py y modifícalo con el siguiente código:
# 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,
)
Listo. Ahora puedes pedirle al agente que no solo te ayude a editar la foto, sino que también genere un video para ti. Vuelve a ejecutar el siguiente comando.
uv run adk web --port 8080
Luego, intenta crear un video con esta imagen.
Generate a slow zoom in and moving from left and right animation

Verás el video generado, como el ejemplo que se muestra a continuación, y ya se guardó como artefacto.

7. ⭐ Resumen
Ahora, revisemos lo que ya hicimos durante este codelab. Este es el aprendizaje clave:
- Manejo de datos multimodales (E/S de herramientas): Se reforzó la estrategia para administrar datos multimodales (como imágenes y videos) para la entrada y salida de herramientas con el servicio de artefactos del ADK y devoluciones de llamada especializadas en lugar de pasar datos de bytes sin procesar directamente.
- Integración del conjunto de herramientas de MCP: Se desarrolló y se integró un servidor de MCP externo de Veo con FastMCP a través del conjunto de herramientas de MCP del ADK para agregar capacidades de generación de video al agente.
- Modificación de entrada de la herramienta (before_tool_callback): Se implementó una devolución de llamada para interceptar la llamada a la herramienta generate_video_with_image, que transforma el artifact_id del archivo (seleccionado por el LLM) en los datos de imagen codificados en base64 requeridos para la entrada del servidor de MCP.
- Modificación del resultado de la herramienta (after_tool_callback): Se implementó una devolución de llamada para interceptar la respuesta de video grande codificada en base64 del servidor de MCP, guardar el video como un artefacto nuevo y devolver una referencia limpia de video_artifact_id al LLM.
8. 🧹 Limpieza
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, elige el proyecto que deseas borrar y haz clic en Borrar.
- En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrarlo.