# Локальный MCP-сервер: создать, подключить и проверить вызов

Источник: https://modelium.tech/zhurnal/mcp-server-lokalno/

Для первого локального MCP-сервера достаточно Python SDK и одной функции без доступа к файлам: клиент запускает процесс через stdio, получает список инструментов и вызывает функцию. Проверьте вызов в MCP Inspector с новой тестовой меткой, а не по правдоподобному ответу модели. Если нужен Open WebUI или доступ по сети, понадобится отдельный Streamable HTTP endpoint и отдельная проверка периметра.

**Граница проверки: 28 сентября 2026 года.** Инструкция сверена с первоисточниками Python SDK v2 на Git commit `f1b6589088534632fef92238ee9750951e3c0185`, Inspector на `1e31c78fbf81a989e8eb47021c6281d7876ad7fd` и спецификацией 2026-07-28 на `ab3a39c13bd23be691c2760e1c6c5c15a64582e1`. Modelium не устанавливал этот SDK, не запускал сервер и не измерял работу модели; ожидаемые результаты ниже — критерии для **вашего** теста. [s1](#src-s1) [s4](#src-s4) [s5](#src-s5)

## Что делает локальный MCP-сервер?

MCP-сервер объявляет инструменты с именем, описанием и схемой аргументов; клиент может получить перечень через `tools/list`, затем отправить `tools/call` с конкретными аргументами. Это интерфейс к функции, а не гарантия, что языковая модель её вызовет. В SDK декоратор `@mcp.tool()` строит схему из типов функции, а её строка документации становится описанием инструмента. [s3](#src-s3) [s7](#src-s7)

Для **одного компьютера** проще начать со `stdio`: MCP-клиент сам запускает Python-файл дочерним процессом и обменивается сообщениями через stdin/stdout. Порт не открывается. В HTTP-варианте сервер слушает отдельный адрес; он нужен для клиентов вроде Open WebUI, которые подключаются к удалённому MCP endpoint. Не пытайтесь вводить `stdio`-команду как URL `/mcp`: это два разных транспорта. [s2](#src-s2) [s5](#src-s5) [s8](#src-s8) [s6](#src-s6)

Маршрут задачи: **безопасный тестовый инструмент → stdio-сервер → Inspector → зафиксированный ответ → при необходимости локальная модель и её host**. Если задача — корпоративные файлы или учётные данные, не заменяйте проверку безопасности безвредным тестом: реальному инструменту потребуются собственные права, ограничение действий и журнал. Спецификация рекомендует человеческое подтверждение для операций, но не заставляет каждый клиент его предоставлять. [s7](#src-s7)

## Что подготовить до запуска?

Документация SDK v2 указывает Python 3.10+ и установку `mcp[cli]`. Для Inspector потребуется установленный Node.js с `npx`; `mcp dev` запускает интерактивный Inspector, а CLI Inspector тоже использует `npx`. Сначала проверьте зависимости в отдельном пустом учебном каталоге и не запускайте непроверенный сервер там, где есть рабочие секреты. Ни одна команда ниже не загружает веса модели, но установка SDK и Inspector получает пакеты из внешних реестров. [s1](#src-s1) [s2](#src-s2) [s4](#src-s4)

mkdir mcp-local-smoke && cd mcp-local-smokeuv inituv add "mcp[cli]"

Эти команды описывают учебное окружение с `uv`, а не установленный нами проект. Сохраняйте нижеуказанный `server.py` именно в созданном каталоге. Для воспроизводимости в рабочем контуре отдельно фиксируйте версии зависимостей и источник пакетов. [s1](#src-s1) [s6](#src-s6)

## Как сделать сервер без доступа к данным?

В отличие от универсального файлового сервера этот пример **не имеет инструментов чтения или записи**: он возвращает переданную короткую метку. Его основа — официальный `MCPServer`, декоратор `@mcp.tool()` и запуск `mcp.run()` с транспортом по умолчанию `stdio`. Ограничение длины метки — наша проектная мера для теста, не свойство протокола. [s1](#src-s1) [s2](#src-s2) [s3](#src-s3)

from mcp.server import MCPServermcp = MCPServer("Local-Smoke")@mcp.tool()def echo_marker(marker: str) -> str:    """Return a short test marker; do not access files or the network."""    if not marker.isascii() or not marker.isalnum() or len(marker) > 24:        return "invalid_marker"    return f"tool_called:{marker}"if __name__ == "__main__":    mcp.run()

Пустой `marker` тоже не годится для осмысленного теста: используйте, например, `smoke28a`, затем **другую** метку `smoke28b`. Функция не читает файл, не обращается к API и не принимает команду на исполнение; проверка аргумента выполняется перед ответом. Этот учебный пример не даёт разрешения добавлять действия с письмами, документами, терминалом или 1С по аналогии без отдельной политики. [s3](#src-s3) [s7](#src-s7)

## Как убедиться, что сервер отвечает по протоколу?

Официальный SDK предлагает `uv run mcp dev server.py`: команда запускает Inspector и сообщает адрес тестового интерфейса. В его вкладке **Tools** должен появиться `echo_marker`; вызовите его с `marker=smoke28a` и сравните результат с `tool_called:smoke28a`. Затем вызовите с `marker=smoke28b` и убедитесь, что значение изменилось. Увидеть список недостаточно: нужен отдельный фактический результат `tools/call`. [s1](#src-s1) [s2](#src-s2) [s4](#src-s4) [s7](#src-s7)

uv run mcp dev server.py

Inspector CLI из официального репозитория допускает вызов `tools/list` и `tools/call` у локального stdio-процесса. Если нужен машинно читаемый журнал вместо формы, запустите команды из каталога проекта; `npx` загрузит Inspector, а абсолютные пути устраняют зависимость от его рабочего каталога. Выберите учебное окружение и проверьте, что **в ответе инструмента** есть метка; не трактуйте напечатанную моделью фразу как протокольный ответ. [s4](#src-s4) [s6](#src-s6)

npx @modelcontextprotocol/inspector --cli "$(pwd)/.venv/bin/python" "$(pwd)/server.py" --method tools/listnpx @modelcontextprotocol/inspector --cli "$(pwd)/.venv/bin/python" "$(pwd)/server.py" --method tools/call --tool-name echo_marker --tool-arg marker=smoke28a

Строки выше описывают Unix-подобную систему, где `uv` создал `.venv` в текущем каталоге; на Windows путь к Python другой. MCP Inspector — **клиент**, его прямой вызов тестирует протокол без языковой модели. Отдельно можно проверить функцию в памяти, но такой тест не доказывает, что конкретный host сумеет стартовать дочерний процесс или что выбранная модель корректно вызовет инструмент. [s4](#src-s4) [s6](#src-s6)

## Как подключить его к локальному клиенту с моделью?

После прямого теста в настройке MCP-клиента укажите **команду и абсолютный путь** к этому файлу. В официальной инструкции Python SDK один и тот же запуск `uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py` служит основой для Claude Desktop, Claude Code и IDE, но формат конфигурации у каждой программы свой. Для VS Code документация показывает `servers` с `type: stdio`, а для Cursor — `mcpServers`; не копируйте чужой JSON в неподходящий клиент. Хост может не наследовать ваш PATH и переменные окружения, поэтому проверяйте реальный исполняемый файл и не вписывайте секреты прямо в публичную конфигурацию. [s6](#src-s6)

**Критерий реального вызова модели**: после запроса о метке в трассе клиента присутствуют `tools/call`, имя `echo_marker`, отправленный аргумент и точный ответ инструмента; ответ модели согласуется с ним. Если виден только гладкий текст без вызова, сервер может работать исправно, а проблема быть в доступе инструмента, режиме клиента либо способности модели к tool calling. Для выбора модели, runtime и отдельной проверки переходите к [гайду по вызову инструментов](/zhurnal/tool-calling-lokalnyh-modeley/). [s3](#src-s3) [s7](#src-s7)

## Что делать, если команда не работает?

- **Терминал «завис» после **`**python server.py**`**.** Для `stdio` это ожидаемо: процесс ждёт протокольный запрос от клиента. Подключите Inspector, не проверяйте сервер HTTP-запросом к несуществующему порту. [s2](#src-s2) [s5](#src-s5)

- **Inspector не видит инструмент.** Сначала проверьте каталог и точный путь к `server.py`, затем версию установленного SDK, наличие `npx` и ошибки запуска в `stderr`; не печатайте служебный текст в `stdout` до начала протокольного обмена. [s1](#src-s1) [s2](#src-s2) [s5](#src-s5)

- **Список виден, вызов не проходит.** Проверьте имя `echo_marker`, аргумент `marker` и сообщение об ошибке в ответе инструмента; SDK валидирует типы аргументов по схеме. Испытайте допустимую и заведомо недопустимую метки. [s3](#src-s3) [s7](#src-s7)

- **Inspector вызывает, но модель не вызывает.** Разделите протокольный тест и тест модели: проверьте включён ли инструмент в клиенте, доступен ли контекст описания и сохранена ли трасса вызова. Само название инструмента в списке не подтверждает выполнение. [s6](#src-s6) [s7](#src-s7)

- **Open WebUI требует URL.** Нативное подключение WebUI использует Streamable HTTP, а не `stdio`; SDK показывает переход на `mcp.run(transport="streamable-http", port=3001)` и адрес `http://127.0.0.1:3001/mcp`. Но открывать endpoint в рабочей сети без контроля доступа нельзя: сначала проверьте адрес, авторизацию, контейнерную маршрутизацию и периметр в [отдельном гайде Open WebUI](/zhurnal/mcp-open-webui-lokalno/). [s2](#src-s2) [s5](#src-s5)

Чтобы убрать учебный сервер, удалите тестовую регистрацию из своего клиента и его каталог с виртуальным окружением **после** проверки, что там нет нужных вам файлов. Сама `stdio`-версия не создаёт фоновый сетевой сервис; прекращение дочернего процесса и удаление регистрации завершают этот опыт. [s2](#src-s2) [s5](#src-s5)

**Следующий шаг:** [проверить вызов инструмента выбранной локальной моделью](/zhurnal/tool-calling-lokalnyh-modeley/), сохранив трассу клиента и ответ `echo_marker`. Это звено «инструмент → runtime/модель → проверяемый результат»; факт наличия MCP-сервера не означает, что его уже использовала модель. [s3](#src-s3) [s7](#src-s7)

## Источники

1. [MCP Python SDK v2 — обзор, требования и установка](https://github.com/modelcontextprotocol/python-sdk/blob/f1b6589088534632fef92238ee9750951e3c0185/docs/index.md) — получено 2026-09-28
2. [MCP Python SDK v2 — Running your server](https://github.com/modelcontextprotocol/python-sdk/blob/f1b6589088534632fef92238ee9750951e3c0185/docs/run/index.md) — получено 2026-09-28
3. [MCP Python SDK v2 — Tools и схема аргументов](https://github.com/modelcontextprotocol/python-sdk/blob/f1b6589088534632fef92238ee9750951e3c0185/docs/servers/tools.md) — получено 2026-09-28
4. [MCP Inspector — CLI, tools/list и tools/call](https://github.com/modelcontextprotocol/inspector/blob/1e31c78fbf81a989e8eb47021c6281d7876ad7fd/clients/cli/README.md) — получено 2026-09-28
5. [MCP specification 2026-07-28 — stdio transport](https://github.com/modelcontextprotocol/specification/blob/ab3a39c13bd23be691c2760e1c6c5c15a64582e1/docs/specification/2026-07-28/basic/transports/stdio.mdx) — получено 2026-09-28
6. [MCP Python SDK v2 — Connect to a real host](https://github.com/modelcontextprotocol/python-sdk/blob/f1b6589088534632fef92238ee9750951e3c0185/docs/get-started/real-host.md) — получено 2026-09-28
7. [MCP specification 2026-07-28 — Tools and human confirmation](https://github.com/modelcontextprotocol/specification/blob/ab3a39c13bd23be691c2760e1c6c5c15a64582e1/docs/specification/2026-07-28/server/tools.mdx) — получено 2026-09-28
8. [Open WebUI — native MCP Streamable HTTP connections](https://github.com/open-webui/docs/blob/6602effdb92ce647f2abe6dbb61e136b62191d7a/docs/features/extensibility/mcp.mdx) — получено 2026-09-28
