Skip to main content
Glama
ASXRND

MCP Weather & Accruals Server

by ASXRND
README.md
# 🌤️ MCP Сервер Погоды с Deepseek

Простой MCP сервер для получения погоды через OpenWeatherMap API с использованием Deepseek API в качестве интерфейса и поддержкой модульной архитектуры.

## 📋 Что это делает?

- 🌍 Получает текущую погоду для любого города через OpenWeatherMap API
- 📅 Показывает прогноз погоды на несколько дней
- 🤖 Использует Deepseek для естественного общения и вызова инструментов с реальными данными
- 📦 Интегрирован с удалённой PostgreSQL базой и FastAPI для работы с данными о начислениях
- 🔧 Реализует протокол MCP для подключения AI к внешним данным
- 🏗️ Модульная архитектура с асинхронными операциями

## 📁 Структура проекта

```
OpenWeatherMap_MCP/
├── modules/                      # Пакет модулей приложения
│   ├── __init__.py              # Инициализация пакета модулей
│   ├── config.py                # Конфигурация (загрузка переменных окружения)
│   ├── weather_api.py           # Функции для работы с OpenWeatherMap API
│   ├── deepseek_api.py          # Функции для работы с Deepseek API
│   └── file_api.py              # Функции для файловых операций
├── fastapi_udalennii/            # Удалённый FastAPI проект (на другом хосте)
│   ├── app/
│   │   ├── main.py              # FastAPI приложение с endpoints
│   │   ├── models.py            # SQLAlchemy таблицы (users, accruals)
│   │   ├── schemas.py           # Pydantic схемы для валидации
│   │   ├── crud.py              # CRUD операции для БД
│   │   ├── db.py                # Подключение к БД
│   │   └── config.py            # Конфигурация
│   ├── alembic/                 # Миграции БД
│   │   └── versions/
│   │       ├── 0001_create_users_table.py
│   │       └── 0002_create_accruals_table.py
│   ├── requirements.txt          # Зависимости FastAPI
│   ├── .env                      # Конфиг БД для удалённого сервера
│   └── README.md                # Инструкции для удалённого FastAPI
├── deepseek_client.py            # Клиент для интерактивного чата с Deepseek
├── server.py                     # MCP сервер с инструментами погоды
├── test_project.py              # Тесты
├── .env                         # API ключи (не добавляйте в Git!)
├── requirements.txt             # Python зависимости для локального клиента
├── DEPLOYMENT_INSTRUCTIONS.md   # Инструкции по развёртыванию FastAPI
└── README.md                    # Эта инструкция
```

## 🚀 Быстрый старт

### 1. Установка зависимостей

```bash
# Создайте виртуальное окружение
python3 -m venv venv

# Активируйте его
# На macOS/Linux:
source venv/bin/activate
# На Windows:
venv\Scripts\activate

# Установите зависимости
pip3 install -r requirements.txt
```

### 2. Настройка API ключей и подключений

Создайте файл `.env` в корне проекта:

```bash
# ===== OpenWeatherMap =====
OPENWEATHER_API_KEY=ваш_ключ_здесь
OPENWEATHER_BASE_URL=https://api.openweathermap.org/data/2.5

# ===== Deepseek =====
DEEPSEEK_API_KEY=ваш_ключ_здесь

# ===== Database (PostgreSQL) =====
DATABASE_URL=postgresql://username:password@192.168.0.134:5432/mydb

# ===== Accruals API (Remote FastAPI) =====
ACCRUALS_API_URL=http://192.168.0.137:8000

# ===== File Operations =====
ALLOWED_BASE_DIR=/path/to/allowed/dir

# ===== Logging =====
LOG_LEVEL=INFO
```

**Получение API ключей:**

- **OpenWeatherMap**:

  1. Зарегистрируйтесь на https://openweathermap.org
  2. Перейдите в раздел API Keys
  3. Скопируйте ключ (бесплатный план: 1000 запросов/день)

- **Deepseek**:
  1. Зарегистрируйтесь на https://platform.deepseek.com
  2. Создайте новый API ключ
  3. Пополните баланс (бесплатный кредит ~$5)

### 3. Запуск Deepseek клиента

```bash
python3 deepseek_client.py
```

### 4. (Опционально) Работа через удалённый API для начислений

Deepseek может запрашивать данные о начислениях через REST API (FastAPI) — если у вас уже развернут удалённый API, укажите его базовый URL в переменной `ACCRUALS_API_URL`.

```
ACCRUALS_API_URL=http://192.168.0.137:8000
```

Убедитесь, что удалённая база и API содержат необходимые данные — локальные утилиты для загрузки Excel (`modules/db_loader.py`) удалены из репозитория. После настройки `ACCRUALS_API_URL` Deepseek сможет запрашивать статистику и списки начислений у удалённого сервера.

Теперь в клиенте Deepseek можно спрашивать о начислениях (см. примеры ниже).

## 💬 Примеры использования

### Работа с погодой

После запуска `deepseek_client.py` просто спрашивайте о погоде на естественном языке:

```
👤 Вы: Какая погода в Москве?
🤖 Deepseek: [Проверяет текущую погоду в Москве через API и показывает результат]

👤 Вы: А какой прогноз на 5 дней для Санкт-Петербурга?
🤖 Deepseek: [Показывает прогноз на 5 дней]

👤 Вы: Что лучше надеть в Лондоне сегодня?
🤖 Deepseek: [Проверяет погоду и дает рекомендации]

👤 Вы: выход
👋 До свидания!
```

### Работа с данными о начислениях (Ozon)

После запуска API (см. раздел "Запуск API для работы с БД") можно запрашивать данные:

```
👤 Вы: Покажи статистику по начислениям
🤖 Deepseek: [Запрашивает /stats/summary и показывает общую сводку: кол-во записей, платформы, типы]

👤 Вы: Сколько начислений по услугам доставки?
🤖 Deepseek: [Запрашивает /stats/accruals?service_group=Услуги+доставки и показывает статистику]

👤 Вы: Покажи список последних начислений с платформы Ozon
🤖 Deepseek: [Запрашивает /accruals?sales_platform=Ozon&limit=50 и показывает записи]

👤 Вы: выход
👋 До свидания!
```

## 🔧 Описание модулей

### `modules/config.py`

**Отвечает за:** конфигурацию приложения, загрузку переменных окружения, валидацию ключей API.

**Основные компоненты:**

- `Config` - класс с константами конфигурации
- `validate()` - проверяет наличие критических переменных окружения
- `get_config_summary()` - возвращает сводку конфигурации для логирования

### `modules/weather_api.py`

**Отвечает за:** взаимодействие с OpenWeatherMap API для получения данных о погоде.

**Основные функции:**

- `make_weather_request()` - вспомогательная функция для HTTP запросов к API
- `get_current_weather()` - получает текущую погоду для города
- `get_forecast()` - получает прогноз на несколько дней
- `format_day_forecast()` - форматирует прогноз на один день

### `modules/deepseek_api.py`

**Отвечает за:** взаимодействие с Deepseek API для обработки запросов пользователя с использованием инструментов (функций).

**Основные функции:**

- `get_weather_tools()` - возвращает определение инструментов для Deepseek
- `call_deepseek_with_tools()` - вызывает Deepseek с поддержкой инструментов (function calling)
- `process_deepseek_response()` - обрабатывает ответ от Deepseek, выполняет вызовы инструментов
- `get_weather_response()` - главная функция для получения ответа о погоде

**Поддерживаемые инструменты:**

- Погода: `get_current_weather`, `get_forecast`
- Файлы: `read_file`, `create_file`, `update_file`, `append_to_file`, `delete_file`, `list_files`

### `modules/file_api.py`

**Отвечает за:** безопасную работу с файлами по определённому пути.

**Основные функции:**

- `read_file()` - чтение содержимого файла
- `create_file()` - создание нового файла
- `update_file()` - обновление содержимого файла
- `append_to_file()` - добавление содержимого в файл
- `delete_file()` - удаление файла
- `list_files()` - просмотр содержимого директории
- `is_path_safe()` - проверка безопасности пути (предотвращает path traversal атаки)

**Примеры команд для Deepseek:**

- "Создай файл test.txt с текстом 'Hello World'"
- "Прочитай содержимое файла README.md"
- "Обнови файл config.py на новый код"
- "Покажи список файлов в папке modules"
- "Добавь новую строку в файл notes.txt"
- "Удали временный файл temp.txt"

### `server.py`

**Отвечает за:** запуск MCP сервера с инструментами для интеграции с другими приложениями.

**Основные инструменты MCP:**

- `current_weather()` - инструмент для получения текущей погоды
- `weather_forecast()` - инструмент для получения прогноза

**Для запуска только MCP сервера (для интеграции с другими приложениями):**

```bash
uv run mcp dev server.py
```

### Удалённые локальные модули

Ранее в репозитории были утилиты для локальной загрузки данных и локальный API:

- `modules/db.py` — локальная SQLAlchemy модель и хелперы для создания таблиц
- `modules/db_loader.py` — скрипт загрузки Excel (pandas → БД)
- `modules/api.py` — FastAPI приложение для доступа к данным о начислениях

Эти файлы удалены из текущего репозитория в пользу использования удалённых сервисов (базы данных и API). Если вам нужно восстановить локальную загрузку или локальный API, можно восстановить соответствующие модули и добавить в `requirements.txt` зависимости: `pandas`, `openpyxl`, `sqlalchemy`, `psycopg2-binary`, `uvicorn`.

### `deepseek_client.py`

**Отвечает за:** главную точку входа приложения - интерактивный чат с пользователем.

**Основные функции:**

- `chat_with_deepseek()` - интерактивный цикл чата с естественным языком
- `main()` - инициализация и запуск приложения

**Для запуска полного приложения:**

```bash
python3 deepseek_client.py
```

Это команда, которая вам нужна! Она запускает интерактивный чат с Deepseek, который использует реальные данные о погоде из OpenWeatherMap API и может запрашивать данные о начислениях (если API запущен).

## 🌐 Схема взаимодействия

```
Пользователь
    ↓
deepseek_client.py (chat_with_deepseek)
    ↓
modules/deepseek_api.py (get_weather_response)
    ↓
Deepseek API
    ├─ Анализирует запрос
    └─ Вызывает инструменты (function calling)
         ↓
    modules/weather_api.py
         ├─ get_current_weather()
         └─ get_forecast()
              ↓
         OpenWeatherMap API
              ↓
         Возвращает реальные данные о погоде
    ↓
Deepseek API (обработка результатов инструментов)
    ↓
Финальный ответ пользователю
```

## 🔌 Добавление новых функций

Чтобы добавить новый инструмент (например, получение качества воздуха):

1. **Добавьте функцию в модуль `modules/weather_api.py`:**

```python
async def get_air_quality(city: str) -> str:
    """Получить качество воздуха для города"""
    # Реализация...
    return result
```

2. **Добавьте определение инструмента в `modules/deepseek_api.py`:**

```python
def get_weather_tools() -> List[Dict[str, Any]]:
    tools = [
        # ... существующие инструменты ...
        {
            "type": "function",
            "function": {
                "name": "get_air_quality",
                "description": "Получить качество воздуха",
                # ... параметры ...
            }
        }
    ]
    return tools
```

3. **Добавьте обработку в `process_deepseek_response()`:**

```python
if tool_name == "get_air_quality":
    result = await get_air_quality(tool_args.get("city"))
```

4. **Добавьте инструмент в MCP сервер `server.py`:**

```python
@mcp.tool()
async def air_quality(city: str) -> str:
    """Инструмент MCP для получения качества воздуха"""
    return await get_air_quality(city)
```

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

Приложение использует встроенный модуль `logging` для отслеживания всех операций. Логи записываются в файл `app.log` и выводятся в консоль.

**Уровни логирования:**

- `DEBUG` - подробная информация для отладки
- `INFO` - основная информация о работе
- `WARNING` - предупреждения
- `ERROR` - ошибки
- `CRITICAL` - критические ошибки

Уровень логирования можно настроить через переменную окружения `LOG_LEVEL` в `.env`.

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

Если хотите протестировать MCP сервер без клиента:

```bash
# Используйте MCP Inspector
uv run mcp dev server.py

# Или установите в Claude Desktop
uv run mcp install server.py --name "Weather Service"
```

## 🐛 Поиск и решение проблем

### Ошибка: "OPENWEATHER_API_KEY не найден"

**Решение:** Убедитесь, что файл `.env` находится в корне проекта и содержит `OPENWEATHER_API_KEY=ваш_ключ`

### Ошибка: "Не удалось получить погоду для города"

**Решение:**

- Проверьте написание названия города
- Убедитесь, что у вас есть интернет подключение
- Проверьте, не исчерпан ли лимит бесплатного плана OpenWeatherMap

### Ошибка: "Ошибка при обращении к Deepseek API"

**Решение:**

- Проверьте, что DEEPSEEK_API_KEY скопирован правильно
- Убедитесь, что на вашем счёте есть баланс для API запросов
- Проверьте статус Deepseek API на https://status.deepseek.com/

## 📝 Лицензия

Этот проект лицензирован под MIT License.

## 🤝 Контрибьютинг

Приветствуются pull requests! Для больших изменений сначала откройте issue для обсуждения.

## 🛠️ Доступные инструменты

### `get_current_weather`

Получает текущую погоду для города

**Параметры:**

- `city` (обязательный): Название города
- `units` (опционально): "metric" или "imperial"

### `get_forecast`

Получает прогноз погоды на несколько дней

**Параметры:**

- `city` (обязательный): Название города
- `days` (опционально): Количество дней (1-5)
- `units` (опционально): "metric" или "imperial"

## 🌐 Архитектура с удалённым FastAPI

Проект использует **двухуровневую архитектуру**:

### Локальный слой (ваша машина)

- **deepseek_client.py** - интерактивный чат с Deepseek
- **modules/deepseek_api.py** - интеграция с Deepseek для обработки запросов
- **modules/weather_api.py** - получение данных о погоде
- **modules/file_api.py** - файловые операции

### Удалённый слой (другой хост 192.168.0.137:8000)

- **fastapi_udalennii/app/main.py** - REST API для работы с начислениями (accruals)
- **fastapi_udalennii/app/models.py** - SQLAlchemy таблицы (users, accruals)
- **fastapi_udalennii/app/crud.py** - операции БД
- **fastapi_udalennii/app/schemas.py** - валидация данных (Pydantic)

### База данных (PostgreSQL)

- Хост: 192.168.0.134:5432
- База: mydb
- Пользователь: asx

### Схема взаимодействия:

```
Пользователь
    ↓
deepseek_client.py
    ↓
Deepseek API (обработка запроса)
    ├─ Погода → modules/weather_api.py → OpenWeatherMap API
    ├─ Файлы → modules/file_api.py → локальная ФС
    └─ Начисления → httpx HTTP запрос → fastapi_udalennii (192.168.0.137:8000)
         ├─ GET /accruals/ → fastapi_udalennii/app/crud.py → PostgreSQL
         ├─ GET /stats/summary → fastapi_udalennii/app/crud.py → PostgreSQL
         └─ POST /accruals/ → fastapi_udalennii/app/crud.py → PostgreSQL
    ↓
Deepseek API (формирует ответ)
    ↓
Пользователю
```

### Новые endpoints в FastAPI:

После развёртывания на удалённом сервере (см. `DEPLOYMENT_INSTRUCTIONS.md`) доступны:

**Accruals endpoints:**

- `POST /accruals/` - создание новой записи о начислении
- `GET /accruals/` - получение списка с фильтрацией

**Stats endpoints:**

- `GET /stats/summary` - общая статистика по всем начислениям
- `GET /stats/accruals` - статистика с фильтрацией

**Примеры запросов:**

```bash
# Получить все начисления
curl http://192.168.0.137:8000/accruals/

# Получить начисления по платформе Ozon
curl "http://192.168.0.137:8000/accruals/?sales_platform=Ozon&limit=50"

# Получить статистику
curl http://192.168.0.137:8000/stats/summary

# Создать новое начисление
curl -X POST http://192.168.0.137:8000/accruals/ \
  -H "Content-Type: application/json" \
  -d '{
    "id_accrual": "ACC001",
    "accrual_date": "2025-12-08",
    "service_group": "Доставка",
    "accrual_type": "Комиссия",
    "sales_platform": "Ozon",
    "total_amount_rub": 1234.56
  }'
```

## ⚙️ Развёртывание и обновления

Для развёртывания обновлённого FastAPI на удалённом сервере смотрите инструкции в `DEPLOYMENT_INSTRUCTIONS.md`.

Краткая схема:

1. Синхронизация кода через `rsync`
2. Активация venv на удалённом сервере
3. Установка зависимостей (если добавлены новые)
4. Запуск миграций Alembic
5. Перезагрузка FastAPI сервиса

## ⚠️ Важные замечания

1. **Не используйте `print()` в server.py** - это сломает STDIO транспорт
2. **Храните `.env` в безопасности** - добавьте в `.gitignore`
3. **Лимиты API**:
   - OpenWeatherMap Free: 1000 запросов/день
   - Deepseek: зависит от вашего плана
4. **Стоимость Deepseek**: Более дешевая чем OpenAI
5. **Миграции БД**: После обновления FastAPI кода обязательно запустите `alembic upgrade head`

## 🐛 Решение проблем

**Ошибка: "OPENWEATHER_API_KEY не найден"**

- Проверьте, что файл `.env` создан и содержит ключ
- Убедитесь, что файл находится в той же папке, что и скрипты

**Ошибка: "Не удалось получить погоду"**

- Проверьте правильность написания города
- Попробуйте английское название города

**Сервер не запускается**

- Убедитесь, что виртуальное окружение активировано
- Проверьте, что все зависимости установлены

## 📚 Полезные ссылки

- [MCP Documentation](https://modelcontextprotocol.io/)
- [OpenWeatherMap API](https://openweathermap.org/api)
- [Канал "Черный треугольник"](https://t.me/black_triangle_tg)