Об'єкт Context
Машинний переклад
Цю сторінку перекладено автоматично з англомовної документації, і основною версією є англомовна сторінка. Якщо щось читається неправильно, на сторінці Переклади пояснено, як про це повідомити.
Аргументи інструмента надходять від моделі. Усе інше (запит, який ви обслуговуєте, сервер, у якому живе інструмент, спосіб звернутися назад до клієнта) надходить з одного об'єкта: Context.
Його не потрібно ні створювати, ні налаштовувати. Достатньо попросити.
Як його попросити
Додайте до будь-якого інструмента параметр з анотацією Context:
from mcp.server import MCPServer
from mcp.server.mcpserver import Context
mcp = MCPServer("Bookshop")
@mcp.tool()
def search_books(query: str, ctx: Context) -> str:
"""Search the catalog by title or author."""
return f"[request {ctx.request_id}] Found 3 books matching {query!r}."
- SDK створює новий
Contextдля кожного запиту й передає його у функцію. - Ім'я параметра не має значення.
ctx,context,c: SDK знаходить його за анотацією. - Ресурси та промпти теж можуть оголосити такий параметр, у той самий спосіб.
ctx.request_id— ідентифікатор запиту, який ваша функція обслуговує просто зараз.
Info
Якщо ви працювали з FastAPI, цей прийом вам знайомий: оголошуєте параметр із власним типом
фреймворку (Request там, Context тут), і фреймворк його підставляє. Нічого реєструвати,
нічого налаштовувати: анотація типу — це й увесь механізм.
Невидимий для моделі
Це те, що варто добре засвоїти. Ось схема вхідних даних, яку tools/list повідомляє для search_books:
{
"type": "object",
"properties": {
"query": {"title": "Query", "type": "string"}
},
"required": ["query"],
"title": "search_booksArguments"
}
Одна властивість. ctx — не аргумент: він ніколи не з'являється у схемі, моделі про нього ніколи не повідомляють, і жоден клієнт не може його заповнити. Це домовленість між вами та SDK, якої не видно в переданих даних.
Спробуйте самі
Запустіть сервер у MCP Inspector:
uv run mcp dev server.py
Форма для search_books має єдине поле query. Викличте інструмент зі значенням dune:
[request 3] Found 3 books matching 'dune'.
Число показує, яким за ліком виявився цей запит. Викличте інструмент ще раз — і воно зміниться: кожен запит отримує власний Context.
Що він дає
Впроваджений об'єкт невеликий. Окрім request_id:
await ctx.read_resource(uri): прочитати один із власних ресурсів сервера зсередини інструмента. Про це — наступний розділ.await ctx.report_progress(progress, total, message): передавати перебіг виконання тому, хто викликав, упродовж тривалого виклику. Докладніше — на сторінці Перебіг виконання.await ctx.elicit(message, schema)таawait ctx.elicit_url(...): призупинити інструмент і поставити користувачеві запитання. Це Еліцитація (elicitation).ctx.session: серверний бік розмови з цим клієнтом. Тут живуть сповіщення, які ви надсилаєте клієнтові; останній розділ ним користується.ctx.headers: заголовки запиту, які передав транспорт, абоNoneдля stdio. Прочитати власний заголовок можна так:(ctx.headers or {}).get("x-..."). Заголовки — це дані від клієнта: вони годяться для локалі чи прапорця функції, але ніколи — для ідентифікації особи.ctx.request_context: сирий запис про поточний запит. Поле, яке вам знадобиться, —lifespan_context, об'єкт, який ваш код запуску віддав через yield (див. Життєвий цикл (lifespan)).
Логування навмисно немає в цьому списку. Сервер пише логи модулем logging Python, як і будь-яка інша програма на Python. Логування — коротка сторінка про те, чому саме так.
Tip
Впровадження відбувається лише для функції, яку ви зареєстрували. Допоміжна функція, яку
викликає ваш інструмент, не отримує власного Context; передавайте ctx далі як звичайний
аргумент. Жодного фонового «поточного контексту», який можна було б дістати звідкись іще, немає.
Читання власних ресурсів
Ресурси сервера — не лише для клієнтів. Інструмент теж може їх читати:
from mcp.server import MCPServer
from mcp.server.mcpserver import Context
mcp = MCPServer("Bookshop")
@mcp.resource("catalog://genres")
def genres() -> str:
"""The genres the catalog is organised into."""
return "fiction, non-fiction, poetry"
@mcp.tool()
async def describe_catalog(ctx: Context) -> str:
"""Describe how the catalog is organised."""
[contents] = await ctx.read_resource("catalog://genres")
return f"The catalog is organised into: {contents.content}"
ctx.read_resource розв'язує URI через той самий реєстр, що обслуговує resources/read, тож інструмент отримує те саме, що отримав би клієнт: ітерований об'єкт із ReadResourceContents, по одному на кожен блок вмісту. Для цього URI він один:
contents.content # 'fiction, non-fiction, poetry'
contents.mime_type # 'text/plain'
content— це рівно те, що повернулаgenres(). Одне джерело істини: клієнт переглядає ресурс, ваші інструменти його споживають, ніхто не копіює рядок.- Єдиний параметр
describe_catalog— цеContext, тож його схема вхідних даних не має жодної властивості. Модель викликає його з{}.
Сповіщення клієнта про зміну списку
Те, що пропонує сервер, не зафіксовано на момент імпорту. Зареєструйте інструмент під час виконання, а потім повідомте клієнта:
from mcp.server import MCPServer
from mcp.server.mcpserver import Context
mcp = MCPServer("Bookshop")
def recommend_book(genre: str) -> str:
"""Recommend a book in the given genre."""
return f"In {genre}, try 'Dune'."
@mcp.tool()
async def enable_recommendations(ctx: Context) -> str:
"""Switch on the recommendation tool."""
mcp.add_tool(recommend_book)
await ctx.session.send_tool_list_changed()
return "Recommendations are now available."
mcp.add_tool(recommend_book)реєструє звичайну функцію як інструмент: ім'я, опис і схема виводяться точно так само, як це зробив би@mcp.tool().await ctx.session.send_tool_list_changed()надсилаєnotifications/tools/list_changed. Клієнт, що його отримав, знову викликаєtools/listі бачитьrecommend_book.
Споріднені методи — send_resource_list_changed(), send_prompt_list_changed() і send_resource_updated(uri) для зміни одного конкретного ресурсу.
На з'єднанні покоління 2026-07-28 клієнти отримують сповіщення про зміни лише в потоці subscriptions/listen, який вони самі відкрили, тож наведені вище методи send_* до цих потоків не доходять. Методи публікації Context доставляють сповіщення в усі підписані потоки одразу: await ctx.notify_tools_changed(), await ctx.notify_prompts_changed(), await ctx.notify_resources_changed() та await ctx.notify_resource_updated(uri). Докладніше, зокрема про масштабування на кілька реплік, — на сторінці Підписки.
Check
Поки ніхто не запустив enable_recommendations, обіцяного інструмента не існує. Викличте його
все одно — і результатом буде помилка, яку модель може прочитати:
Unknown tool: recommend_book
Запустіть enable_recommendations — і той самий виклик спрацює. Список інструментів справді
динамічний: tools/list відображає те, що зареєстровано саме зараз.
Підсумки
- Анотуйте параметр типом
Context(в інструменті, ресурсі чи промпті) — і SDK його впровадить. Ім'я обираєте ви. - Для моделі він невидимий: схема вхідних даних завжди містить лише ваші справжні аргументи.
ctx.request_idідентифікує запит;ctx.request_context.lifespan_context— те, що ваш код запуску віддав через yield.await ctx.read_resource(uri)дає інструменту змогу читати власні ресурси сервера.ctx.session— канал назад до клієнта:send_tool_list_changed()та споріднені методи кажуть йому заново отримати список, який ви змінили.- Звітування про перебіг виконання та еліцитація теж починаються з
Context; кожному присвячено окрему сторінку.
Параметри, яких модель ніколи не бачить і які заповнюють ваші власні функції, — це Залежності.