В AI-приложении нужно находить заказы во внутренней системе, читать файлы проекта и создавать задачи в GitHub. Для каждой операции уже может существовать API, но приложению ещё предстоит объяснить модели, какие действия доступны, как передавать аргументы и кому разрешено их выполнять.
Без общего соглашения разработчик пишет интеграцию для каждого источника: HTTP-клиент или доступ к базе, преобразование ответа, описание функций для модели и обработку ошибок. Если те же операции понадобятся другому AI-приложению, придётся переносить этот код, поддерживать общую библиотеку или создавать собственный сервис-посредник.
Model Context Protocol (MCP) определяет общий интерфейс между AI-приложением и сервисом, который предоставляет инструменты или данные. Через него клиент может узнать о доступных операциях, получить схемы их аргументов, вызвать нужную операцию и прочитать результат. Сервер при этом сам решает, как обратиться к GitHub, базе или локальному файлу.
Например, сервер заказов предоставляет get_order(order_id). Одно приложение использует этот инструмент для ответа покупателю, другое — для внутренней диагностики. Оба узнают его имя и входную схему через MCP. Реализация поиска заказа остаётся общей, но каждому приложению по-прежнему нужны собственные правила доступа и обработки ответа.
MCP стандартизирует протокольный обмен; он не предоставляет бизнес-логику, права доступа к заказам или универсальную защиту от небезопасных действий. Далее проследим один вызов от приложения до данных, посмотрим на формат сообщений и реализуем тот же сценарий на Python.
Разбор относится к спецификации MCP от 28 июля 2026 года. В ней существенно изменился начальный обмен сообщениями; отличия от редакций 2025 года обозначим отдельно.
Компоненты: Host, Client и Server
Рассмотрим путь запроса «найдите заказ ORD-101».
- MCP Host — приложение, в котором работает пользователь: например, редактор кода или AI-чат. Host управляет подключениями, взаимодействием с моделью, набором доступных инструментов и пользовательскими разрешениями.
- MCP Client — компонент host, реализующий протокол. Для каждого MCP-сервера host создаёт отдельный клиент. Клиент отправляет запросы и получает ответы; один клиент связан с одним сервером, а host может работать сразу с несколькими серверами.
- MCP Server — локальная программа или удалённый сервис. Он объявляет возможности, принимает запросы и выполняет конкретную логику: в нашем примере ищет заказ и вычисляет сумму.
- Источник данных —
orders.json, база данных или внешний HTTP API. MCP-сервер обращается к нему обычным способом; источник не обязан поддерживать MCP.
Граница протокола проходит между Client и Server. Стрелка Host → Client на схеме обозначает внутреннее управление приложением, а Server → orders.json — работу с данными. Это помогает понять, где искать ошибку: неправильный выбор инструмента происходит в host, несовместимые протокольные сообщения — на границе client/server, неверная сумма — в логике сервера.
Подключение организует клиент под управлением host. В локальном сценарии клиент запускает процесс сервера и обменивается сообщениями через stdin/stdout; в сетевом — обращается к MCP endpoint по HTTP. Сервер предоставляет описания своих возможностей, клиент запрашивает их через протокольные методы. Наличие инструмента в списке ещё не означает, что пользователю следует разрешить его вызов.
Host контролирует и объём передаваемого контекста: к серверу уходит конкретный запрос с аргументами, а не автоматически вся история разговора и данные других серверов. Сам сервер, конечно, имеет доступ к тем ресурсам и учётным данным, которые ему предоставлены. Поэтому изоляция зависит не только от протокола, но и от конфигурации приложения и прав процесса.
Эти отношения закреплены в официальной архитектуре MCP.
Что предоставляет сервер: Tools, Resources, Prompts
Сервер объявляет поддерживаемые возможности (capabilities). Для нашего примера достаточно tools, но MCP также описывает resources и prompts. Их удобнее различать по действию клиента:
| Возможность | Что получает клиент | Пример в системе заказов | Методы |
|---|---|---|---|
| Tool | Выполняемую операцию с аргументами | Посчитать сумму ORD-101 | tools/list, tools/call |
| Resource | Содержимое, доступное по URI | Справку о статусах orders://status-guide | resources/list, resources/read |
| Prompt | Готовый шаблон сообщений, возможно с параметрами | Шаблон разбора спорного заказа | prompts/list, prompts/get |
Tool подходит, когда требуется действие или вычисление. Сервер публикует имя, описание и inputSchema — JSON Schema аргументов. Например, клиент узнаёт, что get_order принимает обязательную строку order_id. Вызов передаёт значение ORD-101; поиск выполняется уже в коде сервера. Инструмент может менять данные, поэтому права и подтверждения зависят от характера операции.
Resource предоставляет данные, которые приложение может прочитать и добавить в контекст модели: справку, документ, содержимое файла. URI адресует материал, а resources/read получает его. Для адресов с параметрами спецификация предусматривает шаблоны ресурсов. В отличие от вызова calculate_order_total, чтение справки не просит сервер произвести этот расчёт.
Prompt описывает повторяемый сценарий общения: например, начальные сообщения для анализа расхождений в заказе. prompts/get возвращает шаблон с подставленными параметрами, после чего host может передать сообщения модели. Само получение prompt не запускает модель.
Представьте последовательность работы пользователя: сначала приложение читает resource со значениями статусов, затем вызывает tool для получения заказа, а для объяснения расхождения выбирает prompt. Это три разных интерфейса одного сервера — если сервер действительно их реализует. Наш Python-пример ниже реализует только два tools; показанные resource и prompt служат иллюстрацией возможностей спецификации, а не обещанием функций демонстрационного сервера.
Подробные требования: tools, resources и prompts.
Как клиент обнаруживает и вызывает инструмент
MCP передаёт сообщения в формате JSON-RPC 2.0. В запросе есть jsonrpc: "2.0", уникальный для незавершённых запросов id и метод method. Ответ возвращает тот же id и поле result либо error. Это обмен между MCP-клиентом и сервером; обращение пользователя к AI-модели происходит вне этой границы.
Проследим запрос стоимости заказа.
- Версия и возможности. В редакции
2026-07-28сервер обязан поддерживать методserver/discover, а клиент может вызвать его заранее, чтобы узнать поддерживаемые версии и capabilities. Если клиент сразу послал другой метод с неподдерживаемой версией, сервер обязан вернутьUnsupportedProtocolVersionError(-32022) со списком поддерживаемых версий. Это другой этап, чем получение списка инструментов. - Обнаружение tools. Клиент вызывает
tools/listу сервера, объявившего capabilitytools. Он получает имена, описания иinputSchema— схемы аргументов. Например, дляget_orderсхема требует строкуorder_id. Каталог может иметь несколько страниц и меняться в зависимости от авторизации запроса. - Выбор и разрешение. Host соотносит пользовательскую задачу с описанием инструмента. Если выбор предлагает модель, host всё равно отвечает за проверку разрешений и подтверждение чувствительных действий.
- Вызов. Клиент отправляет
tools/callсname: "get_order"иarguments: {"order_id": "ORD-101"}. Сервер проверяет аргументы, обращается к источнику данных и формирует результат. - Ответ. Сервер возвращает данные в
contentи, если доступен структурированный результат, вstructuredContent. ПолеisErrorсообщает об ошибке выполнения инструмента. Host решает, что из результата передать модели или показать пользователю.
Так может выглядеть иллюстративный JSON-RPC-запрос по редакции 2026-07-28 в теле сообщения:
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "get_order",
"arguments": {"order_id": "ORD-101"},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}
Здесь показаны обязательные поля _meta: версия протокола и возможности клиента. Его идентификатор io.modelcontextprotocol/clientInfo имеет уровень SHOULD — его рекомендуется передавать, но отсутствие не делает запрос недопустимым. В Streamable HTTP потребуются ещё обязательные HTTP-заголовки, в том числе MCP-Protocol-Version, совпадающий с версией в теле. Сообщение выше — пример формы запроса, а не сохранённый дамп выполнения Python SDK.
Результат в современной редакции использует resultType: complete означает завершение, input_required — необходимость получить дополнительные сведения и повторить запрос по правилам multi round-trip requests. Для нашего read-only инструмента предполагается обычное завершение complete; сценарий дополнительного ввода он не реализует. В прежних редакциях поля resultType не было; совместимый клиент учитывает это при разборе ответов.
Что означает initialize в старых примерах
В версиях до 2025-11-25 включительно клиент начинал работу с initialize, получал согласованную версию и возможности, а затем отправлял notifications/initialized. В редакции 2026-07-28 обязательной инициализации и протокольной сессии больше нет: каждый запрос несёт необходимые метаданные. При поддержке обоих поколений SDK способен переключаться между этими режимами.
У официального Python SDK v2 высокоуровневый Client по умолчанию работает с mode="auto": сначала пробует server/discover, а при подключении к старому серверу переходит к initialize. Поэтому код из прежних примеров с ClientSession.initialize() нельзя автоматически переносить в новый высокоуровневый Client и считать обязательным шагом протокола.
Две категории ошибок
Протокольная ошибка JSON-RPC означает, что запрос не удалось корректно обработать на уровне протокола: например, неизвестно имя инструмента или неверна форма сообщения. Ответ содержит error с кодом и сообщением.
Ошибка выполнения инструмента означает, что операция не дала нужного результата: заказ не найден, внешний API отказал, нарушено бизнес-правило или обработчик отклонил аргументы. Тогда сервер может вернуть результат с isError: true, чтобы host мог объяснить причину и при необходимости предложить корректный повтор.
Здесь есть отличие спецификации от реализации: спецификация относит неизвестное имя tool к протокольным ошибкам, а высокоуровневый MCPServer официального Python SDK v2 обрабатывает его через ToolError и может вернуть клиенту обычный результат с is_error=True. Это описано в документации об ошибках Python SDK. Поэтому в тестах ориентируйтесь на фактический контракт используемой библиотеки; не считайте каждый is_error JSON-RPC-ошибкой.
Описание полей, resultType и ошибок дано в базовом протоколе и разделе Tools.
stdio и Streamable HTTP
MCP определяет сообщения независимо от канала доставки. Клиент может отправить одинаковый по смыслу tools/call локальному процессу или удалённому сервису; различаются запуск, обрамление сообщений и средства защиты.
stdio используется в нашем примере. Host запускает сервер дочерним процессом; клиент пишет JSON-RPC-сообщения в stdin и читает ответы из stdout. Каждое сообщение — одна строка UTF-8. Отладочные сообщения сервер пишет в stderr: произвольный print() в stdout нарушит протокольный поток. Открывать HTTP-порт не нужно, но сервер получает права запущенного процесса и доступ к предоставленным файлам.
Streamable HTTP используется для обращения к HTTP-службе. Клиент отправляет каждое MCP-сообщение отдельным POST на единый endpoint, например /mcp. Для запроса сервер возвращает либо JSON-ответ, либо SSE-поток, связанный именно с этим запросом. Клиент должен поддерживать обе формы ответа. Запрос требует Accept с application/json и text/event-stream, MCP-Protocol-Version и Mcp-Method. Для tools/call нужен также Mcp-Name. Версия и значения заголовков метода и имени должны совпадать с соответствующими полями в теле.
В редакции 2026-07-28 удалены прежние протокольные сессии с Mcp-Session-Id и отдельный GET-поток. Если клиенту нужны уведомления об изменениях, он может открыть subscriptions/listen; это отдельный долгоживущий запрос с потоком ответа. SSE остаётся способом передачи событий внутри Streamable HTTP, но не самостоятельным основным транспортом. Старый HTTP+SSE — транспорт прежних редакций для совместимости.
| Вопрос | stdio | Streamable HTTP |
|---|---|---|
| Где работает сервер | Обычно локально как дочерний процесс | Локально или на удалённом HTTP-узле |
| Как доставляется сообщение | Строка JSON-RPC по stdin/stdout | Отдельный POST, JSON-ответ или SSE-поток |
| Что защищать | Права процесса, файлы, запуск команд | HTTP endpoint, авторизацию, сетевой доступ и TLS |
Что означает tools/call | Вызов инструмента | Тот же вызов инструмента |
При реализации Streamable HTTP сервер MUST проверять Origin, если заголовок присутствует; недопустимый Origin требует ответа 403. Для локального сервера спецификация SHOULD рекомендует привязку к 127.0.0.1. Аутентификацию, полномочия на операции и защиту данных нужно проектировать отдельно — наличие HTTPS не означает, что пользователь имеет право на конкретный tool.
Подробнее: транспорты, stdio и Streamable HTTP.
Практика: два инструмента для локальных заказов
Теперь реализуем цепочку со схемы: Python-клиент создаёт MCP-соединение, узнаёт имена tools, затем читает заказ и вычисляет его сумму. Сервер берёт данные из orders.json. Для запуска нужен Python 3.11+ и официальный SDK mcp==2.3.0; модель, внешний API и секреты не используются.
Ниже четыре файла. Сохраните их в одной папке или возьмите готовыми из репозитория с примером. Там же находится test_orders.py для проверки успешных и ошибочных вызовов. Пример позволяет проверить описанную логику независимо от AI-приложения. Версию пакета и API сверяйте с документацией Python SDK и клиентским API.
Зависимости, requirements.txt:
mcp==2.3.0
pydantic==2.13.5
Данные, orders.json:
[
{"id":"ORD-101","items":[
{"sku":"KB-01","quantity":2,"unit_price":120},
{"sku":"MS-02","quantity":1,"unit_price":140}
]},
{"id":"ORD-102","items":[
{"sku":"MON-03","quantity":1,"unit_price":900}
]}
]
У заказа ORD-101 две позиции: 2 × 120 + 1 × 140 = 380. Это целочисленные условные единицы; здесь нет налогов, скидок, округления или платёжных операций.
MCP-сервер, server.py:
"""Local read-only orders MCP server (mcp==2.3.0)."""
import json
from pathlib import Path
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
from pydantic import BaseModel, Field
DATA = Path(__file__).with_name("orders.json")
mcp = MCPServer("LocalOrders")
class LineItem(BaseModel):
sku: str
quantity: int = Field(gt=0)
unit_price: int = Field(ge=0)
class Order(BaseModel):
id: str
items: list[LineItem]
class Total(BaseModel):
order_id: str
total: int
def find_order(order_id: str) -> Order:
"""Only look up records in the fixed demonstration catalog."""
if not order_id.startswith("ORD-") or len(order_id) > 32:
raise ToolError("Invalid order ID")
orders = json.loads(DATA.read_text(encoding="utf-8"))
for record in orders:
if record["id"] == order_id:
return Order.model_validate(record)
raise ToolError("Order not found")
@mcp.tool()
def get_order(order_id: str) -> Order:
"""Return an order from the local catalog."""
return find_order(order_id)
@mcp.tool()
def calculate_order_total(order_id: str) -> Total:
"""Calculate the total of order line items."""
order = find_order(order_id)
return Total(
order_id=order.id,
total=sum(item.quantity * item.unit_price for item in order.items),
)
if __name__ == "__main__":
mcp.run()
Декораторы @mcp.tool() делают две Python-функции доступными как MCP-инструменты. Из аргумента order_id: str SDK формирует входную схему, а модели Pydantic Order и Total описывают результаты. Функция find_order отвечает за бизнес-логику: читает фиксированный JSON, проверяет формат ID и возвращает запись. Ошибка ToolError сообщает, почему операция не выполнена. Это поведение конкретного SDK и нашего обработчика; сама спецификация не предписывает названия Python-классов.
mcp.run() запускает stdio-сервер. Его не нужно запускать в другом терминале: следующий скрипт создаёт процесс автоматически.
MCP-клиент, client.py:
"""List and call both MCP tools using a local stdio process."""
import asyncio
import sys
from pathlib import Path
from mcp import Client, StdioServerParameters
SERVER = Path(__file__).with_name("server.py")
async def run() -> None:
parameters = StdioServerParameters(command=sys.executable, args=[str(SERVER)])
async with Client(parameters) as client:
response = await client.list_tools()
names = {tool.name for tool in response.tools}
assert names == {"get_order", "calculate_order_total"}, names
print("tools:", ", ".join(sorted(names)))
order = await client.call_tool("get_order", {"order_id": "ORD-101"})
assert not order.is_error, order.content
assert order.structured_content is not None
assert order.structured_content["id"] == "ORD-101"
assert len(order.structured_content["items"]) == 2
print("order: ORD-101, items: 2")
total = await client.call_tool(
"calculate_order_total", {"order_id": "ORD-101"}
)
assert not total.is_error, total.content
assert total.structured_content is not None
assert total.structured_content["total"] == 380
print("total: 380")
if __name__ == "__main__":
asyncio.run(run())
Клиент использует StdioServerParameters для запуска server.py, затем вызывает list_tools() и call_tool(). Здесь инструменты выбирает обычный Python-код, а не модель. Высокоуровневый Client в стандартном режиме auto согласует поддерживаемую редакцию протокола; для нашего современного сервера это 2026-07-28. structured_content — атрибут ответа Python SDK; на уровне JSON-RPC соответствующее поле называется structuredContent.
Запуск в каталоге с этими файлами:
python -m venv .venv
# Linux/macOS
source .venv/bin/activate
python -m pip install -r requirements.txt
python client.py
В Windows PowerShell для активации используйте .\\.venv\\Scripts\\Activate.ps1, в cmd — .venv\\Scripts\\activate.bat. Команды установки и запуска после активации те же.
Проверьте, что клиент обнаружил именно get_order и calculate_order_total, получил заказ ORD-101 с двумя позициями и проверил сумму 380. Проверки assert останавливают скрипт при расхождении. Это ожидаемое поведение по коду, а не приписанный материалу результат тестового запуска.
Чтобы увидеть прикладную ошибку, замените в клиентском вызове get_order идентификатор ORD-101 на ORD-999 и снова запустите скрипт. Сервер не найдёт запись, вернёт результат с is_error, а клиент остановится на assert not order.is_error. После эксперимента верните исходный ID. В проекте предусмотрен отдельный test_orders.py, который также проверяет оба заказа и отрицательные сценарии.
Если клиент не стартует, проверьте версию Python и установку пакетов в активном окружении. Если список tools отличается от ожидаемого — проверьте наличие обоих декораторов и путь к серверу. Для stdio особенно важно не печатать произвольный текст в stdout сервера.
В демонстрации нет разграничения доступа к реальным заказам. Она показывает, за что отвечает протокол и за что — код сервера, не более.
MCP, обычный API и LLM tool calling
Эти механизмы работают на разных границах. Путаница возникает, когда одно слово «инструмент» используют и для функции, которую видит модель, и для удалённого сервиса, который эту функцию выполняет.
| Механизм | Между кем действует контракт | Что он описывает |
|---|---|---|
| HTTP API | Клиент приложения ↔ конкретный backend | Маршруты, методы, авторизацию и предметный формат данных |
| Tool calling LLM-провайдера | Приложение ↔ модель | Как предоставить модели описание функции и получить предложенные имя и аргументы |
| MCP | MCP Client ↔ MCP Server | Как обнаружить инструменты и данные, передать аргументы, получить результат и согласовать протокольные возможности |
Представьте заказ ORD-101. Обычный backend может возвращать его по GET /orders/ORD-101. В приложении с tool calling разработчик описывает модели функцию get_order(order_id), а затем сам обрабатывает предложенный вызов. Если подключить MCP, эта функция обнаруживается на MCP-сервере: приложение получает её описание через tools/list, вызывает tools/call, а сервер уже обращается к исходному API. API остаётся на месте — появляется стандартизованный способ подключить его к поддерживающим MCP приложениям.
Модель предлагает get_order("ORD-101")
↓ решение и разрешение в Host
MCP Client → tools/call → MCP Server → HTTP API / SQL / JSON
← результат вызова ← данные заказа
В демонстрационном Python-клиенте модели вообще нет: вызовы записаны в коде. Это подтверждает разделение функций. Tool calling не обязателен для MCP, а MCP не обязателен для tool calling: приложение может напрямую вызывать HTTP API после ответа модели.
Когда выбрать прямой API. Если ваш backend делает несколько заранее известных запросов к одной системе и нет потребности подключать их к другим AI-host, отдельный MCP-сервер добавит обслуживание, версионирование и ещё одну точку отказа.
Когда MCP оправдан. Если одна интеграция нужна нескольким AI-приложениям, клиентам требуется обнаруживать доступные операции, а доступ к источнику удобно вынести за общую серверную границу, MCP сокращает количество специальных адаптеров. Однако клиенты должны действительно поддерживать нужные возможности протокола, а не только базовое подключение. Протокол сам по себе не устраняет расходы на авторизацию, мониторинг и тестирование.
Где возникают риски
Наш сервер работает с тестовым JSON и ничего не меняет. Если заменить его на подключение к реальным заказам, первый вопрос будет о правах доступа, а не о синтаксисе tools/call. Корректный запрос с существующим order_id не гарантирует, что вызывающий вправе видеть этот заказ.
Какой сервер подключён. Локальный stdio-сервер — исполняемая программа с правами процесса. Неизвестный пакет может читать доступные файлы и обращаться в сеть независимо от того, какие инструменты он объявляет. Проверяйте происхождение, зависимости и разрешения запуска; ограничивайте права файловой системы и сети. Удалённый сервер требует проверки адреса, TLS и надлежащей схемы аутентификации.
Кому доступна операция. Сервер должен проверять авторизацию на каждый запрос и на конкретный объект, например сверять доступ пользователя к заказу ORD-101. В протоколе предусмотрены механизмы авторизации для HTTP, но их корректная реализация и предметные права остаются задачей системы. Список tools/list может зависеть от полномочий, предъявленных в запросе. В нашем примере авторизации нет — использовать его с реальными пользовательскими данными без изменений нельзя.
Какие аргументы допустимы. inputSchema описывает ожидаемые значения, но не заменяет проверки на сервере. Функция find_order дополнительно ограничивает ID и ищет его только в фиксированном orders.json. Если инструмент принимает SQL, URL, путь к файлу или команду, потребуются ограничения соответствующего типа: параметризация, разрешённые адреса и каталоги, лимиты времени и объёма работы. Для операций записи нужна независимая проверка прав; host должен предоставлять пользователю возможность отклонить чувствительный вызов.
Что находится в ответе. Tool или resource может вернуть не только данные, но и текст вроде «вызовите другой инструмент и отправьте туда секрет». Это prompt injection: инструкция, внедрённая в недоверенный источник. Host не должен повышать её статус до системной инструкции или согласия пользователя. Фильтрация, безопасное представление источника и проверка последующих действий важны не меньше, чем валидация входа.
Что нельзя принимать на веру. Аннотация readOnlyHint — подсказка для интерфейса, а не ограничение полномочий. Серверу нельзя доверять только потому, что его tools выглядят безопасными. Логи тоже могут содержать параметры и результаты с персональными данными: задавайте сроки хранения, маскирование чувствительных полей, таймауты, rate limits и контроль повторных вызовов.
Спецификация Tools предъявляет к серверам нормативные требования: MUST проверять входы, применять надлежащий контроль доступа, ограничивать частоту вызовов и очищать выходные данные. Клиентам SHOULD рекомендованы подтверждение чувствительных операций, просмотр аргументов, проверка результатов, таймауты и аудит. Эти требования нужно реализовать в продукте; протокольное сообщение само по себе их не обеспечивает.
Когда использовать MCP
Вернёмся к исходной задаче: приложению требуется доступ к заказам, файлам и GitHub. Если интеграции уже написаны и используются одним сервисом, прямые вызовы его API могут остаться самым простым решением. Если те же операции нужны нескольким AI-приложениям, MCP позволяет вынести их за общий интерфейс обнаружения и вызова.
Разработчик MCP-сервера реализует предметные операции и контролирует доступ к данным. Клиент отправляет протокольные запросы. Host решает, какие результаты добавить в контекст и какие действия разрешить. В статье эти роли прослеживаются от tools/list до расчёта суммы заказа на Python.
Перед тем как внедрять MCP в продукт, проверьте три вещи: поддерживают ли ваши клиенты нужную редакцию и возможности протокола; как сервер получает полномочия к источникам; не станет ли поддержка отдельного сервера сложнее существующей прямой интеграции. Успешный вызов инструмента подтверждает прохождение протокольного обмена, но корректность расчёта и право на доступ проверяются отдельно.
Источники
- Актуальная спецификация и ограничения безопасности
- JSON-RPC, resultType и обработка ошибок
- Поведение Client и режимы совместимости
- Границы host, client, server и capabilities
- Контракт tools/list, tools/call и схемы
- 2026-07-28 и старый initialize
- Стандартные транспорты
- Локальный stdio
- Streamable HTTP
- Resources
- Prompts
- Python SDK v2
- Ошибки tool и протокола в официальном Python SDK
- Client SDK
- Версия mcp==2.3.0
- Готовые файлы практического примера и проверки вызовов