
Как сделать свой MCP-сервер: пример, проверка и подключение к агенту
Пишем сервер с одним инструментом на Python и на TypeScript, проверяем его в MCP Inspector и подключаем к Claude Code и Cursor. В конце — локальный stdio против HTTP и свой сервер для 1С.
Что понадобится
MCP-сервер — программа, которая отдаёт модели три вида вещей: инструменты, ресурсы и промпты. Инструмент вызывает сама модель, ресурс подкладывает в контекст приложение, промпт выбирает пользователь. С моделью сервер напрямую не говорит: его запускает клиент внутри приложения вроде Claude Code или Cursor.
Для сервера на Python нужен Python 3.11 или новее и пакет mcp. Дополнение cli ставит команду mcp с подкомандами mcp dev, mcp run и mcp install, на них держится запуск и проверка ниже.
Для сервера на TypeScript нужен Node.js 20 или новее и пакет @modelcontextprotocol/server. SDK собран только в ES-модулях, поэтому в package.json нужен type=module; tsx запускает TypeScript без сборки. Для MCP Inspector нужен свежий Node.js: 22.23.4, 24.22.1 или 26.12.1 и новее на своей ветке.
# Python 3.11 или новее
uv add "mcp[cli]" # или: pip install "mcp[cli]"
# Node.js 20 или новее
mkdir greeting && cd greeting
npm init -y
npm pkg set type=module
npm install @modelcontextprotocol/server zod tsx
mkdir srcМинимальный сервер на Python
Сохраните код в server.py. Декоратор @mcp.tool() делает функцию add инструментом. Имя инструмента SDK берёт из имени функции, описание — из докстринга, схему аргументов — из подсказок типов: a: int, b: int и есть JSON Schema, писать её отдельно не нужно.
mcp.run() без аргументов запускает сервер на stdio: он читает сообщения протокола из stdin и пишет ответы в stdout. Вызов стоит под if __name__ == "__main__":, потому что mcp dev, mcp run и mcp install импортируют файл, и без этой проверки сервер стартовал бы при любом импорте.
Во второй версии SDK класс называется MCPServer и импортируется из mcp.server. В версиях 1.x тот же класс назывался FastMCP и жил в mcp.server.fastmcp, поэтому в старых примерах вы встретите from mcp.server.fastmcp import FastMCP.
from mcp.server import MCPServer
mcp = MCPServer("Demo")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
if __name__ == "__main__":
mcp.run()Тот же сервер на TypeScript
Сохраните код в src/index.ts. registerTool принимает имя, настройки и асинхронный обработчик. Схема входа задаётся через Zod, из неё SDK строит JSON Schema для модели, проверяет аргументы до вызова обработчика и выводит их типы.
Обработчик возвращает content — список блоков, здесь один текстовый. Если вернуть isError: true, модель увидит ошибку и сможет на неё отреагировать.
Пример написан под вторую версию SDK: пакеты @modelcontextprotocol/server и @modelcontextprotocol/client. Первая версия выходит пакетом @modelcontextprotocol/sdk, живёт в ветке v1.x и получает исправления ещё минимум полгода после выхода v2 27 июля 2026 года.
import { McpServer } from '@modelcontextprotocol/server';
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';
const server = new McpServer({ name: 'greeting-server', version: '1.0.0' });
server.registerTool(
'greet',
{
description: 'Greet someone by name',
inputSchema: z.object({ name: z.string() })
},
async ({ name }) => ({
content: [{ type: 'text', text: `Hello, ${name}!` }]
})
);
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
}
main();Как запустить и проверить через MCP Inspector
MCP Inspector — локальное веб-приложение для ручного вызова инструментов. Он запускает переданную команду и подключается к серверу по stdio, ровно как это сделает клиент. Для Python достаточно uv run mcp dev server.py: откройте адрес, который напечатает команда, вызовите add с a=1 и b=2 и получите 3.
Для TypeScript передайте Inspector команду запуска. В открывшейся вкладке нажмите Connect, откройте Tools, выберите greet, введите имя и запустите. Флаг --cli вызывает те же методы из терминала, без браузера; есть и текстовый интерфейс --tui.
Inspector хранит OAuth-токены и значения env для stdio в связке ключей ОС. Где связки нет — на Linux без libsecret, по SSH, в контейнерах — секреты ложатся в ~/.mcp-inspector/secrets.json без шифрования, если не задать ключ.
# Python: откроет сервер в Inspector
uv run mcp dev server.py
# TypeScript: Inspector запустит команду и подключится по stdio
npx @modelcontextprotocol/inspector npx tsx src/index.ts
# Без браузера: список инструментов и вызов
npx @modelcontextprotocol/inspector --cli npx tsx src/index.ts --method tools/list
npx @modelcontextprotocol/inspector --cli npx tsx src/index.ts --method tools/call --tool-name greet --tool-arg name=МирКак подключить свой сервер к Claude Code
Клиенту нужна одна вещь — команда, которая запускает сервер. В Claude Code файл править не нужно: всё, что стоит после --, и есть команда запуска.
Для Python подходит uv run --with "mcp[cli]" mcp run с абсолютным путём к server.py: uv сам поднимет окружение с SDK, работает из любой папки и без активации venv. Сервер на TypeScript регистрируйте из корня проекта.
Чтобы проверить подключение, наберите /mcp в сессии Claude Code: сервер должен быть в списке вместе со своими инструментами. Флаги вроде области хранения настроек описаны на странице Claude Code в разделе клиентов каталога.
# сервер на Python
claude mcp add demo -- uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py
# сервер на TypeScript, из корня проекта
claude mcp add greeting -- npx tsx src/index.tsКак подключить к Cursor, VS Code и Claude Desktop
В Cursor создайте .cursor/mcp.json в корне проекта: та же команда и аргументы под ключом mcpServers. После сохранения сервер появится в настройках MCP в Cursor вместе с инструментами.
В VS Code файл называется .vscode/mcp.json, внешний ключ — servers, и у каждой записи есть поле type: "stdio". Нужен VS Code 1.99 или новее с расширением GitHub Copilot, чат должен стоять в режиме Agent: другие режимы инструменты не вызывают.
Для Claude Desktop у Python SDK есть команда uv run mcp install server.py: она сама найдёт файл настроек и пропишет туда команду с абсолютными путями. После правки полностью закройте Claude Desktop и откройте снова. Готовые конфиги для девяти клиентов, включая Codex, Gemini CLI и LM Studio, собраны на страницах клиентов каталога.
{
"mcpServers": {
"demo": {
"command": "uv",
"args": ["run", "--with", "mcp[cli]", "mcp", "run", "/absolute/path/to/server.py"]
}
}
}Локальный stdio или удалённый HTTP
Локальный MCP-сервер работает на stdio: клиент запускает ваш файл дочерним процессом и общается через его stdin и stdout. Порт не открывается, настраивать нечего. Это вариант для личного инструмента и одной машины.
Чтобы сервером пользовались люди без вашего файла, раздайте адрес вместо команды: тот же объект mcp, запущенный на Streamable HTTP. В Python для этого хватает аргумента transport в mcp.run(), клиенты подключаются к http://127.0.0.1:3001/mcp. Без аргумента port сервер слушает 127.0.0.1:8000, путь по умолчанию /mcp; то же делает команда uv run mcp run server.py --transport streamable-http.
В Claude Code удалённый сервер добавляется флагом --transport http: claude mcp add --transport http demo http://127.0.0.1:3001/mcp. Старый транспорт SSE с ревизии протокола 2025-03-26 заменён на Streamable HTTP, новые серверы на нём не стройте. Перед выкладкой за пределы localhost настройте защиту от DNS-rebinding, параметр transport_security.
from mcp.server import MCPServer
mcp = MCPServer("Demo")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
if __name__ == "__main__":
mcp.run(transport="streamable-http", port=3001)Как написать MCP-сервер для 1С
Для 1С есть конструктор 1c_mcp Владимира Харина: расширение MCP_Сервер.cfe берёт протокол на себя, а инструменты вы пишете на языке 1С. Нужна платформа 8.3.20 или новее. Расширение подключается к конфигурации, затем база публикуется на веб-сервере с HTTP-сервисом mcp_APIBackend, и сервер отвечает по адресу http://<веб-сервер>/<имя публикации>/hs/mcp/. Регистр имени базы в адресе должен совпадать с именем публикации, иначе редиректы превращают POST-запросы в GET.
Свой инструмент — это обработка в подсистеме mcp_КонтейнерыИнструментов с двумя экспортными методами в модуле менеджера. ДобавитьИнструменты описывает инструмент и его параметры, ВыполнитьИнструмент выполняет логику по имени инструмента. Менять HTTP-сервис и другие модули не нужно. Инструменты можно вынести в своё расширение: скопируйте туда подсистему mcp_MCPСервер с префиксом расширения, например МОЙ_mcp_MCPСервер.
Из коробки есть list_metadata_objects и get_metadata_structure для метаданных конфигурации, поддерживаются и ресурсы с промптами. Для клиентов, которым нужен stdio, и для входа через OAuth2 в репозитории лежит Python-прокси. Файл src/1c_ext/agents.md с устройством расширения можно отдать агенту, который будет писать инструменты. Готовые серверы для 1С собраны на странице «MCP-сервер для 1С» в каталоге.
Процедура ДобавитьИнструменты(Инструменты) Экспорт
МассивПараметров = Новый Массив;
// Добавляем параметры
МассивПараметров.Добавить(mcp_Метаданные.ПараметрИнструмента(
"text", "string", "Текст для обработки", , Истина));
МассивПараметров.Добавить(mcp_Метаданные.ПараметрИнструмента(
"maxLength", "number", "Максимальная длина", 100));
// Создаем схему
СхемаПараметров = mcp_Метаданные.СхемаПараметровИнструмента(МассивПараметров);
// Добавляем инструмент
mcp_Метаданные.ДобавитьИнструмент(
Инструменты, "process_text", "Обработка текста", СхемаПараметров);
КонецПроцедуры
Функция ВыполнитьИнструмент(ИмяИнструмента, Аргументы) Экспорт
Если ИмяИнструмента = "process_text" Тогда
Текст = Аргументы.text;
МаксДлина = ?(Аргументы.Свойство("maxLength"), Аргументы.maxLength, 100);
// Логика обработки
Результат = Лев(Текст, МаксДлина);
Возврат Результат;
КонецЕсли;
ВызватьИсключение "Неизвестный инструмент: " + ИмяИнструмента;
КонецФункцииЕсли клиент не видит сервер
Сначала запустите команду запуска руками. Сервер на stdio молчит и не завершается: он ждёт, пока клиент заговорит первым, остановить его можно Ctrl+C. Сервер на TypeScript из примера SDK печатает одну строку в stderr и тоже ждёт. Трассировка ошибки или мгновенный выход — это и есть поломка, и здесь её видно.
Если команда ждёт как положено, причина почти всегда одна из трёх. Относительный путь: клиент запускает сервер из своей рабочей папки, поэтому путь к server.py, а при нужде и к uv, должен быть абсолютным; путь к uv подскажет which uv или where uv. Клиент работает со старыми настройками и читает их только при запуске. Что-то пишет в stdout: на stdio это канал протокола, поэтому логируйте через logging в Python и console.error в TypeScript, один console.log ломает поток JSON-RPC.
# Python
uv run --with "mcp[cli]" mcp run /absolute/path/to/server.py
# TypeScript, из корня проекта
npx tsx src/index.tsЧастые вопросы
Что такое MCP-сервер простыми словами?
Как сделать локальный MCP-сервер?
Где взять пример MCP-сервера?
Как написать MCP для 1С?
Пример с FastMCP выдаёт No module named 'mcp.server.fastmcp'. Что делать?
Источники: modelcontextprotocol/python-sdk, modelcontextprotocol/python-sdk/blob/main/docs/get-started/f, modelcontextprotocol/python-sdk/blob/main/docs/get-started/r, modelcontextprotocol/python-sdk/blob/main/docs/run/index.md, modelcontextprotocol/python-sdk/blob/main/docs/migration.md, modelcontextprotocol/typescript-sdk, modelcontextprotocol/typescript-sdk/blob/main/docs/get-start, modelcontextprotocol/typescript-sdk/blob/main/docs/get-start