You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: load media examples from disk instead of inline base64
The Image/Audio tutorials fed the helpers base64-decoded one-pixel
placeholders, so the first thing a reader met was an opaque blob.
Point them at logo.png / chime.wav beside the server instead, anchored
to the script's own directory so hosts that launch stdio servers from
an arbitrary working directory still resolve them. The page teaches
path= first and keeps data= + format= for bytes that never touch disk.
Tests fabricate the assets in tmp_path and repoint the module
constants, so no binary lands in the repo.
Copy file name to clipboardExpand all lines: docs/servers/media.md
+24-14Lines changed: 24 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,17 +6,18 @@ The SDK ships two helpers for binary results (**`Image`** and **`Audio`**) and a
6
6
7
7
## Returning an image
8
8
9
-
Annotate the return type as `Image`and return one:
9
+
Annotate the return type as `Image`, point it at a file, and return it:
10
10
11
-
```python title="server.py" hl_lines="14 16"
11
+
```python title="server.py" hl_lines="8 12 14"
12
12
--8<--"docs_src/media/tutorial001.py"
13
13
```
14
14
15
-
*`Image` takes exactly one of `data` (raw bytes) or `path` (a file to read).
16
-
*`format="png"` becomes the MIME type the client sees: `image/png`.
17
-
* The bytes here are a one-pixel placeholder so the file runs on its own. In a real server they come from Pillow, matplotlib, a headless browser, or anything else that hands you `bytes`.
15
+
*`Image` takes exactly one of `path` (a file to read) or `data` (raw bytes).
16
+
* The MIME type the client sees is guessed from the suffix: `logo.png` is announced as `image/png`.
17
+
* Anchoring to `Path(__file__).parent` matters. Hosts launch stdio servers from an arbitrary working directory, so a bare `"logo.png"` would resolve against wherever that happens to be.
18
+
* Nothing here is special about logos. Any PNG next to `server.py` works: a chart your code rendered, a diagram, a photo.
18
19
19
-
`Image` is an SDK convenience, not a protocol type. On the wire your return value becomes an **`ImageContent`** block (your bytes base64-encoded, plus the MIME type):
20
+
`Image` is an SDK convenience, not a protocol type. On the wire your return value becomes an **`ImageContent`** block (the file's bytes base64-encoded, plus the MIME type):
*`data` is base64. You returned raw `bytes`; the SDK did the encoding.
29
+
*`data` is base64. You never touched the bytes; the SDK read the file and did the encoding.
29
30
*`structured_content` is `None`. An `Image` is content for the model to look at, not data for the application to parse: there is no output schema. (Contrast **[Structured Output](structured-output.md)**, where the return annotation *is* the schema.)
30
31
31
32
!!! info
@@ -35,32 +36,41 @@ Two things to notice:
35
36
36
37
### Try it
37
38
39
+
Drop any PNG next to `server.py`, name it `logo.png`, and run:
40
+
38
41
```console
39
42
uv run mcp dev server.py
40
43
```
41
44
42
-
Open the **Tools** tab and call `logo`. The result is not a string: it is an `image` content block, and the Inspector renders it as a picture. You returned `bytes`; everything between that and the pixels on screen was the SDK.
45
+
Open the **Tools** tab and call `logo`. The result is not a string: it is an `image` content block, and the Inspector renders your picture. Everything between the file on disk and the pixels on screen was the SDK.
43
46
44
47
## Returning audio
45
48
46
-
`Audio` is the same shape:
49
+
`Audio` is the same shape. Keep `logo.png` where it was, and put any WAV beside it as `chime.wav`:
Same deal: raw bytes in, base64 and a MIME type out, no output schema.
62
+
Same deal: a file on disk in, base64 and a MIME type out, no output schema.
60
63
61
64
## Bytes or a file
62
65
63
-
Both helpers also accept `path=` instead of `data=`. The file is read when the result is built, and the MIME type is guessed from the suffix:
66
+
Both helpers also accept `data=` (raw bytes) instead of `path=`. That is the mode for bytes that never touch disk — Pillow just drew the chart, a headless browser just took the screenshot:
67
+
68
+
```python
69
+
Image(data=chart_png, format="png") # image/png
70
+
Audio(data=chime_wav, format="wav") # audio/wav
71
+
```
72
+
73
+
With `path=` there is nothing to declare: the file is read when the result is built, and the MIME type is guessed from the suffix:
@@ -100,7 +110,7 @@ A tool's icons are on the `Tool` object from `tools/list`, a resource's on the `
100
110
## Recap
101
111
102
112
* Return an `Image` or `Audio` from a tool and the client receives an `ImageContent` / `AudioContent` block: your bytes base64-encoded, with a MIME type.
103
-
* Build one from in-memory `data=`plus an explicit `format=`, or from a `path=`and let the suffix decide.
113
+
* Build one from a `path=`and let the suffix decide the MIME type, or from in-memory `data=`plus an explicit `format=`.
104
114
* Media results carry no `structured_content` and no output schema.
105
115
* An `Icon` is a pointer: a `src` URI plus optional `mime_type`, `sizes`, and `theme`.
106
116
*`icons=[...]` works on the server, on tools, on resources, and on prompts, and clients find them on the matching objects.
0 commit comments