Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Первый MCP сервер
first_server

Первый MCP сервер

Создание Hello World сервера. Запуск и отладка через stdio транспорт.

Первый MCP сервер

От теории к практике. В этой теме создадим первый работающий MCP сервер с нуля, запустим и протестируем через Claude Desktop.


#1. Минимальный сервер: 30 строк кода

Начнём с простейшего сервера, который предоставляет один инструмент.

#Базовая структура

#!/usr/bin/env python3 """Простейший MCP сервер с одним инструментом.""" from mcp.server.fastmcp import FastMCP # Создаём сервер mcp = FastMCP("Hello MCP") # Регистрируем инструмент @mcp.tool() def hello(name: str) -> str: """Приветствие пользователя.""" return f"Hello, {name}! Welcome to MCP." # Запуск сервера if __name__ == "__main__": mcp.run()

#Запуск сервера

# Сохраните как hello_server.py poetry run python hello_server.py

Сервер запущен и ждёт подключений через stdio!


#2. Как это работает

#FastMCP — высокоуровневый API

FastMCP — это упрощённый интерфейс для создания MCP серверов. Он автоматически:

  • Обрабатывает JSON-RPC сообщения
  • Управляет сессиями
  • Преобразует Python функции в MCP инструменты
  • Генерирует JSON Schema для параметров

#Декоратор @mcp.tool()

@mcp.tool() def hello(name: str) -> str: """Приветствие пользователя.""" return f"Hello, {name}! Welcome to MCP."

Что происходит:

  1. Имя инструмента: берётся из имени функции (hello)
  2. Описание: берётся из docstring ("Приветствие пользователя.")
  3. Схема параметров: автоматически генерируется из type hints
  4. Тип возвращаемого значения: используется для форматирования ответа

Сгенерированная JSON Schema:

{ "name": "hello", "description": "Приветствие пользователя.", "inputSchema": { "type": "object", "properties": { "name": { "type": "string", "description": "" } }, "required": ["name"] } }

#3. Тестирование через MCP Inspector

#Запуск Inspector

# Установка (если не установлен) npm install -g @modelcontextprotocol/inspector # Запуск с вашим сервером npx @modelcontextprotocol/inspector python hello_server.py

#Работа с Inspector

  1. Откройте браузер на http://localhost:5173
  2. Вы увидите список инструментов (Tools)
  3. Нажмите на инструмент hello
  4. Введите параметр name: "World"
  5. Нажмите "Call Tool"
  6. Получите ответ: "Hello, World! Welcome to MCP."

Интерфейс Inspector:

┌─────────────────────────────────────────┐
│ MCP Inspector                           │
├─────────────────────────────────────────┤
│ Tools │ Resources │ Prompts             │
├─────────────────────────────────────────┤
│ hello                                   │
│   Приветствие пользователя.             │
│                                         │
│ Parameters:                             │
│   name: [World________]                 │
│                                         │
│ [Call Tool]                             │
│                                         │
│ Result:                                 │
│ "Hello, World! Welcome to MCP."         │
└─────────────────────────────────────────┘

#4. Тестирование через Claude Desktop

#Настройка конфига

Добавьте сервер в claude_desktop_config.json:

{ "mcpServers": { "hello-mcp": { "command": "poetry", "args": ["run", "python", "hello_server.py"], "cwd": "/path/to/your/project" } } }

#Проверка подключения

  1. Откройте Claude Desktop
  2. Перейдите в Settings → MCP
  3. Убедитесь, что hello-mcp в списке и статус "Connected"

#Использование в диалоге

Напишите в чате:

Привет! Можешь поздравить меня с днём рождения?

Claude увидит доступный инструмент hello и может его использовать:

[Использует инструмент hello с name="User"]
Hello, User! Welcome to MCP.

Поздравляю с днём рождения! 🎉

#5. Расширяем сервер: несколько инструментов

Добавим ещё инструментов для демонстрации:

#!/usr/bin/env python3 """MCP сервер с несколькими инструментами.""" from mcp.server.fastmcp import FastMCP mcp = FastMCP("Calculator MCP") @mcp.tool() def add(a: int, b: int) -> int: """Сложение двух чисел.""" return a + b @mcp.tool() def subtract(a: int, b: int) -> int: """Вычитание b из a.""" return a - b @mcp.tool() def multiply(a: int, b: int) -> int: """Умножение двух чисел.""" return a * b @mcp.tool() def divide(a: float, b: float) -> float: """Деление a на b.""" if b == 0: raise ValueError("Деление на ноль невозможно") return a / b if __name__ == "__main__": mcp.run()

#Тестирование калькулятора

Запрос через Claude:

Сколько будет 123 * 456 - 789?

Claude использует инструменты:

[Вызывает multiply(123, 456) → 56088]
[Вызывает subtract(56088, 789) → 55299]

Ответ: 55299

#6. Работа с параметрами

#Обязательные и необязательные параметры

@mcp.tool() def greet( name: str, greeting: str = "Hello", punctuation: str = "!" ) -> str: """ Персональное приветствие. Args: name: Имя человека greeting: Слово приветствия (по умолчанию "Hello") punctuation: Знак препинания (по умолчанию "!") """ return f"{greeting}, {name}{punctuation}"

JSON Schema:

{ "name": "greet", "description": "Персональное приветствие.", "inputSchema": { "type": "object", "properties": { "name": { "type": "string", "description": "Имя человека" }, "greeting": { "type": "string", "description": "Слово приветствия", "default": "Hello" }, "punctuation": { "type": "string", "description": "Знак препинания", "default": "!" } }, "required": ["name"] } }

Важно: Только name обязательный — у остальных есть значения по умолчанию.


#7. Обработка ошибок в инструментах

#Возврат ошибок

@mcp.tool() def safe_divide(a: float, b: float) -> float: """Безопасное деление с обработкой ошибок.""" if b == 0: raise ValueError("Деление на ноль невозможно") return a / b

Что видит LLM при ошибке:

{ "content": [ { "type": "text", "text": "Error: Деление на ноль невозможно" } ], "isError": true }

#Best practices обработки ошибок

@mcp.tool() def get_user_data(user_id: int) -> dict: """Получение данных пользователя.""" if user_id < 0: raise ValueError("user_id должен быть положительным") try: # Попытка получить данные data = database.get_user(user_id) if data is None: raise ValueError(f"Пользователь {user_id} не найден") return data except DatabaseError as e: # Логируем ошибку, но не показываем детали LLM logger.exception(f"Database error for user {user_id}") raise ValueError("Ошибка при получении данных")

Принципы:

  • ✅ Валидируйте входные параметры
  • ✅ Давайте понятные сообщения об ошибках
  • ✅ Не показывайте внутренние детали (стек трейс, SQL)
  • ✅ Логируйте ошибки для отладки

#8. Типы возвращаемых значений

#Простые типы

@mcp.tool() def get_name() -> str: return "Alice" @mcp.tool() def get_age() -> int: return 30 @mcp.tool() def get_price() -> float: return 19.99 @mcp.tool() def is_active() -> bool: return True

#Сложные типы

from typing import List, Dict @mcp.tool() def get_user(user_id: int) -> Dict: """Данные пользователя.""" return { "id": user_id, "name": "Alice", "email": "alice@example.com" } @mcp.tool() def list_users() -> List[Dict]: """Список всех пользователей.""" return [ {"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"} ]

#Форматирование вывода

@mcp.tool() def get_report() -> str: """Отчёт в читаемом формате.""" data = {"sales": 1000, "profit": 200} # Форматируем как текст return f""" Отчёт по продажам: ──────────────────── Продажи: {data['sales']}$ Прибыль: {data['profit']}$ Маржа: {data['profit'] / data['sales'] * 100:.1f}% """

#9. Resources: доступ к данным

Кроме инструментов, MCP серверы могут предоставлять ресурсы — данные для чтения.

#Простой ресурс

from mcp.server.fastmcp import FastMCP mcp = FastMCP("File MCP") @mcp.resource("config://app") def get_config() -> str: """Конфигурация приложения.""" return """ APP_NAME=MyApp VERSION=1.0.0 DEBUG=true """ @mcp.resource("file:///tmp/hello.txt") def read_hello_file() -> str: """Содержимое файла hello.txt.""" with open("/tmp/hello.txt", "r") as f: return f.read()

#URI схемы ресурсов

СхемаПримерОписание
file://file:///etc/hostsФайл в файловой системе
config://config://appКонфигурация (кастомная схема)
db://db://users/123Запись в базе данных
http://http://api.example.com/dataВнешний API

#Чтение ресурсов через Inspector

  1. Откройте вкладку "Resources"
  2. Нажмите на ресурс file:///tmp/hello.txt
  3. Увидите содержимое файла

#10. Prompts: шаблоны взаимодействия

Prompts — предустановленные шаблоны для частых сценариев.

#Простой промпт

@mcp.prompt() def code_review(code: str) -> str: """Шаблон для код-ревью.""" return f""" Пожалуйста, проверь этот код: ```python {code}

Обрати внимание на:

  1. Потенциальные баги
  2. Нарушения best practices
  3. Возможности для оптимизации
  4. Читаемость кода """

### Промпт с несколькими аргументами

```python
@mcp.prompt()
def write_test(function_name: str, function_code: str, test_framework: str = "pytest") -> str:
    """Шаблон для написания тестов."""
    return f"""
Напиши тесты для функции {function_name} используя {test_framework}:

```python
{function_code}

Тесты должны покрывать:

  • Обычный случай использования
  • Граничные значения
  • Ошибочные входные данные """

---

## 11. Полный пример: Weather MCP Server

Создадим сервер с инструментами, ресурсами и промптами:

```python
#!/usr/bin/env python3
"""MCP сервер с прогнозом погоды."""

from mcp.server.fastmcp import FastMCP
from datetime import datetime
import random

mcp = FastMCP("Weather MCP")


# === TOOLS ===

@mcp.tool()
def get_current_weather(city: str) -> str:
    """
    Получить текущую погоду в городе.
    
    Args:
        city: Название города
    """
    # Имитация API погоды
    conditions = ["Sunny", "Cloudy", "Rainy", "Partly Cloudy"]
    temp = random.randint(15, 30)
    condition = random.choice(conditions)
    
    return f"""
Погода в городе {city}:
🌡️ Температура: {temp}°C
☁️ Состояние: {condition}
💨 Ветер: {random.randint(0, 20)} км/ч
"""


@mcp.tool()
def get_forecast(city: str, days: int = 3) -> str:
    """
    Получить прогноз погоды на несколько дней.
    
    Args:
        city: Название города
        days: Количество дней (1-7)
    """
    if days > 7:
        raise ValueError("Максимум 7 дней")
    
    forecast = f"Прогноз для {city}:\n"
    conditions = ["☀️ Sunny", "☁️ Cloudy", "🌧️ Rainy", "⛅ Partly Cloudy"]
    
    for i in range(days):
        date = datetime.now().strftime(f"%d.%m")
        temp = random.randint(15, 30)
        condition = random.choice(conditions)
        forecast += f"  {date}: {temp}°C {condition}\n"
    
    return forecast


# === RESOURCES ===

@mcp.resource("weather://cities")
def get_supported_cities() -> str:
    """Список поддерживаемых городов."""
    return """
Поддерживаемые города:
- Moscow
- Saint Petersburg
- London
- New York
- Tokyo
"""


# === PROMPTS ===

@mcp.prompt()
def weather_advice(activity: str, city: str = "Moscow") -> str:
    """
    Получить рекомендации по активности с учётом погоды.
    
    Args:
        activity: Планируемая активность
        city: Город
    """
    return f"""
Я планирую {activity} в городе {city}.

Пожалуйста:
1. Проверь текущую погоду и прогноз на сегодня
2. Посоветуй, подходит ли погода для этой активности
3. Если погода плохая, предложи альтернативы
4. Рекомендуй, что взять с собой
"""


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

#Тестирование Weather MCP

Запрос через Claude:

Хочу пойти на пикник в Москве. Стоит ли?

Claude использует инструменты:

[Вызывает get_current_weather("Moscow")]
[Вызывает get_forecast("Moscow", 3)]

Судя по погоде (22°C, солнечно), сегодня отличный день для пикника!
Рекомендую взять: солнцезащитный крем, воду, плед...

#12. Отладка первого сервера

#Логирование

import logging import sys logging.basicConfig( level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', stream=sys.stderr ) logger = logging.getLogger(__name__) @mcp.tool() def debug_tool(value: str) -> str: logger.info(f"debug_tool called with: {value}") logger.debug("Processing...") return f"Processed: {value}"

#Проверка JSON-RPC сообщений

Запустите сервер вручную и отправьте запрос:

# Терминал 1: запуск сервера poetry run python hello_server.py # Терминал 2: отправка запроса echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}' | \ poetry run python hello_server.py

#13. Чеклист: первый сервер готов

  • Сервер запускается без ошибок
  • Инструменты отображаются в Inspector
  • Инструменты возвращают правильные результаты
  • Обработка ошибок работает корректно
  • Claude Desktop видит сервер
  • Claude использует инструменты в диалоге

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

КонцептОписание
FastMCPВысокоуровневый API для быстрого создания серверов
@mcp.tool()Декоратор для регистрации инструментов
@mcp.resource()Декоратор для регистрации ресурсов
@mcp.prompt()Декоратор для регистрации промптов
Type hintsИспользуются для генерации JSON Schema
DocstringsИспользуются для описания инструментов
MCP InspectorИнструмент для тестирования серверов

Следующая тема: Resources API — детально работа с ресурсами: шаблоны, подписки, бинарные данные.

Далее: Resources API