Как сделать свой MCP-сервер: пример, проверка и подключение к агенту

Проверено 12.11.2026

Пишем сервер с одним инструментом на 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-сервер простыми словами?
Программа, которая даёт модели инструменты, данные и шаблоны запросов по общему протоколу. Её запускает клиент внутри приложения — Claude Code, Cursor, Claude Desktop — и пересказывает модели, что сервер умеет. Модель сама решает, какой инструмент вызвать, по его имени, описанию и схеме.
Как сделать локальный MCP-сервер?
Любой сервер на stdio локальный: клиент запускает его на вашем компьютере дочерним процессом, порт не нужен. В Python это mcp.run() без аргументов, в TypeScript — StdioServerTransport. Примеры выше работают именно так.
Где взять пример MCP-сервера?
Минимальные примеры есть в README Python SDK (инструмент add и ресурс greeting) и TypeScript SDK (инструмент greet). В пошаговом руководстве TypeScript SDK разобран сервер погодных предупреждений с инструментом get-alerts, а в папке examples/ репозитория лежат готовые пары клиента и сервера.
Как написать MCP для 1С?
Возьмите расширение 1c_mcp: оно берёт протокол на себя. Создайте обработку в подсистеме mcp_КонтейнерыИнструментов и реализуйте в модуле менеджера ДобавитьИнструменты и ВыполнитьИнструмент, как в примере выше. Базу нужно опубликовать на веб-сервере с HTTP-сервисом mcp_APIBackend.
Пример с FastMCP выдаёт No module named 'mcp.server.fastmcp'. Что делать?
Во второй версии Python SDK FastMCP переименован в MCPServer, модули mcp.server.fastmcp переехали в mcp.server.mcpserver. Замените импорт на from mcp.server import MCPServer или закрепите старую ветку зависимостью mcp>=1.28,<2.

Источники: 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