콘텐츠로 이동

미디어

기계 번역

이 페이지는 영어 문서를 자동으로 번역한 것이며, 영어 페이지가 기준이 되는 정식 버전입니다. 어색하거나 잘못된 부분이 있다면 번역 페이지에서 제보하는 방법을 확인하세요.

도구가 반환할 수 있는 것은 텍스트만이 아닙니다.

SDK는 바이너리 결과를 위한 두 가지 헬퍼(Image와 Audio)와, 클라이언트 UI에서 서버, 도구, 리소스, 프롬프트에 얼굴을 부여하는 Icon 타입을 제공합니다.

이미지 반환하기

반환 타입을 Image로 표기하고, 파일을 지정한 뒤 반환하세요.

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는 path(읽을 파일) 또는 data(원시 바이트) 중 정확히 하나만 받습니다.
  • 클라이언트가 보는 MIME 타입은 확장자로 추측합니다. logo.png는 image/png로 알려집니다.
  • 로고라서 특별한 것은 아닙니다. server.py 옆에 있는 PNG라면 무엇이든 됩니다. 코드가 렌더링한 차트, 다이어그램, 사진 모두 가능합니다.

Image는 SDK의 편의 기능이지 프로토콜 타입이 아닙니다. 전송 시 반환값은 ImageContent 블록(파일의 바이트를 base64로 인코딩한 값과 MIME 타입)이 됩니다.

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

눈여겨볼 점이 두 가지 있습니다.

  • data는 base64입니다. 바이트를 직접 다룬 적이 없습니다. SDK가 파일을 읽고 인코딩까지 처리했습니다.
  • structured_content는 None입니다. Image는 모델이 보기 위한 콘텐츠이지 애플리케이션이 파싱할 데이터가 아니므로 출력 스키마가 없습니다. (반환 타입 표기가 곧 스키마가 되는 구조화된 출력과 대조해 보세요.)

Info

ImageContent와 AudioContent는 mcp.types에 있으며, 평범한 str 결과가 변환되는 TextContent 바로 옆에 있습니다(도구). 도구 결과는 콘텐츠 블록의 리스트이고, Image와 Audio는 두 가지 바이너리 종류를 만드는 가장 짧은 방법입니다.

직접 해 보기

아무 PNG나 server.py 옆에 두고 이름을 logo.png로 바꾼 뒤 다음을 실행하세요.

uv run mcp dev server.py

Tools 탭을 열고 logo를 호출하세요. 결과는 문자열이 아니라 image 콘텐츠 블록이며, Inspector가 그림을 렌더링합니다. 디스크의 파일에서 화면의 픽셀까지, 그 사이의 모든 일은 SDK가 했습니다.

오디오 반환하기

Audio도 같은 형태입니다. logo.png는 그대로 두고, 아무 WAV나 그 옆에 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)

결과는 AudioContent 블록입니다.

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

마찬가지입니다. 디스크의 파일이 들어가고, base64와 MIME 타입이 나오며, 출력 스키마는 없습니다.

바이트 또는 파일

두 헬퍼 모두 path= 대신 data=(원시 바이트)도 받습니다. 애초에 자기 파일에서 온 적이 없는 바이트, 즉 데이터베이스 컬럼, HTTP 응답, Pillow가 방금 그린 결과물 같은 경우에 쓰는 방식입니다.

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

path=를 쓰면 선언할 것이 없습니다. 결과를 만들 때 파일을 읽고, MIME 타입은 확장자로 추측합니다.

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

인식하지 못하는 확장자는 application/octet-stream으로 대체됩니다.

Check

data=를 쓰면 파일 이름이 없으므로 추측할 근거가 없습니다. format=을 빠뜨리면 SDK는 기본값으로 대체합니다. 이미지는 image/png, 오디오는 audio/wav입니다. MP3 바이트로 Audio를 그렇게 만들면 클라이언트는 mime_type="audio/wav"라고 전달받고, 그대로 믿고 디코딩에 실패합니다. data=를 전달할 때는 format=도 전달하세요.

리소스 임베드하기

도구는 문서도 반환할 수 있습니다. 텍스트나 바이트를 그 문서가 위치한 URI, MIME 타입과 함께 묶은 것입니다. 이것이 또 다른 종류의 콘텐츠 블록인 EmbeddedResource입니다. 평범한 str과 달리 콘텐츠가 무엇인지 클라이언트에게 알려 주므로, 클라이언트는 이를 첨부 파일로 보여 주거나 이미 알고 있는 리소스임을 알아볼 수 있습니다.

server.py
from mcp.server import MCPServer
from mcp.types import EmbeddedResource, TextResourceContents

mcp = MCPServer("Brand kit")


@mcp.resource("brand://guidelines", mime_type="text/markdown")
def guidelines() -> str:
    """How to use the brand assets."""
    return "# Brand guidelines\n\nUse the primary colour for calls to action.\n"


@mcp.tool()
def brand_guidelines() -> EmbeddedResource:
    """The brand guidelines as a Markdown document."""
    return EmbeddedResource(
        resource=TextResourceContents(uri="brand://guidelines", mime_type="text/markdown", text=guidelines())
    )
  • brand://guidelines는 평범한 리소스입니다(리소스에서 다룹니다). 도구는 요청이 있을 때 같은 문서를 모델에게 건네며, guidelines()를 직접 호출하므로 단일 정보 출처가 유지됩니다.
  • EmbeddedResource와 TextResourceContents는 mcp.types에서 가져옵니다. 이미지처럼 헬퍼가 있는 것은 아닙니다. 만든 블록은 그대로 결과에 들어가고, structured_content는 없습니다.
  • 리소스가 등록된 URI를 쓰세요. 그래야 클라이언트가 첨부 파일과 brand://guidelines가 같은 문서임을 알 수 있습니다. 등록 여부와 상관없이 어떤 URI든 허용됩니다.
result.content  # [EmbeddedResource(type="resource", resource=TextResourceContents(uri="brand://guidelines", mime_type="text/markdown", text="# Brand guidelines\n\n..."))]

바이너리 콘텐츠에는 TextResourceContents 대신 BlobResourceContents(uri=..., mime_type=..., blob=...)를 쓰고, 바이트를 base64로 인코딩해 blob에 넣으세요. 클라이언트가 나중에 resources/read로 읽을 수 있는 포인터만 보내려면 대신 ResourceLink(name=..., uri=...)를 반환하세요. 이것도 콘텐츠 블록입니다.

아이콘

Icon은 콘텐츠가 아니라 메타데이터입니다. 이미지를 담지 않고 URI로 이미지를 가리키며, 클라이언트는 이를 가져와 서버 이름, 도구, 리소스, 프롬프트 옆에 표시할 수 있습니다.

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는 클라이언트가 해석할 수 있는 URI입니다. https:이거나, 추가로 가져오지 않고 아이콘을 내장하고 싶다면 data: URI를 씁니다.
  • mime_type과 sizes("48x48", 또는 크기 조절이 가능한 형식이면 "any")는 여러 개를 제공할 때 클라이언트가 알맞은 것을 고르게 해 줍니다.
  • theme="light" 또는 theme="dark"는 아이콘을 한 가지 색 구성표용으로 표시합니다.

같은 icons=[...] 키워드를 MCPServer(...), @mcp.tool(), @mcp.resource(), @mcp.prompt()가 모두 받습니다.

클라이언트가 보는 위치

아이콘은 자신이 꾸미는 대상과 함께 전달됩니다. 서버의 아이콘은 클라이언트가 연결할 때 client.server_info로 도착합니다(2026년대 연결에서는 선택 사항이므로 먼저 타입을 좁히세요).

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

도구의 아이콘은 tools/list의 Tool 객체에, 리소스의 아이콘은 resources/list의 Resource에, 프롬프트의 아이콘은 prompts/list의 Prompt에 있습니다. 필드 이름은 언제나 icons입니다.

요약

  • 도구에서 Image나 Audio를 반환하면 클라이언트는 ImageContent / AudioContent 블록을 받습니다. 바이트는 base64로 인코딩되고 MIME 타입이 함께 갑니다.
  • path=로 만들어 확장자가 MIME 타입을 정하게 하거나, 메모리의 data=와 명시적인 format=으로 만드세요.
  • EmbeddedResource를 반환하면 문서(텍스트 또는 base64 blob, URI와 MIME 타입 포함)를 결과에 넣을 수 있고, ResourceLink를 반환하면 포인터만 보냅니다.
  • 미디어 결과에는 structured_content도 출력 스키마도 없습니다.
  • Icon은 포인터입니다. src URI에 선택적인 mime_type, sizes, theme이 더해집니다.
  • icons=[...]는 서버, 도구, 리소스, 프롬프트에서 동작하며, 클라이언트는 대응하는 객체에서 아이콘을 찾습니다.

이것이 도구가 결과에 넣을 수 있는 전부입니다. 도구가 실패할 때 무슨 일이 일어나는지(그리고 누가 알아야 하는지)는 오류 처리에서 다룹니다.