Python SDK v1 · mcp==1.30.0 · протокол 2025-11-25. Для SDK v2 требуется отдельная миграция.
Перед началом
Нужна папка лаборатории из первого урока с .venv и SDK 1.30.0, а также полный lab_session.py из контракта. Сохраните следующие два новых файла рядом с ним. Конфигурацию редактора не меняйте: мы проверим новую версию через отдельный stdio-клиент.
1. Создайте сервер с двумя аргументами
Сохраните validation_server.py:
"""Add an optional length limit to the lab tool; keep its default at 80."""
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("label-validation")
@mcp.tool()
def normalize_label(text: str, max_length: int = 80) -> dict[str, str]:
"""Trim a label; use a length limit from 1 to 80 characters."""
if not 1 <= max_length <= 80:
raise ValueError("max_length must be between 1 and 80")
label = text.strip()
if not 1 <= len(label) <= max_length:
raise ValueError("Label must contain 1 to max_length characters after trimming")
return {"label": label}
if __name__ == "__main__":
mcp.run(transport="stdio")Проверки выполняются в определённом порядке. Сначала убеждаемся, что max_length находится в диапазоне 1–80. Затем удаляем крайние пробелы и проверяем длину подписи. Отрицательный предел не должен превращаться в странную ошибку текста, поэтому у него отдельное сообщение.
Тип int и значение по умолчанию попадут в inputSchema. Диапазон 1–80 в этом примере контролирует функция. В схеме не объявлены minimum или maximum; не обещайте клиенту ограничения, которых он не получил. Если вам нужна схема с диапазоном, это отдельное изменение аннотаций и тестов, а не замена сообщения об ошибке.
2. Создайте полный проверочный клиент
Сохраните check_validation.py:
"""Check both the SDK input schema and the lab's additional length rule."""
import asyncio
import json
from lab_session import lab_session
async def main():
async with lab_session("validation_server.py") as (session, _):
tool = (await session.list_tools()).tools[0]
schema = tool.inputSchema
assert schema["properties"]["max_length"]["type"] == "integer"
assert schema["properties"]["max_length"]["default"] == 80
assert "max_length" not in schema.get("required", [])
cases = [("default_80", {"text": "x" * 80}, False), ("five", {"text": " Draft ", "max_length": 5}, False), ("blank", {"text": " "}, True), ("over_limit", {"text": "Draft!", "max_length": 5}, True), ("bad_limit", {"text": "Draft", "max_length": 0}, True), ("missing_text", {}, True)]
results = {}
for name, arguments, expected_error in cases:
answer = await session.call_tool("normalize_label", arguments)
assert answer.isError is expected_error, name
if name == "five":
assert answer.structuredContent == {"label": "Draft"}
if name == "default_80":
assert answer.structuredContent == {"label": "x" * 80}
results[name] = answer.model_dump(mode="json", exclude_none=True)
print("PASS: schema, default limit, two successful calls, four errors")
print(json.dumps({"input_schema": schema, "cases": results}, ensure_ascii=False, indent=2))
if __name__ == "__main__":
asyncio.run(main())Проверка обращается к validation_server.py, не к исходному label_server.py. Она сначала утверждает опубликованную схему, затем проверяет два успеха: строку длиной 80 с default и Draft с пределом 5. После этого каждый отказ должен получить isError: true.
3. Запустите тест
.\.venv\Scripts\python.exe check_validation.pyОжидаемая первая строка:
PASS: schema, default limit, two successful calls, four errorsНиже будет схема с max_length.type: "integer", max_length.default: 80; обязательным остаётся text. У короткого успешного вызова structuredContent.label равно Draft.
| Случай | Аргументы | Ожидаемый отказ |
|---|---|---|
| blank | text из пробелов | Label must contain 1 to max_length characters after trimming |
| over_limit | Draft!, max_length 5 | Label must contain 1 to max_length characters after trimming |
| bad_limit | Draft, max_length 0 | max_length must be between 1 and 80 |
| missing_text | пустые arguments {} | Ошибка схемы: Field required |
Не привязывайте приложение ко всему тексту диагностического сообщения SDK: его формат может измениться. Для этого упражнения флаг isError, успешные данные и схема являются проверяемыми условиями. Полный JSON помогает понять причину отказа.
Если не получается
ModuleNotFoundError: lab_session— сохраните общий файл из второго урока в эту же папку.- В схеме нет
max_length— клиент запустил старый сервер. Сверьте имя вlab_session("validation_server.py")и содержимое нового файла. - Ошибки проверки входа возникают до тела функции: отсутствие text относится к SDK, а пустая строка — к вашему правилу.
- Если хотите увидеть новую схему в редакторе, нужна отдельная запись для нового сервера с его путём и перезапуском. Этот урок такой записи не создаёт и не заменяет рабочую .mcp.json.
Проверьте себя
В копии проверочного клиента добавьте успешную подпись из одного символа с max_length: 1 и отказ из двух символов при том же пределе. Сначала решите, какой ответ является правильным, затем внесите assert. Не меняйте ожидаемый ответ после падения, пока не выясните, нарушен тест или контракт.
Версия и источники
Упражнение закреплено за Python 3.11 и mcp==1.30.0, SDK v1, протоколом 2025-11-25. SDK v2 требует отдельной миграции. Примеры используют синтетические подписи, без внешнего API и модели. Документация сверена 8 октября 2026 года.
На локальном stdio проверены опубликованная схема, два успеха и четыре отказа. Новая установка и UI редактора не выполнялись.
Источники: FastMCP server v1 (в новой вкладке), клиент SDK v1 (в новой вкладке), tools и ошибки (в новой вкладке), Python str.strip (в новой вкладке).
Вопросы по материалу
Увидит ли клиент диапазон max_length от 1 до 80 в JSON Schema?
В этой версии примера он увидит целый тип и значение по умолчанию 80. Диапазон проверяет функция; minimum и maximum в схеме не объявлены. Чтобы передать диапазон клиенту, потребуется отдельное изменение аннотаций и тестов.
Чем отсутствие text отличается от строки из пробелов?
Без text вызов нарушает входную схему. Строка из пробелов проходит проверку типа, но после strip становится пустой и отклоняется правилом функции. В проверочном клиенте предусмотрены оба случая.
Продукты ATOMNO
Другие задачи для AI-помощника
Это отдельные продукты ATOMNO для задач с данными. Они не входят в учебные примеры.
Узнать курс и ставку ЦБ
Помощник получает курсы валют и ключевую ставку.
Курсы и ставка Банка России
Опубликованный клиент; свежесть конкретного ответа сверяйте с источником.
Проверить организацию
ИНН или ОГРН → ограниченная проверка организации.
Проверка контрагента
Состав проверки и доступ уточняйте в документации.
Найти госзакупку
Поиск извещения → чтение карточки закупки.
Поиск госзакупок
Полнота архива и доставка уведомлений не обещаются.
Открыть карточку товарного знака
Номер свидетельства → карточка российского знака.
Карточка товарного знака
Поиск по названию и оценка сходства не входят.