Zum Inhalt

Medien

Maschinelle Übersetzung

Diese Seite wurde automatisch aus der englischen Dokumentation übersetzt, und die englische Seite ist die maßgebliche Fassung. Wenn sich etwas falsch liest, erklärt Übersetzungen, wie du es melden kannst.

Text ist nicht das Einzige, was ein Tool zurückgeben kann.

Das SDK bringt zwei Helfer für binäre Ergebnisse mit (Image und Audio) sowie einen Typ Icon, mit dem dein Server, deine Tools, Ressourcen und Prompts im UI des Clients ein Gesicht bekommen.

Ein Bild zurückgeben

Annotiere den Rückgabetyp als Image, zeige auf eine Datei und gib sie zurück:

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 nimmt genau eines von path (eine Datei, die gelesen wird) oder data (rohe Bytes).
  • Den MIME-Typ, den der Client sieht, errät das SDK aus der Dateiendung: logo.png wird als image/png angekündigt.
  • Nichts hiervon ist speziell für Logos. Jedes PNG neben server.py funktioniert: ein Diagramm, das dein Code gerendert hat, eine Skizze, ein Foto.

Image ist eine Bequemlichkeit des SDK, kein Protokolltyp. Auf der Leitung wird dein Rückgabewert zu einem ImageContent-Block (die Bytes der Datei base64-kodiert, dazu der MIME-Typ):

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

Zwei Dinge fallen auf:

  • data ist base64. Du hast die Bytes nie angefasst; das SDK hat die Datei gelesen und kodiert.
  • structured_content ist None. Ein Image ist Inhalt, den das Modell anschaut, keine Daten, die die Anwendung parst: Es gibt kein Output-Schema. (Vergleiche Strukturierte Ausgabe, wo die Rückgabeannotation das Schema ist.)

Info

ImageContent und AudioContent liegen in mcp.types, direkt neben dem TextContent, zu dem ein einfaches str-Ergebnis wird (Tools). Ein Tool-Ergebnis ist eine Liste von Content-Blöcken; Image und Audio sind der kürzeste Weg, die beiden binären Arten zu erzeugen.

Ausprobieren

Lege ein beliebiges PNG neben server.py, nenne es logo.png und starte:

uv run mcp dev server.py

Öffne den Tab Tools und rufe logo auf. Das Ergebnis ist kein String: Es ist ein Content-Block vom Typ image, und der Inspector rendert dein Bild. Alles zwischen der Datei auf der Platte und den Pixeln auf dem Bildschirm hat das SDK erledigt.

Audio zurückgeben

Audio hat dieselbe Form. Lass logo.png, wo es war, und lege eine beliebige WAV-Datei als chime.wav daneben:

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)

Das Ergebnis ist ein AudioContent-Block:

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

Dasselbe Prinzip: eine Datei auf der Platte hinein, base64 und ein MIME-Typ heraus, kein Output-Schema.

Bytes oder eine Datei

Beide Helfer akzeptieren auch data= (rohe Bytes) statt path=. Das ist der Modus für Bytes, die nie aus einer eigenen Datei kamen – eine Datenbankspalte, eine HTTP-Response, etwas, das Pillow gerade gezeichnet hat:

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")

Mit path= gibt es nichts zu deklarieren: Die Datei wird gelesen, wenn das Ergebnis gebaut wird, und der MIME-Typ wird aus der Endung erraten:

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

Eine Endung, die nicht erkannt wird, fällt auf application/octet-stream zurück.

Check

Mit data= gibt es keinen Dateinamen, also nichts, woraus sich etwas erraten ließe. Vergisst du format=, fällt das SDK auf einen Standardwert zurück: image/png für Bilder, audio/wav für Audio. Baust du so ein Audio aus MP3-Bytes, bekommt der Client mime_type="audio/wav" mitgeteilt und scheitert dann folgerichtig am Dekodieren. Wenn du data= übergibst, übergib auch format=.

Icons

Ein Icon ist Metadaten, kein Inhalt. Es trägt das Bild nicht; es zeigt per URI auf eines, und ein Client kann es abrufen und neben dem Namen deines Servers, einem Tool, einer Ressource oder einem Prompt anzeigen.

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 ist ein URI, den der Client auflösen kann: https: oder ein data:-URI, wenn du das Icon ohne zusätzlichen Abruf einbetten willst.
  • Mit mime_type und sizes ("48x48" oder "any" für ein skalierbares Format) kann der Client das passende auswählen, wenn du mehrere anbietest.
  • theme="light" oder theme="dark" markiert ein Icon für ein Farbschema.

Dasselbe Keyword icons=[...] akzeptieren MCPServer(...), @mcp.tool(), @mcp.resource() und @mcp.prompt().

Wo ein Client sie sieht

Icons reisen mit dem, was sie schmücken. Die des Servers kommen an, wenn sich der Client verbindet, auf client.server_info (auf Verbindungen der 2026er-Generation optional, also grenze es zuerst ein):

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"])]

Die Icons eines Tools liegen auf dem Tool-Objekt aus tools/list, die einer Ressource auf der Resource aus resources/list, die eines Prompts auf dem Prompt aus prompts/list. Das Feld heißt immer icons.

Zusammenfassung

  • Gib ein Image oder Audio aus einem Tool zurück, und der Client empfängt einen ImageContent- bzw. AudioContent-Block: deine Bytes base64-kodiert, mit einem MIME-Typ.
  • Baue eines aus einem path= und lass die Endung den MIME-Typ bestimmen, oder aus data= im Speicher plus einem expliziten format=.
  • Medien-Ergebnisse tragen kein structured_content und kein Output-Schema.
  • Ein Icon ist ein Zeiger: ein src-URI plus optional mime_type, sizes und theme.
  • icons=[...] funktioniert auf dem Server, auf Tools, auf Ressourcen und auf Prompts, und Clients finden sie auf den passenden Objekten.

Das ist alles, was ein Tool in ein Ergebnis packen kann. Was passiert, wenn ein Tool fehlschlägt (und wer davon erfahren sollte), steht in Fehler behandeln.