docs: refresh translations for recent English changes (#3379)

This commit is contained in:
Max 2026-08-24 19:29:54 +01:00 • committed by GitHub
commit c5d7d0b6d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 3149 additions and 1047 deletions

View file

@ -1,13 +1,13 @@
---
translation:
sections: [e33d441f12d50535, 7099694c603e0f5f, c1df4cf9673433e6, c9cd294541422e6e, 6cec073617bfd037, efa92b8f99e908c8, 6a22a29e27fb4601]
sections: [7be05607887e6853, e7375894888d9750, c36f73fc7e3af13b, 2fec2d7e129e62fe, 809b0e0a7c27295a, b4395a04d2a5d906, 1a436007f5f54779, c6b2078ed1e63ba5]
tool: 1
---
# Обробка помилок {#handling-errors}
Інструмент може завершитися невдачею двома способами, і SDK обробляє їх зовсім по-різному.
Інструмент може завершитися невдачею трьома способами, і SDK обробляє кожен по-різному.
Викиньте звичайний виняток — і його побачить **модель**. Викиньте `MCPError` — і його побачить **протокол**.
Викиньте `ToolError` — і ваше повідомлення побачить **модель**. Викиньте `MCPError` — і його побачить **протокол**. Викиньте будь-що інше — і це збій: модель дізнається лише, що виклик не вдався, а трасування потрапить у ваш лог.
Ця сторінка — про те, як вибрати.
@ -15,11 +15,11 @@ translation:
Візьмімо інструмент, який щось шукає, і нехай пошук нічого не знайде:
```python title="server.py" hl_lines="11-12"
```python title="server.py" hl_lines="2 12-13"
--8<-- "docs_src/handling_errors/tutorial001.py"
```
У цих двох рядках немає нічого специфічного для MCP. `get_author` викидає звичайний `ValueError`, як це зробила б будь-яка функція Python.
`ToolError` з `mcp.server.mcpserver.exceptions` — це спосіб, яким інструмент повідомляє моделі, що щось пішло не так.
Викличте його з назвою, якої немає в каталозі, і подивіться на результат:
@ -30,13 +30,15 @@ result.structured_content # None
```
* Запит **виконався успішно**. Результат є; на боці того, хто викликав, нічого не викинуто.
* `is_error` дорівнює `True`, а повідомлення вашого винятку (з назвою інструмента на початку) лежить у `content` — саме там, де читає модель.
* `is_error` дорівнює `True`, а ваше повідомлення (з назвою інструмента на початку) лежить у `content` — саме там, де читає модель.
* `structured_content` дорівнює `None`. У невдалого виклику немає значення, яке можна було б структурувати.
Це **помилка інструмента**, і так за замовчуванням обробляється *будь-який* виняток, який викидає ваш інструмент. І майже завжди це саме те, що потрібно.
Це **помилка інструмента**, і майже завжди це саме те, що потрібно.
Ваш інструмент викликає саме модель. Це вона обрала аргументи. Тож помилка інструмента — це репліка в розмові: модель читає *«No book titled 'Nothing' in the catalog.»*, розуміє, що не вгадала назву, і викликає знову з кращою. Один `raise` — і маєте агента, що сам виправляє свої помилки.
На сервері `ToolError` — це один рядок рівня `INFO` у лозі, без трасування. Ви цього очікували, тож розслідувати нічого.
!!! tip
Ніколи не повертайте повідомлення про помилку з інструмента через `return`. Повернутий рядок має `is_error=False`, тож для
моделі (і для кожного клієнтського інтерфейсу) це виглядає так, ніби інструмент спрацював і цей рядок і є відповіддю.
@ -44,7 +46,7 @@ result.structured_content # None
## Помилка, яку модель не може виправити {#an-error-the-model-cannot-fix}
Тепер замініть `ValueError` на `MCPError`.
Тепер замініть `ToolError` на `MCPError`.
```python title="server.py" hl_lines="1 3 14"
--8<-- "docs_src/handling_errors/tutorial002.py"
@ -77,10 +79,10 @@ result.structured_content # None
Ці два шляхи відповідають на два різні запитання.
* **Викидайте будь-який виняток** у разі збою *виконання*: те, що інструмент намагався зробити, не вдалося. Виклик обрала модель, тож саме модель має побачити наслідок і отримати шанс виправитися. Назва з помилкою, зовнішній API, що не відповів вчасно, рядок, якого не існує, — усе це помилки інструмента.
* **Викидайте `ToolError`** у разі збою *виконання*: те, що інструмент намагався зробити, не вдалося. Виклик обрала модель, тож саме модель має побачити наслідок і отримати шанс виправитися. Назва з помилкою, зовнішній API, що не відповів вчасно, рядок, якого не існує, — усе це помилки інструмента.
* **Викидайте `MCPError`**, коли слід відхилити *сам запит*: клієнтові бракує можливості, від якої залежить інструмент, сервер не в тому стані, щоб обслуговувати будь-кого, той, хто викликає, пропустив обов'язковий крок. Жодна повторна спроба моделі нічого з цього не виправить, тож передавати їй повідомлення немає сенсу.
Вирішує одне запитання: **чи могла б розумніша модель цього уникнути?** Так -> звичайний виняток. Ні -> `MCPError`.
Вирішує одне запитання: **чи могла б розумніша модель цього уникнути?** Так -> `ToolError`. Ні -> `MCPError`.
За цим критерієм друга версія `get_author` зробила хибний вибір: краща назва все виправляє, тож модель заслуговувала побачити повідомлення. Ця версія тут, щоб показати механізм, а не щоб його рекомендувати.
@ -89,6 +91,25 @@ result.structured_content # None
корисне навантаження `data`. Усе, що ви в них покладете, клієнт і отримає: SDK пересилає викинутий
`MCPError` дослівно, не очищуючи його.
## Будь-який інший виняток {#any-other-exception}
Тепер приберіть перевірку й дайте пошуку в словнику завершитися невдачею самому по собі:
```python title="server.py" hl_lines="11"
--8<-- "docs_src/handling_errors/tutorial004.py"
```
`CATALOG[title]` викидає `KeyError`. Ви його не передбачали, тож SDK вважає це збоєм:
```python
result.is_error # True
result.content # [TextContent(text="Error executing tool get_author")]
```
Виклик усе одно повертає `is_error=True`, тож модель знає, що він не вдався, і може рухатися далі. Чого вона не отримує — то це тексту винятку: `KeyError` з вашого коду чи купа SQL від драйвера на три бібліотеки глибше можуть описувати нутрощі вашого сервера, тому за його межі вони ніколи не виходять.
Натомість їх отримуєте ви. Сервер записує збій у лог на рівні `ERROR` з повним трасуванням як `Tool 'get_author' raised an unexpected exception`. Тож лог робочого середовища на рівні `WARNING` мовчить під час кожної `ToolError` і озивається, щойно щось справді зламалося.
## Ресурс, якого не існує {#a-resource-that-doesnt-exist}
Ресурси проводять ту саму межу й мають один іменований виняток для типового випадку.
@ -109,7 +130,7 @@ result.structured_content # None
}
```
Зверніть увагу: тут немає напіврезультату з `is_error=True`. Читання ресурсу або повертає вміст, або завершується помилкою: у ресурсів є лише протокольний шлях. Про шаблони й усе інше, що стосується ресурсів, — на сторінці **[Ресурси](resources.md)**.
Зверніть увагу: тут немає напіврезультату з `is_error=True`. Читання ресурсу або повертає вміст, або завершується помилкою: у ресурсів є лише протокольний шлях. `ResourceError` — те саме для збою, який не є «не знайдено» (`-32603`, ваше повідомлення), і обидва — це один рядок рівня `INFO` у вашому лозі. Будь-який інший виняток, окрім `MCPError`, — це збій: клієнт отримує `-32603`, де вказано лише URI, а трасування йде у ваш лог на рівні `ERROR`. Про шаблони й усе інше, що стосується ресурсів, — на сторінці **[Ресурси](resources.md)**.
## Помилки, які ви ніколи не викидаєте {#errors-you-never-raise}
@ -120,19 +141,21 @@ result.structured_content # None
Це означає цілий клас інструкцій `raise`, які писати не треба: не перевіряйте повторно власні анотації типів.
!!! info
Усе на цій сторінці — те, що бачить **клієнт**, і `Client` у пам'яті, з яким ви писатимете
тести, бачить рівно те саме. Навіть `raise_exceptions=True` не перетворює помилку інструмента
назад на трасування: до моменту, коли цей прапорець міг би спрацювати, ваш виняток уже став
результатом з `is_error=True`. Перевіряйте результат через assert. Цей підхід описано на сторінці **[Тестування](../get-started/testing.md)**.
Усе, що на цій сторінці бачить **клієнт**, бачить і `Client` у пам'яті, з яким ви писатимете
тести. Навіть `raise_exceptions=True` не повертає виняток інструмента, що впав,
тому, хто викликав: до моменту, коли цей прапорець міг би спрацювати, ваш виняток уже став
результатом з `is_error=True`. Перевіряйте результат через assert. Якщо потрібне трасування збою, воно
в лозі сервера, і `caplog` з pytest його перехоплює. Цей підхід описано на сторінці **[Тестування](../get-started/testing.md)**.
## Підсумки {#recap}
* Викиньте **будь-який виняток** в інструменті -> виклик повертає `is_error=True` з вашим повідомленням у `content`. Модель читає його й може повторити спробу. Це поведінка за замовчуванням.
* Викиньте **`ToolError`** в інструменті -> виклик повертає `is_error=True` з вашим повідомленням у `content`. Модель читає його й може повторити спробу.
* Викиньте **`MCPError`** -> сам виклик завершується помилкою JSON-RPC. Модель нічого не бачить; розбирається хост. `code`, `message` і `data` доходять без змін.
* Вирішальне запитання: *чи могла б розумніша модель цього уникнути?* Так -> виняток. Ні -> `MCPError`.
* Вирішальне запитання: *чи могла б розумніша модель цього уникнути?* Так -> `ToolError`. Ні -> `MCPError`.
* Будь-який **інший виняток** — це збій -> `is_error=True` лише з `Error executing tool <name>` для моделі та запис рівня `ERROR` із трасуванням для вас.
* `ResourceNotFoundError` з обробника ресурсу -> протокольний `-32602` з URI в `data`.
* Некоректні аргументи відхиляються за схемою ще до запуску вашої функції; для них `raise` не потрібен.
* `from mcp import MCPError`; константи кодів помилок — з `mcp.types`.
* Імпорти: `from mcp import MCPError`, `from mcp.server.mcpserver.exceptions import ToolError, ResourceError, ResourceNotFoundError` і константи кодів помилок з `mcp.types`.
З помилками розібралися. Це все, що сервер *надає назовні*. Про те, що кожен обробник може читати і що робити у відповідь клієнтові під час роботи, — наступний розділ: **[Усередині обробника](../handlers/index.md)**.

View file

@ -1,6 +1,6 @@
---
translation:
sections: [496394d24d221bf1, 4ceb4591180dc6c3, 0fd63e4682d02e0c, 969ede0bd3686a16, 043f526230dd243d, 6ee3e9bcfd24047a]
sections: [496394d24d221bf1, 4ceb4591180dc6c3, 0fd63e4682d02e0c, 969ede0bd3686a16, 864137b5e9c61e91, 043f526230dd243d, db1ef91db7d6b3f3]
tool: 1
---
# Медіа {#media}
@ -86,6 +86,24 @@ result.structured_content # None
так `Audio` з байтів MP3 — і клієнту повідомлять `mime_type="audio/wav"`, після чого
він сумлінно не зможе це декодувати. Передаєте `data=` — передавайте й `format=`.
## Вбудовування ресурсу {#embedding-a-resource}
Інструмент може повернути й документ: текст або байти разом з URI, за яким він доступний, і MIME-типом. Це **`EmbeddedResource`**, ще один різновид блока вмісту. На відміну від звичайного `str`, він повідомляє клієнту, що саме це за вміст, тож клієнт може показати його як вкладення або впізнати ресурс, який уже знає.
```python title="server.py" hl_lines="7 14 16-18"
--8<-- "docs_src/media/tutorial005.py"
```
* `brand://guidelines` — звичайний ресурс (про них — на сторінці **[Ресурси](resources.md)**). Інструмент на запит передає моделі той самий документ, а прямий виклик `guidelines()` зберігає єдине джерело істини.
* `EmbeddedResource` і `TextResourceContents` беруться з `mcp.types`. Допоміжного класу, як для зображень, немає: побудований блок потрапляє в результат без змін, і `structured_content` теж немає.
* Використовуйте URI, під яким ресурс зареєстровано, щоб клієнт міг зрозуміти, що вкладення й `brand://guidelines` — той самий документ. Дозволений будь-який URI, зареєстрований чи ні.
```python
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=...)` — це теж блок вмісту.
## Іконки {#icons}
`Icon` — це метадані, а не вміст. Він не містить зображення, а вказує на нього через URI, і клієнт може завантажити його й показати поруч із назвою сервера, інструментом, ресурсом чи промптом.
@ -115,6 +133,7 @@ client.server_info.icons # [Icon(src="https://example.com/brand-kit.png", mime_
* Поверніть з інструмента `Image` або `Audio` — і клієнт отримає блок `ImageContent` / `AudioContent`: ваші байти в кодуванні base64 з MIME-типом.
* Створюйте їх із `path=`, і тоді MIME-тип визначить розширення, або з `data=` у пам'яті плюс явний `format=`.
* Поверніть `EmbeddedResource`, щоб покласти в результат документ (текст або blob у base64 з його URI та MIME-типом), або `ResourceLink`, щоб надіслати лише вказівник.
* Медіарезультати не мають ні `structured_content`, ні схеми виводу.
* `Icon` — це вказівник: URI `src` плюс необов'язкові `mime_type`, `sizes` і `theme`.
* `icons=[...]` працює на сервері, інструментах, ресурсах і промптах, а клієнти знаходять їх у відповідних об'єктах.

View file

@ -1,6 +1,6 @@
---
translation:
sections: [d65c098f37f5b6c3, dd0c2724d6f2877e, 6835bb3570c6714c, ffe823cb0fedd488, f33651add1b59094]
sections: [d65c098f37f5b6c3, dd0c2724d6f2877e, 6835bb3570c6714c, d30d3c20168b88b2, f5ef38dad59d6f76, 6e38a699ba57fbdf, 2b984a3bf37a0ddd]
tool: 1
---
# Промпти {#prompts}
@ -139,10 +139,55 @@ uv run mcp dev server.py
```
!!! info
Якщо ви читали сторінку **[Інструменти](tools.md)**, то вже знаєте все, що є на цій. Той самий декоратор, той самий
Якщо ви читали сторінку **[Інструменти](tools.md)**, то вже знаєте все, про що йшлося досі. Той самий декоратор, той самий
docstring як опис, ті самі `Annotated`/`Field`. Змінюється лише те, хто
його запускає (користувач) і куди йде результат (у розмову).
## Більше ніж текст {#more-than-text}
`UserMessage` і `AssistantMessage` також приймають блок вмісту або допоміжний об'єкт `Image` / `Audio` всюди, де приймають `str`. У промптах трапляються два випадки: прикріпити документ і прикріпити зображення.
### Вбудовування файлу {#embedding-a-file}
```python title="server.py" hl_lines="5 12 21 23"
--8<-- "docs_src/prompts/tutorial004.py"
```
* Посібник зі стилю — це ресурс за адресою `style://python` (про них — на сторінці **[Ресурси](resources.md)**), який читається з файлу `style-guide.md` поруч із `server.py`. Покладіть туди будь-який Markdown-файл.
* `EmbeddedResource(resource=TextResourceContents(...))`, обидва з `mcp.types`, несе файл разом із його URI та MIME-типом як перше повідомлення; запит, що на нього посилається, іде слідом як звичайний текст.
* Вбудовування замість вставлення посібника в f-рядок дає клієнту змогу показати його як вкладення й пізніше знову відкрити `style://python`, а модель отримує файл дослівно. Для двійкового файлу використовуйте `BlobResourceContents` із `blob` у base64.
Після генерування `content` першого повідомлення — це блок `resource`:
```json
{"type": "resource", "resource": {"uri": "style://python", "mimeType": "text/markdown", "text": "* Prefer early returns.\n..."}}
```
### Прикріплення зображення {#attaching-an-image}
```python title="server.py" hl_lines="4 15"
--8<-- "docs_src/prompts/tutorial005.py"
```
* `Image` — допоміжний клас зі сторінки **[Зображення, аудіо та піктограми](media.md)**. `UserMessage` перетворює його на блок `ImageContent` (файл закодовано в base64, MIME-тип вгадано з `.png`), коли промпт генерується; `Audio` так само стає `AudioContent`.
* Покладіть будь-який PNG з іменем `architecture.png` поруч із `server.py`. Аргументи промпту — рядки, тому зображення завжди надходить із сервера; `component` лише дає слова.
```json
{"type": "image", "data": "iVBORw0KGgoAAAANSUhEUg...", "mimeType": "image/png"}
```
## Зміна списку під час роботи {#changing-the-list-at-runtime}
Промпти можна додавати, поки клієнти під'єднані, наприклад щоб користувач міг зберегти інструкцію як власний пункт меню. Зареєструйте промпт, а тоді надішліть сповіщення:
```python title="server.py" hl_lines="5 23-27"
--8<-- "docs_src/prompts/tutorial006.py"
```
* `mcp.add_prompt(Prompt.from_function(fn, name=..., description=...))` реєструє функцію точно так, як це зробив би `@mcp.prompt()`, а `mcp.remove_prompt(name)` — зворотна дія. `add_prompt` залишає наявний запис із тим самим іменем, а не перезаписує його, тому інструмент спершу видаляє старий, щоб збереження працювало як заміна. `prompts/list` відображає зміну одразу.
* `await ctx.notify_prompts_changed()` надсилає `notifications/prompts/list_changed` кожному клієнту `2026-07-28`, що слухає потік `subscriptions/listen` (**[Підписки](../handlers/subscriptions.md)**). `await ctx.session.send_prompt_list_changed()` надсилає його клієнту, який зробив виклик, якщо той старший за 2026 (**[Обслуговування клієнтів старого покоління](../run/legacy-clients.md)**). Викликайте обидва; кожен нічого не робить, коли сповіщати нікого.
* Клієнт, що отримав сповіщення, знову викликає `prompts/list`. У Python-класі `Client` це `async with client.listen(prompts_list_changed=True) as sub:`, що видає подію `PromptsListChanged`.
## Підсумки {#recap}
* `@mcp.prompt()` над функцією робить її промптом. Ім'я — з функції, опис — з docstring.
@ -151,5 +196,7 @@ uv run mcp dev server.py
* Поверніть `str` — і він стане одним повідомленням користувача. Поверніть список `UserMessage` / `AssistantMessage`, щоб закласти багатоходову розмову.
* `title=` і `Field(description=...)` — це те, що клієнт показує у своєму інтерфейсі.
* Відсутній обов'язковий аргумент провалює весь запит. Окремого результату з помилкою для промпту немає.
* Загорніть `EmbeddedResource` або `Image` у `UserMessage`, щоб прикріпити документ чи зображення.
* Додавайте або видаляйте промпти під час роботи через `mcp.add_prompt(...)` / `mcp.remove_prompt(...)`, а тоді викликайте `await ctx.notify_prompts_changed()` і `await ctx.session.send_prompt_list_changed()`.
Серверне автодоповнення аргументів промпту (або шаблону ресурсу) — це **[Автодоповнення](completions.md)**.

View file

@ -1,6 +1,6 @@
---
translation:
sections: [a838d57f003aed44, 857d03886a0137ed, 42d9efcb9f542867, 2290ff08435b5573, e866c192e11d1c14, 6cdbad079f7b47f0, d4b607372fb28b51, 18dbf726ac45e0b7, c6f7d2a148aa49f4, c851964bb3301907, d715db6f8dccc9cc, ef86634aa70498a7]
sections: [a838d57f003aed44, 857d03886a0137ed, 42d9efcb9f542867, 2290ff08435b5573, 91be9b73602abcf1, 6cdbad079f7b47f0, d4b607372fb28b51, 18dbf726ac45e0b7, c7eff2a5698225fa, c851964bb3301907, 8f296f1f09e4c400, d715db6f8dccc9cc, a0c344a48450dbe4]
tool: 1
---
# Структурований вивід {#structured-output}
@ -105,7 +105,7 @@ result.structured_content # {"temperature": 16.2, "humidity": 0.83, "conditions
--8<-- "docs_src/structured_output/tutorial003.py"
```
Під час виконання `TypedDict` — це звичайний `dict`, тож саме його ви будуєте й повертаєте. Схема, валідація і `structured_content` ідентичні версії з `BaseModel` (за винятком описів, для яких у `TypedDict` немає місця).
Під час виконання `TypedDict` — це звичайний `dict`, тож саме його ви будуєте й повертаєте. Схема, валідація і `structured_content` підпорядковуються тим самим правилам, що й у версії з `BaseModel`: додайте docstring класу або `Annotated[..., Field(description=...)]` — і вони стануть описами, а ключ `NotRequired`, якого немає в словнику, не потрапить і до `structured_content`.
## Dataclass {#a-dataclass}
@ -187,18 +187,19 @@ result.structured_content # {"London": 16.2, "Reykjavik": 4.4}
Анотація обіцяє `WeatherData`. Відповідь зовнішнього сервісу перестала надсилати `humidity`.
!!! check
Викличте `get_weather` — і він не передасть клієнту тихцем напівпорожній об'єкт. Виклик завершується помилкою,
і перші рядки помилки називають поле:
Викличте `get_weather` — і він не передасть клієнту тихцем напівпорожній об'єкт. Виклик завершується помилкою:
клієнт отримує `is_error=True` з `Error executing tool get_weather`, тож модель знає, що виклик
не вдався, замість того щоб упевнено читати погоду, якої немає. Назва поля — для вас,
у лозі сервера на рівні `ERROR`:
```text
Error executing tool get_weather: 1 validation error for WeatherData
Tool 'get_weather' raised an unexpected exception
...
pydantic_core._pydantic_core.ValidationError: 1 validation error for WeatherData
humidity
Field required [type=missing, input_value={'temperature': 16.2, 'conditions': 'Overcast'}, input_type=dict]
```
Цей текст повертається як результат інструмента з `is_error=True`, тож модель знає, що виклик не вдався,
замість того щоб упевнено читати погоду, якої немає.
До речі, повертати звичайний `dict` з інструмента з `-> WeatherData` цілком можна. Саме це й видав `json.loads`. Перевіряється значення, а не тип Python.
## Відмова від структурованого виводу {#opting-out}
@ -213,6 +214,10 @@ result.structured_content # {"London": 16.2, "Reykjavik": 4.4}
Протилежне, `structured_output=True`, перетворює автоматичне визначення на вимогу: інструмент, чий тип повернення не може дати схему, викидає виняток під час імпорту замість відкоту до тексту.
## Блоки вмісту й медіа {#content-blocks-and-media}
Блоки вмісту й медіа (`TextContent`, `EmbeddedResource`, `Image`, `Audio` та подібні — самі по собі, як елементи `list`, `tuple` чи `Sequence` або як варіанти об'єднання типів) вимкнено за вас: вони призначені для читання моделлю, тож автоматичне визначення не виводить із них схеми (`Image` та `Audio` описано на сторінці **[Зображення, аудіо та іконки](media.md)**). `structured_output=True` усе одно примусово створює схему для класів блоків вмісту.
## Клас без анотацій типів {#a-class-without-type-hints}
Є один спосіб опинитися без структурованого виводу, не просивши про це: повернути клас, у **тілі якого немає анотацій**.
@ -245,6 +250,6 @@ result.structured_content # {"London": 16.2, "Reykjavik": 4.4}
* Скаляри, списки, кортежі й об'єднання типів загортаються в `{"result": ...}`. Моделі, `TypedDict`, dataclass, анотовані класи й `dict[str, ...]` — уже об'єкти й лишаються як є.
* Кожен результат несе `content` (текст, для моделі) **і** `structured_content` (дані, для застосунку).
* Те, що ви повертаєте, перевіряється на відповідність схемі. Невідповідність — це помилка інструмента, а не зіпсований результат.
* `structured_output=False` вимикає це для інструмента. Клас без анотацій типів вимикає це мовчки; пильнуйте.
* `structured_output=False` вимикає це для інструмента. Блоки вмісту, `Image` та `Audio` вимкнено за замовчуванням; клас без анотацій типів вимикає це мовчки, тож пильнуйте.
Тепер ви володієте всім, що інструмент може сказати у відповідь. Далі — другий примітив: **[Ресурси](resources.md)**.

View file

@ -1,6 +1,6 @@
---
translation:
sections: [e4cc390d56573409, 8566e2b68594e9ad, 2c97b9f888398951, 048e5471dfa71aea, 3076b1e16ad95950, edbedf2a16e71311, 3d8ef8da89fa87c1, f6c0e02e6ea5a363]
sections: [e4cc390d56573409, f30cf8103a6e918c, 2c97b9f888398951, 048e5471dfa71aea, 3076b1e16ad95950, edbedf2a16e71311, 3d8ef8da89fa87c1, f6c0e02e6ea5a363]
tool: 1
---
# Інструменти {#tools}
@ -39,6 +39,8 @@ translation:
Обидва аргументи потрапили в `required`, бо жоден не має типового значення. За мить ви це виправите. (Ключі `title` — артефакти Pydantic; контракт складають властивості, їхні типи та `required`.)
Ключа `$schema` теж немає: схему без нього MCP трактує як **JSON Schema 2020-12** — саме її й генерує Pydantic, тож вибирати нічого, доки не візьметеся писати схеми вручну для **[низькорівневого Server](../advanced/low-level-server.md#the-dialect-is-json-schema-2020-12)**.
!!! tip
Анотації типів тут — не документація. Вони і є **контракт**. Якщо клієнт надішле `"limit": "ten"`,
SDK відхилить запит ще до того, як ваша функція запуститься.

View file

@ -1,6 +1,6 @@
---
translation:
sections: [4a7033e1ed8ad602, 55dcbfff0c6271bf, 101ef9d14bf4ec46, 4b6c4a845438abc7, f98b46bafbee4acd]
sections: [4a7033e1ed8ad602, 55dcbfff0c6271bf, 317f4256a650cab6, 4b6c4a845438abc7, f98b46bafbee4acd]
tool: 1
---
# URI-шаблони та безпека шляхів {#uri-templates-and-path-safety}
@ -170,7 +170,7 @@ SDK підтримує підмножину, відібрану для зіст
`safe_join`, щоб розв'язати шлях і впевнитися, що він лишається всередині
базового каталогу:
```python title="server.py" hl_lines="4 14"
```python title="server.py" hl_lines="5 15"
--8<-- "docs_src/uri_templates/tutorial002.py"
```
@ -211,9 +211,10 @@ SDK підтримує підмножину, відібрану для зіст
!!! tip
Якщо обробник не може виконати запит (файл не існує, ідентифікатор
невідомий), викиньте виняток. SDK перетворить його на відповідь з
помилкою. Про різницю між помилкою протоколу та помилкою інструмента —
на сторінці **[Обробка помилок](handling-errors.md)**.
невідомий), викиньте `ResourceNotFoundError`, як це робить `read_manual`
вище. Клієнт отримає `-32602` з вашим повідомленням і URI. Неочікуваний
виняток натомість стає загальною помилкою `-32603`. Див.
**[Обробка помилок](handling-errors.md#a-resource-that-doesnt-exist)**.
## Ресурси на низькорівневому Server {#resources-on-the-low-level-server}