ГлавнаяБлогСоздание MCP сервера на Python: полное руководство
Python

Создание MCP сервера на Python: полное руководство

Научитесь создавать MCP сервер на Python с нуля: инструменты, ресурсы и промпты. Подключите к Claude Desktop или Claude Code. Рабочий пример с GitHub API.

Al
Редакция Algolitalgolit.ru
12 мин чтения19 июня 2026 г.

Что такое MCP сервер и зачем он нужен?

Model Context Protocol (MCP) — это открытый протокол, который позволяет AI-ассистентам (Claude, Cursor и другим) вызывать внешние сервисы стандартизированным образом. За два года MCP превратился из нишевого проекта Anthropic в индустриальный стандарт: 97 миллионов загрузок SDK ежемесячно, поддержка ведущих AI-инструментов и место под управлением Linux Foundation. Если вы пишете AI-агентов или интегрируете LLM в свои проекты, MCP — это способ дать им доступ к реальным данным и действиям.

В этом руководстве мы с нуля напишем MCP сервер на Python, который работает с GitHub API. Вы узнаете, как определять инструменты, ресурсы и промпты, тестировать сервер с помощью MCP Inspector и подключать его к Claude Desktop или Claude Code. Код можно адаптировать под любой внешний API.

Предварительные требования

  • Python 3.10 или новее
  • Установленный uv (рекомендуется) или pip
  • Claude Desktop или Claude Code (для подключения)

Как работает MCP сервер

MCP использует протокол JSON-RPC для обмена сообщениями между AI-клиентом и сервером. Сервер предоставляет три основных типа сущностей:

  • Инструменты (Tools) — вызываемые функции, которые AI может запускать для получения данных или выполнения действий.
  • Ресурсы (Resources) — доступные только для чтения данные, которые AI может запрашивать (аналогично файлам или записям БД).
  • Промпты (Prompts) — шаблоны инструкций, хранящиеся на сервере и вызываемые по имени для стандартизации рабочих процессов.

В качестве транспорта используем stdio — сервер запускается как подпроцесс и общается через стандартный ввод/вывод. Это работает с Claude Desktop и Claude Code без дополнительной настройки.

Настройка проекта

Создайте новую директорию и установите MCP SDK с дополнительным пакетом [cli], который включает dev-сервер и инспектор:

mkdir github-mcp-server
cd github-mcp-server
uv init .
uv add "mcp[cli]" httpx

Если вы используете pip:

pip install "mcp[cli]" httpx

Проект состоит из трёх файлов: server.py, pyproject.toml (если используете uv) и опционального .env для GitHub токена.

Минимальный инструмент за 10 строк

Начнём с простейшего рабочего примера, чтобы убедиться, что SDK настроен корректно:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("hello-mcp")

@mcp.tool()
def greet(name: str) -> str:
    """Возвращает персонализированное приветствие. Используй, когда нужно поприветствовать кого-то."""
    return f"Привет, {name}! Твой MCP сервер работает."

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

Запустите uv run mcp dev server.py и откройте http://localhost:5173. Перейдите на вкладку Tools, вызовите greet с любым именем и проверьте ответ. Обратите внимание: FastMCP автоматически генерирует JSON-RPC обвязку, декоратор @mcp.tool() создаёт схему из аннотаций типов, а docstring используется AI для принятия решения о вызове инструмента — пишите её чётко.

Создание сервера для GitHub

Теперь заменим минимальный пример на полноценный сервер с двумя инструментами: получение метаданных репозитория и список открытых issues. Используем httpx для асинхронных запросов к GitHub API.

import os, logging, sys, httpx
from pydantic import BaseModel
from mcp.server.fastmcp import FastMCP

logging.basicConfig(stream=sys.stderr, level=logging.INFO)
logger = logging.getLogger(__name__)

mcp = FastMCP("github-tools", instructions=(
    "Этот сервер предоставляет инструменты для работы с GitHub API. "
    "Используй get_repo_info для получения метаданных репозитория. "
    "Используй list_open_issues для получения открытых issues."
))

GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", "")

def _github_headers() -> dict[str, str]:
    headers = {
        "Accept": "application/vnd.github+json",
        "X-GitHub-Api-Version": "2022-11-28",
    }
    if GITHUB_TOKEN:
        headers["Authorization"] = f"Bearer {GITHUB_TOKEN}"
    return headers

class RepoInfo(BaseModel):
    full_name: str
    description: str | None
    stars: int
    forks: int
    open_issues: int
    language: str | None
    url: str

@mcp.tool()
async def get_repo_info(owner: str, repo: str) -> RepoInfo:
    """
    Получить метаданные репозитория GitHub: звёзды, форки, количество открытых issues.
    Args:
        owner: Имя пользователя или организации GitHub (например 'anthropics')
        repo: Название репозитория (например 'claude-code')
    """
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"https://api.github.com/repos/{owner}/{repo}",
            headers=_github_headers(),
            timeout=10.0,
        )
        response.raise_for_status()
        data = response.json()
        return RepoInfo(
            full_name=data["full_name"],
            description=data.get("description"),
            stars=data["stargazers_count"],
            forks=data["forks_count"],
            open_issues=data["open_issues_count"],
            language=data.get("language"),
            url=data["html_url"],
        )

@mcp.tool()
async def list_open_issues(owner: str, repo: str, limit: int = 10) -> str:
    """
    Вывести открытые issues репозитория, отсортированные по дате обновления.
    Args:
        owner: Имя пользователя или организации GitHub
        repo: Название репозитория
        limit: Максимум issues (1-30, по умолчанию 10)
    """
    limit = max(1, min(limit, 30))
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"https://api.github.com/repos/{owner}/{repo}/issues",
            headers=_github_headers(),
            params={"state": "open", "per_page": limit, "sort": "updated"},
            timeout=10.0,
        )
        response.raise_for_status()
        issues = response.json()
        if not issues:
            return f"Открытых issues в {owner}/{repo} не найдено."
        lines = [f"Открытые issues в **{owner}/{repo}** (показано {len(issues)}):\n"]
        for issue in issues:
            lines.append(f"- #{issue['number']}: {issue['title']}")
        return "\n".join(lines)

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

Важные решения: возврат Pydantic модели даёт AI типизированный структурированный ответ, что надёжнее парсинга строк. Для строковых инструментов лучше перехватывать исключения и возвращать сообщение об ошибке — необработанное исключение может убить соединение. Всегда ограничивайте числовые параметры, такие как limit — AI может передать 0, 100 или строку.

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

Ресурсы позволяют AI читать данные пассивно. Вот ресурс, сообщающий, настроен ли GitHub токен, и динамический ресурс для получения README репозитория:

@mcp.resource("config://github-tools/status")
def server_status() -> str:
    """Сообщить, настроен ли GitHub токен."""
    auth_status = "аутентифицирован" if GITHUB_TOKEN else "не аутентифицирован (ограничение 60 запросов/час)"
    return f"GitHub Tools MCP Сервер\nСтатус: {auth_status}"

@mcp.resource("github://repos/{owner}/{repo}/readme")
async def get_readme(owner: str, repo: str) -> str:
    """Получить содержимое README репозитория."""
    async with httpx.AsyncClient() as client:
        response = await client.get(
            f"https://api.github.com/repos/{owner}/{repo}/readme",
            headers={**_github_headers(), "Accept": "application/vnd.github.raw+json"},
            timeout=10.0,
        )
        if response.status_code == 404:
            return "README для этого репозитория не найден."
        response.raise_for_status()
        return response.text

Промпты — это шаблоны инструкций, которые любой MCP клиент может вызвать по имени. Этот промпт структурирует запрос на ревью кода, используя наши инструменты:

@mcp.prompt()
def review_pull_request(owner: str, repo: str, pr_number: int) -> str:
    """
    Шаблон промпта для ревью пул-реквеста на GitHub.
    """
    return (
        f"Пожалуйста, проверьте пул-реквест #{pr_number} в {owner}/{repo}.\n"
        f"Начните с получения информации о репозитории через get_repo_info,\n"
        f"затем выведите открытые issues, чтобы понять контекст проекта.\n"
        f"Сосредоточьтесь на корректности, производительности и соблюдении паттернов проекта."
    )

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

Быстрейший способ проверить сервер — встроенный инспектор, не требующий Claude. Запустите uv run mcp dev server.py и откройте http://localhost:5173.

Установите GITHUB_TOKEN в разделе Environment Variables перед подключением. Затем тестируйте инструменты на вкладке Tools, проверяйте ресурсы на вкладке Resources и промпты на вкладке Prompts. Если что-то не работает, панель Logs показывает сырой JSON-RPC обмен — это самый прямой способ найти проблему.

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

Откройте файл конфигурации Claude Desktop: на macOS это ~/Library/Application Support/Claude/claude_desktop_config.json, на Windows — %APPDATA%\Claude\claude_desktop_config.json. Добавьте ваш сервер в раздел mcpServers:

{
  "mcpServers": {
    "github-tools": {
      "command": "uv",
      "args": ["run", "--with", "mcp[cli]", "--with", "httpx", "python", "/абсолютный/путь/к/github-mcp-server/server.py"],
      "env": {
        "PYTHONUNBUFFERED": "1",
        "GITHUB_TOKEN": "ваш_github_токен"
      }
    }
  }
}

Используйте uv run, а не голый python — Claude Desktop запускает своё окружение без вашего PATH, поэтому голый python часто не работает. Полностью выйдите и перезапустите Claude Desktop после сохранения. Иконка плагина в поле ввода подтверждает подключение сервера.

Подключение к Claude Code

Для Claude Code используйте CLI команду claude mcp add. Разделитель -- обязателен для отделения имени сервера от команды запуска:

claude mcp add github-tools \
  -e GITHUB_TOKEN=ваш_токен \
  -e PYTHONUNBUFFERED=1 \
  -- uv run --with "mcp[cli]" --with httpx python /абсолютный/путь/к/server.py

Чтобы поделиться конфигурацией сервера с командой, используйте --scope project. Это создаст файл .mcp.json в корне репозитория и предложит участникам активировать его при открытии проекта. Выполните claude mcp list для проверки регистрации.

Что делать прямо сейчас

  1. Создайте новый проект с MCP SDK по инструкции выше.
  2. Скопируйте код сервера для GitHub и замените токен на свой.
  3. Запустите MCP Inspector и протестируйте все инструменты и ресурсы.
  4. Подключите сервер к Claude Desktop или Claude Code.
  5. Попробуйте задать Claude вопрос: «Сколько звёзд у репозитория python/cpython?»
  6. Расширьте сервер: добавьте новые инструменты для других API (например, погода, базы данных, внутренние сервисы).

Теперь у вас есть работающий MCP сервер на Python, который можно адаптировать под любые задачи. Делитесь опытом в комментариях!

#MCP#Python#сервер#API#Claude
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →