Model Context Protocol (MCP) превратился в стандартный способ давать ИИ-моделям доступ к внешним данным и действиям: файлам, базам, API, вашей CRM. Готовых серверов уже сотни, но рано или поздно возникает задача, под которую подходящего сервера нет, — и его приходится писать самому. Хорошая новость: минимальный рабочий MCP-сервер занимает пару десятков строк кода. В этом гайде разберём, из чего состоит сервер, какие бывают транспорты, и напишем рабочий пример на Python и на TypeScript.
Если вы ещё не знакомы с самим протоколом, начните с заметки «Что такое MCP простыми словами» — там разобрано, зачем нужен этот «разъём для ИИ». А если интересует не написание сервера с нуля, а подключение готовых инструментов к сайту и CRM, посмотрите практический разбор «MCP: подключаем ИИ к сайту и CRM».
Что делает MCP-сервер
MCP-сервер — это программа, которая по стандартному протоколу сообщает ИИ-клиенту (Claude Desktop, Claude Code, IDE, вашему агенту): «вот что я умею», а затем выполняет запросы. Клиент и сервер обмениваются сообщениями в формате JSON-RPC 2.0. Модель сама решает, когда вызвать ваш инструмент, а сервер просто отдаёт результат. Благодаря единому протоколу один и тот же сервер работает с любым MCP-совместимым клиентом — писать отдельную интеграцию под каждое приложение больше не нужно.
Писать собственный сервер стоит, когда нужно дать модели доступ к вашей внутренней системе: базе данных, самописному API, специфичному бизнес-процессу, локальным файлам или оборудованию. Всё, что можно вызвать из кода, оборачивается в инструмент MCP.
Три строительных блока: инструменты, ресурсы, промпты
Спецификация описывает три вида возможностей, которые сервер может предоставлять клиенту.
Инструменты (tools) — действия, которые вызывает модель: «найти клиента по email», «создать задачу», «выполнить SQL-запрос». Это самый частый и самый мощный примитив. У инструмента есть имя, описание и схема входных параметров, по которой модель понимает, что и как передавать.
Ресурсы (resources) — данные только для чтения, которые клиент подгружает в контекст: содержимое файла, запись из базы, документ. В отличие от инструментов, ресурсы не выполняют действий и не имеют побочных эффектов — их выбирает и подставляет приложение или пользователь.
Промпты (prompts) — переиспользуемые шаблоны запросов, которые сервер отдаёт клиенту как готовые сценарии. Например, «сделай ревью этого кода по нашему чек-листу». Пользователь выбирает промпт в интерфейсе, а сервер подставляет нужные параметры.
Для большинства задач достаточно инструментов, поэтому дальше сосредоточимся на них.
Транспорты: stdio и Streamable HTTP
Транспорт — это канал, по которому клиент общается с сервером. Актуальная спецификация (версия 2025-11-25) определяет два стандартных транспорта.
stdio — клиент запускает ваш сервер как дочерний процесс и обменивается с ним сообщениями через стандартный ввод-вывод. Это простейший вариант, идеальный для локальных инструментов: интеграций с Claude Desktop, CLI-утилит, доступа к локальным файлам. Спецификация рекомендует поддерживать stdio всегда, когда это возможно.
Streamable HTTP — сервер работает как отдельный веб-сервис на одном HTTP-эндпоинте (например, https://example.com/mcp), принимающем POST и GET. При необходимости он может стримить ответы через Server-Sent Events. Этот транспорт нужен для удалённых серверов, к которым подключаются несколько клиентов по сети. Он пришёл на смену старому транспорту HTTP+SSE из версии протокола 2024-11-05 — если встречаете в старых гайдах отдельный SSE-эндпоинт, знайте, что он устарел.
Начинать почти всегда стоит с stdio: меньше кода, не нужно думать про аутентификацию и сеть, легко отлаживать. Перейти на HTTP можно потом, когда сервер понадобится вынести на удалённую машину.
Пишем MCP-сервер на Python
Официальный Python SDK включает высокоуровневый класс FastMCP, который берёт на себя всю работу с протоколом. Вам остаётся только описать инструменты обычными функциями.
Установка
Понадобится Python 3.10+ и пакет mcp. Удобнее всего ставить через менеджер uv, но подойдёт и обычный pip:
pip install "mcp[cli]"
Первый инструмент
Создадим файл server.py. Инструмент — это функция с декоратором @mcp.tool(); SDK сам построит схему параметров из аннотаций типов, а строку документации использует как описание для модели.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-server")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Сложить два числа."""
return a + b
@mcp.tool()
def get_weather(city: str) -> str:
"""Вернуть погоду для указанного города."""
# здесь мог бы быть реальный запрос к API
return f"В городе {city} сейчас +18 °C, ясно"
if __name__ == "__main__":
mcp.run(transport="stdio")
Это уже полноценный сервер с двумя инструментами. Аннотации типов (a: int, city: str) важны: по ним SDK формирует схему, а модель понимает, что передавать. Строка-докстринг — не формальность, а описание, которое читает ИИ, решая, вызывать ли инструмент.
Подключение к клиенту
Чтобы Claude Desktop увидел сервер, добавьте его в конфигурацию клиента, указав команду запуска процесса:
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/полный/путь/к/server.py"]
}
}
}
После перезапуска клиента инструменты add и get_weather станут доступны модели. Точно так же сервер подключается к Claude Code и другим MCP-совместимым клиентам.
Пишем MCP-сервер на TypeScript
Если вам ближе экосистема Node.js, есть официальный TypeScript SDK — пакет @modelcontextprotocol/sdk. Установка:
npm install @modelcontextprotocol/sdk zod
Библиотека zod нужна для описания схем входных параметров. Минимальный сервер выглядит так:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "my-server", version: "1.0.0" });
server.registerTool(
"add",
{
title: "Сложение",
description: "Сложить два числа",
inputSchema: { a: z.number(), b: z.number() },
},
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
})
);
const transport = new StdioServerTransport();
await server.connect(transport);
Логика та же, что и в Python: создаём объект McpServer, регистрируем инструменты через registerTool() (для ресурсов и промптов есть registerResource() и registerPrompt()), затем подключаем транспорт и вызываем server.connect(). Результат инструмента возвращается в поле content — массиве блоков, чаще всего текстовых.
Безопасность: не пропускайте этот раздел
Пока сервер работает по stdio на вашей машине, поверхность атаки минимальна. Но как только вы переводите его на Streamable HTTP и открываете наружу, появляются реальные риски, и спецификация прямо предписывает защиту.
Во-первых, сервер обязан проверять заголовок Origin у всех входящих соединений — это защита от атак DNS rebinding, когда вредоносный сайт в браузере пытается достучаться до вашего локального сервера. Если Origin некорректен, нужно отвечать 403 Forbidden. Во-вторых, при локальном запуске сервер стоит привязывать только к 127.0.0.1, а не к 0.0.0.0, чтобы он не был виден всей сети. В-третьих, для любых сетевых подключений следует внедрять аутентификацию.
Отдельно помните про доверие к вводу: инструмент, выполняющий SQL или shell-команды по параметрам от модели, — потенциальная дыра. Валидируйте входные данные и ограничивайте права так же строго, как для любого публичного API.
Как отладить и что дальше
Для локальной отладки удобен инспектор — официальная утилита, которая подключается к вашему серверу и показывает список инструментов, их схемы и результаты вызовов без необходимости поднимать полноценный клиент. Запускается она через npx и открывает веб-интерфейс, где можно вручную дёргать инструменты и смотреть JSON-RPC-обмен.
Когда сервер готов, дальнейший путь зависит от задачи: для личных инструментов достаточно stdio и локального запуска, а для командного использования сервер оборачивают в Streamable HTTP, разворачивают на сервере и закрывают аутентификацией. Начните с малого — один-два инструмента на stdio, — убедитесь, что модель корректно их вызывает, и наращивайте функциональность оттуда.
Вывод
Собственный MCP-сервер — это не сложная инфраструктура, а несколько функций, обёрнутых в стандартный протокол. Выберите SDK по вкусу (Python с FastMCP или TypeScript), опишите инструменты обычными функциями с понятными аннотациями и описаниями, запустите на stdio и подключите к клиенту. Когда понадобится удалённый доступ — переходите на Streamable HTTP, не забывая про проверку Origin, привязку к localhost и аутентификацию. Этого достаточно, чтобы дать вашему ИИ-ассистенту доступ к чему угодно — от базы данных до внутреннего API.
Частые вопросы
Официальные SDK есть для Python (класс FastMCP) и для TypeScript (пакет @modelcontextprotocol/sdk). Логика идентична, поэтому выбирайте тот язык, что ближе вашему проекту.
Для локальных инструментов достаточно транспорта stdio — клиент сам запускает сервер как процесс. Streamable HTTP нужен, когда сервер должен работать удалённо и обслуживать несколько клиентов по сети.
Да. Старый транспорт HTTP+SSE из версии протокола 2024-11-05 заменён на Streamable HTTP в актуальной спецификации (2025-11-25). Отдельный SSE-эндпоинт в новых серверах не нужен.
Это три вида возможностей MCP-сервера: инструменты — действия, которые вызывает модель; ресурсы — данные только для чтения; промпты — готовые переиспользуемые шаблоны запросов.
Источники
- 1.MCP Specification — Transports (2025-11-25)https://modelcontextprotocol.io/specification/2025-11-25/basic/transports
- 2.MCP TypeScript SDK (официальный репозиторий)https://github.com/modelcontextprotocol/typescript-sdk
- 3.MCP Python SDK (официальная документация)https://py.sdk.modelcontextprotocol.io/
- 4.@modelcontextprotocol/sdk — npmhttps://www.npmjs.com/package/@modelcontextprotocol/sdk



