Библиотека · Подключения: API, MCP и работа круглосуточно

MCP Builder — создание собственного MCP сервера

Инженер85 минОбновлено: октябрь 2026
25 из 105 в библиотеке

Время: ~25 мин теории + 60 мин практики

Команды и пакеты в этом уроке проверены по официальной документации на октябрь 2026. SDK и Claude Code обновляются часто: если команда не сработала, сверься с документацией MCP в Claude Code и modelcontextprotocol.io. Актуальные версии: Актуальное сейчас.


Суть урока

MCP — это как USB-порт для Claude. USB — стандартный разъём: подключи мышь, флешку, микрофон, принтер — компьютер их видит. MCP — стандартный протокол: подключи свой CRM, базу данных, корпоративный API, файловую систему — Claude их видит как инструменты. Сегодня ты напишешь собственный MCP сервер: 30-50 строк кода, и у Claude появляются новые возможности которых у него не было.

🎨 Образ: MCP = USB-разъём для AI. Anthropic сделал стандарт, ты делаешь устройство. Пользователь просто подключает. Вся экосистема работает потому что разъём один и тот же.


Ключевые концепции

  • MCP (Model Context Protocol) — открытый стандарт Anthropic для подключения AI к внешним инструментам (modelcontextprotocol.io)
  • MCP сервер — программа которая предоставляет tools, resources, prompts для Claude
  • Транспорты: stdio (локально), HTTP (remote, рекомендуемый), SSE (remote, deprecated), WebSocket (только через JSON-конфиг)
  • Три типа объектов: tools (действия), resources (данные), prompts (шаблоны)
  • Три области видимости: local (дефолт, приватно), project (через .mcp.json, для команды), user (все проекты)
  • Установка: claude mcp add (CLI), .mcp.json (файл), или через плагин
  • Токен-экономика: предупреждение при >10,000 токенов, лимит по умолчанию 25,000 токенов на вызов
  • TypeScript SDK — @modelcontextprotocol/server / Python SDK — pip install "mcp[cli]" (старый TypeScript-пакет @modelcontextprotocol/sdk ещё встречается в примерах)

Теория

Архитектура MCP

Код
Claude Code (Client)
       │
       │  Стандартный MCP протокол (JSON-RPC 2.0)
       │  через stdio или HTTP (SSE устарел)
       ▼
MCP Server (твой код)
       │
       ├── tools    → функции которые Claude может вызвать
       ├── resources → данные которые Claude может прочитать
       └── prompts  → шаблоны для повторяющихся задач
       │
       ▼
Внешняя система (CRM, БД, API, файлы...)

🎨 Образ: MCP сервер — как бригадир на стройке. Он всегда на месте пока идёт работа. Claude звонит бригадиру ("найди контакт"), бригадир идёт в CRM и возвращается с ответом. Claude не знает как устроена CRM — только что бригадир умеет с ней работать.

Ключевое: MCP сервер — обычная программа. Она запускается когда Claude Code стартует в проекте и остаётся активной пока сессия открыта. Claude вызывает tools через JSON-RPC запросы, сервер отвечает результатами.

Что можно делать с подключёнными MCP серверами (из официальной документации):

  • Реализовать фичу из issue tracker: "Сделай фичу из JIRA ENG-4521 и создай PR на GitHub"
  • Анализировать мониторинг: "Проверь Sentry и покажи ошибки за 24 часа"
  • Запрашивать базы данных: "Найди пользователей которые использовали фичу X"
  • Интегрировать дизайны: "Обнови шаблон по новым Figma макетам"
  • Автоматизировать: "Создай черновики писем для этих 10 пользователей"

Три способа установки MCP серверов

Способ 1: Remote HTTP сервер (рекомендуемый для облачных сервисов)

bash
claude mcp add --transport http notion https://mcp.notion.com/mcp

Способ 2: Remote SSE сервер (deprecated, используй HTTP)

bash
claude mcp add --transport sse asana https://mcp.asana.com/sse

Способ 3: Локальный stdio сервер

bash
claude mcp add --transport stdio --env AIRTABLE_API_KEY=YOUR_KEY airtable \
  -- npx -y airtable-mcp-server

Важно: все опции (--transport, --env, --scope) ставятся перед именем сервера. -- разделяет имя от команды запуска.

Три области видимости (scope)

Scope Где хранится Кому доступен Когда использовать
local (default) ~/.claude.json Только тебе, только в этом проекте Личные серверы, эксперименты
project .mcp.json в корне проекта Всей команде (через git) Общие для проекта инструменты
user ~/.claude.json Тебе во всех проектах Личные утилиты для всех проектов
bash
# Добавить как project scope (для команды)
claude mcp add --transport http --scope project sentry https://mcp.sentry.dev/mcp

При конфликте имён приоритет: local > project > user > plugin > claude.ai connectors. Серверы, заданные администратором организации, имеют приоритет над всеми.

Управление серверами

bash
claude mcp list              # Список всех серверов
claude mcp get github        # Детали конкретного сервера
claude mcp remove github     # Удалить сервер
/mcp                         # Внутри Claude Code — статус серверов и повторное подключение

Токен-экономика MCP (важно для бизнеса)

Каждый MCP сервер потребляет токены из контекстного окна. Это критично для стоимости:

  • Предупреждение при выводе >10,000 токенов от одного вызова
  • Лимит по умолчанию: 25,000 токенов на один ответ MCP tool
  • Настройка лимита: MAX_MCP_OUTPUT_TOKENS=50000 claude
  • Таймаут старта: MCP_TIMEOUT=10000 claude (10 секунд)

🎨 Образ: каждый MCP сервер = пассажир в контекстном автобусе. Раньше описания всех его инструментов занимали место сразу. Сейчас по умолчанию работает tool search: при старте загружаются только названия, а подробности подтягиваются когда Claude они нужны. Но результаты вызовов всё равно занимают контекст. Выбирай тех кто реально нужен.

Авто-переподключение: если HTTP/SSE сервер отключается — Claude Code автоматически переподключается с экспоненциальным откатом (до 5 попыток). Локальные stdio-серверы сами не переподключаются: перезапусти их через /mcp.


Три типа объектов MCP

🎨 Образ: Tools — отвёртка (действия). Resources — чертёж (данные для чтения). Prompts — инструкция по сборке (шаблон). В большинстве проектов нужна только отвёртка.

Tools (инструменты) — действия которые Claude может выполнять:

  • get_contact — получить контакт из CRM
  • create_task — создать задачу
  • send_message — отправить сообщение
  • query_database — выполнить запрос к БД

Resources (ресурсы) — данные которые Claude может читать:

  • crm://contacts/list — список контактов
  • db://reports/monthly — месячный отчёт
  • file://config/settings — конфиг приложения

Prompts (шаблоны) — готовые инструкции для типовых задач:

  • analyze_deal — шаблон анализа сделки
  • write_followup — шаблон follow-up письма

Большинству проектов достаточно только tools.


Минимальный MCP сервер: Hello World

Устанавливаем SDK:

bash
npm init -y
npm install @modelcontextprotocol/server zod
npm install -D @types/node typescript
mkdir src

В package.json добавь "type": "module". Рядом положи tsconfig.json:

json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "types": ["node"],
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}

Создаём src/server.ts:

typescript
import { McpServer } from "@modelcontextprotocol/server";
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import { z } from "zod";

// Создаём сервер
const server = new McpServer({
  name: "my-first-mcp",
  version: "1.0.0",
});

// Добавляем tool — простая функция
server.registerTool(
  "get_weather",                              // Имя tool
  {
    description: "Получить погоду для города",           // Описание для Claude
    inputSchema: z.object({                              // Параметры (Zod схема)
      city: z.string().describe("Название города"),
    }),
  },
  async ({ city }) => {
    // Здесь реальная логика: API вызов, БД запрос, и т.д.
    // Для примера — заглушка
    return {
      content: [{
        type: "text",
        text: `Погода в ${city}: +22°C, облачно`
      }]
    };
  }
);

// Подключаем stdio транспорт и запускаем
const transport = new StdioServerTransport();
await server.connect(transport);

Важно: stdio-сервер общается с Claude через стандартный вывод, поэтому в нём нельзя печатать логи через console.log. Для логов используй console.error.

Компилируем и запускаем:

bash
npx tsc
node build/server.js

Реальный пример: MCP сервер для CRM

Полноценный сервер который Claude Code использует для работы с вымышленной CRM через REST API:

typescript
import { McpServer } from "@modelcontextprotocol/server";
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import { z } from "zod";

const CRM_API_URL = process.env.CRM_API_URL || "https://api.mycrm.com";
const CRM_API_KEY = process.env.CRM_API_KEY || "";

const server = new McpServer({
  name: "crm-mcp-server",
  version: "1.0.0",
});

// Tool 1: Получить контакт по имени или email
server.registerTool(
  "get_contact",
  {
    description: "Найти контакт в CRM по имени или email адресу",
    inputSchema: z.object({
      query: z.string().describe("Имя или email для поиска"),
    }),
  },
  async ({ query }) => {
    const response = await fetch(
      `${CRM_API_URL}/contacts/search?q=${encodeURIComponent(query)}`,
      { headers: { "X-API-Key": CRM_API_KEY } }
    );
    const data = await response.json();

    if (!data.contacts?.length) {
      return { content: [{ type: "text", text: `Контакт "${query}" не найден` }] };
    }

    const contact = data.contacts[0];
    return {
      content: [{
        type: "text",
        text: JSON.stringify({
          id: contact.id,
          name: contact.full_name,
          email: contact.email,
          company: contact.company,
          deal_stage: contact.deal_stage,
          last_contact: contact.last_contact_date,
        }, null, 2)
      }]
    };
  }
);

// Tool 2: Создать задачу
server.registerTool(
  "create_task",
  {
    description: "Создать задачу в CRM привязанную к контакту",
    inputSchema: z.object({
      contact_id: z.string().describe("ID контакта"),
      title: z.string().describe("Название задачи"),
      due_date: z.string().describe("Срок выполнения в формате YYYY-MM-DD"),
      priority: z.enum(["low", "medium", "high"]).describe("Приоритет задачи"),
    }),
  },
  async ({ contact_id, title, due_date, priority }) => {
    const response = await fetch(`${CRM_API_URL}/tasks`, {
      method: "POST",
      headers: {
        "X-API-Key": CRM_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ contact_id, title, due_date, priority }),
    });
    const task = await response.json();

    return {
      content: [{
        type: "text",
        text: `Задача создана. ID: ${task.id}. Срок: ${due_date}. Приоритет: ${priority}.`
      }]
    };
  }
);

// Tool 3: Обновить статус сделки
server.registerTool(
  "update_deal_stage",
  {
    description: "Обновить стадию сделки для контакта",
    inputSchema: z.object({
      contact_id: z.string().describe("ID контакта"),
      stage: z.enum(["lead", "qualified", "proposal", "negotiation", "closed_won", "closed_lost"])
             .describe("Новая стадия сделки"),
      note: z.string().optional().describe("Заметка к изменению стадии"),
    }),
  },
  async ({ contact_id, stage, note }) => {
    await fetch(`${CRM_API_URL}/contacts/${contact_id}`, {
      method: "PATCH",
      headers: {
        "X-API-Key": CRM_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ deal_stage: stage, stage_note: note }),
    });

    return {
      content: [{
        type: "text",
        text: `Стадия сделки обновлена: ${stage}${note ? `. Заметка: ${note}` : ""}`
      }]
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);

Регистрация в проекте: .mcp.json

Чтобы Claude Code автоматически запускал твой MCP сервер при открытии проекта, создаёшь .mcp.json в корне проекта:

json
{
  "mcpServers": {
    "crm": {
      "command": "node",
      "args": ["./mcp-servers/crm/build/server.js"],
      "env": {
        "CRM_API_URL": "https://api.mycrm.com",
        "CRM_API_KEY": "${CRM_API_KEY}"
      }
    }
  }
}

После этого при открытии Claude Code в этой папке сервер запускается автоматически. Claude видит tools get_contact, create_task, update_deal_stage как встроенные возможности.

Переменные окружения в .mcp.json (официальная фича):

Поддерживается синтаксис ${VAR} и ${VAR:-default} в полях command, args, env, url, headers:

json
{
  "mcpServers": {
    "api-server": {
      "type": "http",
      "url": "${API_BASE_URL:-https://api.example.com}/mcp",
      "headers": {
        "Authorization": "Bearer ${API_KEY}"
      }
    }
  }
}

Это позволяет коммитить .mcp.json в git без секретов — каждый разработчик ставит свои переменные окружения.

Регистрация через CLI (альтернатива):

bash
# Как user scope (доступен во всех проектах)
claude mcp add --transport stdio --scope user crm -- node ./server.js

# Добавить через JSON
claude mcp add-json crm '{"command":"node","args":["./server.js"],"env":{"CRM_API_KEY":"${CRM_API_KEY}"}}'

Импорт из Claude Desktop (если уже настроено, работает на macOS и WSL):

bash
claude mcp add-from-claude-desktop

Тестирование: MCP Inspector

🎨 Образ: MCP Inspector — как тест-драйв автомобиля на пустой парковке. Прежде чем выехать на шоссе (Claude Code), ты проверяешь: руль работает, тормоза работают, двигатель не стучит. Экономит часы на отладке в боевом режиме.

Проект MCP предоставляет интерактивный инспектор для тестирования серверов без Claude (нужен Node 22.19 или новее):

bash
npx @modelcontextprotocol/inspector node build/server.js

Открывается веб-интерфейс где можно:

  • Видеть все зарегистрированные tools
  • Вызывать каждый tool вручную с параметрами
  • Смотреть что server отвечает
  • Дебажить ошибки

Есть и консольный режим: npx @modelcontextprotocol/inspector --cli node build/server.js --method tools/list покажет список tools и завершится. Это гораздо быстрее чем тестировать через Claude Code.


Claude Code как MCP сервер

Claude Code сам может работать как MCP сервер для других приложений:

bash
claude mcp serve

Подключение из Claude Desktop:

json
{
  "mcpServers": {
    "claude-code": {
      "type": "stdio",
      "command": "claude",
      "args": ["mcp", "serve"],
      "env": {}
    }
  }
}

Это даёт другим AI приложениям доступ к инструментам Claude Code (Read, Edit, Bash и др.).


Привязка MCP серверов к суб-агентам

🎨 Образ: Привязка MCP к суб-агенту — как выдать инструменты только нужной бригаде. Сантехник не ходит с инструментами электрика — только со своими. Основной разговор не засоряется инструментами которые нужны только на время работы одного субагента.

MCP серверы можно привязать к конкретному суб-агенту через поле mcpServers в frontmatter:

Напиши в чат
---
name: browser-tester
description: Tests features in a real browser using Playwright
mcpServers:
  - playwright:
      type: stdio
      command: npx
      args: ["-y", "@playwright/mcp@latest"]
---

Инлайн-серверы подключаются при старте суб-агента и отключаются когда он завершает работу. Основной разговор не видит эти инструменты — это экономит контекст.


Python вариант: FastMCP

Если предпочитаешь Python, есть более декларативный способ: SDK строит описание tool из аннотаций типов и docstring. В актуальной документации класс называется MCPServer (в старых примерах встречается FastMCP):

python
# pip install "mcp[cli]"   или   uv add "mcp[cli]"
from mcp.server import MCPServer

mcp = MCPServer("crm-server")

@mcp.tool()
def get_contact(query: str) -> str:
    """Найти контакт в CRM по имени или email"""
    # Логика поиска
    return f"Контакт найден: {query}"

@mcp.tool()
def create_task(contact_id: str, title: str, due_date: str) -> str:
    """Создать задачу в CRM"""
    # Логика создания задачи
    return f"Задача создана: {title} для {contact_id}"

if __name__ == "__main__":
    mcp.run(transport="stdio")

Регистрация в .mcp.json:

json
{
  "mcpServers": {
    "crm-python": {
      "command": "python",
      "args": ["./mcp-servers/crm_server.py"]
    }
  }
}

Публикация на npm

Если хочешь поделиться MCP сервером или использовать в нескольких проектах:

bash
# package.json
{
  "name": "@yourname/mcp-crm",
  "version": "1.0.0",
  "type": "module",
  "bin": { "mcp-crm": "./server.js" },
  "main": "./server.js"
}

# Публикация
npm publish --access public

После публикации любой может использовать:

json
{
  "mcpServers": {
    "crm": {
      "command": "npx",
      "args": ["-y", "@yourname/mcp-crm"]
    }
  }
}

Ресурсы MCP: @-упоминания

MCP серверы могут предоставлять resources которые ты ссылаешь через @:

Напиши в чат
Проанализируй @github:issue://123 и предложи фикс
Посмотри документацию @docs:file://api/authentication

Ресурсы появляются в автокомплите рядом с файлами когда ты набираешь @.

Динамическое обновление инструментов

Claude Code поддерживает list_changed нотификации от MCP серверов. Если сервер добавляет или убирает tools — Claude Code автоматически обновляет список без переподключения.


Практика

Задание: MCP сервер для работы с локальными файлами заметок

  1. Создай папку my-notes-mcp/, инициализируй проект по шагам из раздела Hello World выше: npm init -y, npm install @modelcontextprotocol/server zod, npm install -D @types/node typescript, "type": "module" и tsconfig.json
  2. Создай src/server.ts с тремя tools:
    • list_notes — список файлов в папке ~/Notes/ (или любой твоей)
    • read_note — прочитать конкретный файл по имени
    • create_note — создать новый файл с заметкой
  3. Скомпилируй: npx tsc
  4. Протестируй через MCP Inspector: npx @modelcontextprotocol/inspector node build/server.js
  5. Зарегистрируй в .mcp.json проекта
  6. Перезапусти Claude Code — проверь что tools появились
  7. Попроси Claude: "Создай заметку о сегодняшней встрече" — он должен использовать твой tool
  8. Бонус: добавь search_notes tool который ищет по содержимому заметок через grep

Цель: написать работающий MCP сервер с нуля, зарегистрировать и протестировать через Claude Code.


Инструменты и ресурсы

  • @modelcontextprotocol/server — npm install @modelcontextprotocol/server — официальный TypeScript SDK
  • mcp — pip install "mcp[cli]" — Python SDK (класс MCPServer, раньше FastMCP)
  • zod — npm install zod — типизация параметров tools (обязательно для TypeScript SDK)
  • MCP Inspector — npx @modelcontextprotocol/inspector — тестирование без Claude
  • Документация: modelcontextprotocol.io — спецификация протокола
  • Официальная страница MCP в Claude Code: https://code.claude.com/docs/en/mcp
  • GitHub: github.com/modelcontextprotocol/servers — сотни готовых серверов
  • CLI команды:
    • claude mcp add — добавить сервер
    • claude mcp list — список серверов
    • claude mcp get <name> — детали сервера
    • claude mcp remove <name> — удалить
    • claude mcp add-from-claude-desktop — импорт из Claude Desktop
    • claude mcp add-json <name> '<json>' — добавить из JSON
    • claude mcp serve — запустить Claude Code как MCP сервер
    • /mcp — статус серверов внутри Claude Code (включая OAuth аутентификацию)

Ключевые выводы

MCP сервер — обычная программа на TypeScript или Python. 30-50 строк кода дают Claude новые инструменты. Сложность растёт только от сложности твоей логики, не от MCP протокола.

Транспорты: stdio (локально), HTTP (remote, рекомендуемый), SSE (deprecated), WebSocket (через JSON-конфиг). Три scope: local (по умолчанию), project (.mcp.json для команды), user (все проекты).

Токен-экономика: результаты вызовов MCP потребляют контекст (описания инструментов по умолчанию подгружаются по мере надобности). Предупреждение при >10,000 токенов вывода. Лимит по умолчанию 25,000 токенов. Настраивается через MAX_MCP_OUTPUT_TOKENS.

Тестируй через MCP Inspector перед подключением к Claude — это экономит время на отладке.

MCP серверы можно привязать к суб-агентам через поле mcpServers в frontmatter — сервер подключается только на время работы суб-агента и не засоряет контекст основного разговора.

.mcp.json поддерживает переменные окружения (${VAR}, ${VAR:-default}) — можно коммитить в git без секретов.


Следующий урок

→ Портфолио и кейс-стади: как показать ценность

Отметка хранится только в этом браузере и никуда не отправляется. Мой прогресс