Aller au contenu

Médias

Traduction automatique

Cette page a été traduite automatiquement à partir de la documentation en anglais, et la page en anglais fait foi. Si quelque chose vous semble incorrect, la page Traductions explique comment le signaler.

Le texte n’est pas la seule chose qu’un outil (tool) peut renvoyer.

Le SDK fournit deux utilitaires pour les résultats binaires (Image et Audio) et un type Icon pour donner un visage à votre serveur, à vos outils, à vos ressources et à vos prompts dans l’interface du client.

Renvoyer une image

Annotez le type de retour avec Image, pointez-le vers un fichier, et renvoyez-le :

server.py
from pathlib import Path

from mcp.server import MCPServer
from mcp.server.mcpserver import Image

mcp = MCPServer("Brand kit")

LOGO_FILE = Path(__file__).parent / "logo.png"  # or the path to your file on disk


@mcp.tool()
def logo() -> Image:
    """The brand logo as a PNG."""
    return Image(path=LOGO_FILE)
  • Image prend exactement l’un des deux : path (un fichier à lire) ou data (des octets bruts).
  • Le type MIME que voit le client est deviné à partir de l’extension : logo.png est annoncé comme image/png.
  • Les logos n’ont rien de particulier ici. N’importe quel PNG placé à côté de server.py convient : un graphique que votre code a généré, un schéma, une photo.

Image est une commodité du SDK, pas un type du protocole. Sur la liaison, votre valeur de retour devient un bloc ImageContent (les octets du fichier encodés en base64, plus le type MIME) :

result.content             # [ImageContent(type="image", data="iVBORw0KGgoAAAANSUhEUg...", mime_type="image/png")]
result.structured_content  # None

Deux choses à remarquer :

  • data est en base64. Vous n’avez jamais touché aux octets ; le SDK a lu le fichier et s’est chargé de l’encodage.
  • structured_content vaut None. Une Image est du contenu que le modèle regarde, pas des données que l’application analyse : il n’y a pas de schéma de sortie. (À comparer avec la Sortie structurée, où l’annotation de retour est le schéma.)

Info

ImageContent et AudioContent se trouvent dans mcp.types, juste à côté du TextContent que devient un simple résultat str (Outils). Un résultat d’outil est une liste de blocs de contenu ; Image et Audio sont le moyen le plus court de produire les deux variantes binaires.

Essayer

Déposez n’importe quel PNG à côté de server.py, nommez-le logo.png, et lancez :

uv run mcp dev server.py

Ouvrez l’onglet Tools et appelez logo. Le résultat n’est pas une chaîne : c’est un bloc de contenu image, et l’Inspector affiche votre image. Tout ce qui s’est passé entre le fichier sur le disque et les pixels à l’écran, c’est le SDK.

Renvoyer de l’audio

Audio a la même forme. Laissez logo.png là où il était, et placez n’importe quel WAV à côté, sous le nom chime.wav :

server.py
from pathlib import Path

from mcp.server import MCPServer
from mcp.server.mcpserver import Audio, Image

mcp = MCPServer("Brand kit")

LOGO_FILE = Path(__file__).parent / "logo.png"
CHIME_FILE = Path(__file__).parent / "chime.wav"


@mcp.tool()
def logo() -> Image:
    """The brand logo as a PNG."""
    return Image(path=LOGO_FILE)


@mcp.tool()
def chime() -> Audio:
    """The notification chime as a WAV."""
    return Audio(path=CHIME_FILE)

Le résultat est un bloc AudioContent :

result.content             # [AudioContent(type="audio", data="UklGR...", mime_type="audio/wav")]
result.structured_content  # None

Même principe : un fichier sur le disque en entrée, du base64 et un type MIME en sortie, pas de schéma de sortie.

Des octets ou un fichier

Les deux utilitaires acceptent aussi data= (des octets bruts) à la place de path=. C’est le mode prévu pour des octets qui n’ont jamais eu de fichier à eux — une colonne de base de données, une réponse HTTP, quelque chose que Pillow vient de dessiner :

server.py
from pathlib import Path

from mcp.server import MCPServer
from mcp.server.mcpserver import Image

mcp = MCPServer("Brand kit")

LOGO_FILE = Path(__file__).parent / "logo.png"


@mcp.tool()
def logo_from_bytes() -> Image:
    """The brand logo as a PNG."""
    png = LOGO_FILE.read_bytes()  # a database read, an HTTP response, Pillow output...
    return Image(data=png, format="png")

Avec path=, il n’y a rien à déclarer : le fichier est lu au moment où le résultat est construit, et le type MIME est deviné à partir de l’extension :

  • Image : .png, .jpg, .jpeg, .gif, .webp.
  • Audio : .wav, .mp3, .ogg, .flac, .aac, .m4a.

Une extension qu’il ne reconnaît pas se rabat sur application/octet-stream.

Check

Avec data=, il n’y a pas de nom de fichier, donc rien à partir de quoi deviner. Oubliez format= et le SDK se rabat sur une valeur par défaut : image/png pour les images, audio/wav pour l’audio. Construisez un Audio à partir d’octets MP3 de cette façon et le client reçoit mime_type="audio/wav", puis échoue consciencieusement à le décoder. Quand vous passez data=, passez format=.

Icônes

Une Icon est une métadonnée, pas du contenu. Elle ne transporte pas l’image ; elle en désigne une par un URI, et un client peut la récupérer et l’afficher à côté du nom de votre serveur, d’un outil, d’une ressource ou d’un prompt.

server.py
from mcp.server import MCPServer
from mcp.types import Icon

LOGO = Icon(src="https://example.com/brand-kit.png", mime_type="image/png", sizes=["48x48"])
PALETTE = Icon(src="https://example.com/palette.svg", mime_type="image/svg+xml", sizes=["any"])

mcp = MCPServer("Brand kit", icons=[LOGO])


@mcp.tool(icons=[PALETTE])
def palette() -> list[str]:
    """The brand colour palette as hex codes."""
    return ["#1d4ed8", "#f59e0b", "#10b981"]


@mcp.resource("brand://guidelines", icons=[LOGO])
def guidelines() -> str:
    """How to use the brand assets."""
    return "Use the primary colour for calls to action."
  • src est un URI que le client peut résoudre : https:, ou un URI data: si vous voulez l’icône embarquée sans récupération supplémentaire.
  • mime_type et sizes ("48x48", ou "any" pour un format vectoriel) permettent au client de choisir la bonne lorsque vous en proposez plusieurs.
  • theme="light" ou theme="dark" réserve une icône à un jeu de couleurs.

Le même mot-clé icons=[...] est accepté par MCPServer(...), @mcp.tool(), @mcp.resource() et @mcp.prompt().

Où un client les voit

Les icônes voyagent avec ce qu’elles décorent. Celles du serveur arrivent quand le client se connecte, sur client.server_info (facultatif sur les connexions de génération 2026, donc restreignez d’abord le type) :

assert client.server_info is not None  # python-sdk servers identify themselves by default
client.server_info.icons  # [Icon(src="https://example.com/brand-kit.png", mime_type="image/png", sizes=["48x48"])]

Les icônes d’un outil sont sur l’objet Tool issu de tools/list, celles d’une ressource sur le Resource issu de resources/list, celles d’un prompt sur le Prompt issu de prompts/list. Le champ s’appelle toujours icons.

Récapitulatif

  • Renvoyez une Image ou un Audio depuis un outil et le client reçoit un bloc ImageContent / AudioContent : vos octets encodés en base64, avec un type MIME.
  • Construisez-en un à partir d’un path= et laissez l’extension décider du type MIME, ou à partir de data= en mémoire plus un format= explicite.
  • Les résultats média ne portent ni structured_content ni schéma de sortie.
  • Une Icon est un pointeur : un URI src plus, en option, mime_type, sizes et theme.
  • icons=[...] fonctionne sur le serveur, sur les outils, sur les ressources et sur les prompts, et les clients les retrouvent sur les objets correspondants.

C’est tout ce qu’un outil peut mettre dans un résultat. Ce qui se passe quand un outil échoue (et qui doit l’apprendre), c’est Gérer les erreurs.