Newer
Older
vmk-360_data_mcp / README.md

VMK Data MCP Server

MCP-сервер (Model Context Protocol) для интеллектуального поиска по базе данных недвижимости vmk_data. Предоставляет AI-агентам (Claude, GPT и др.) безопасный набор инструментов для семантического и полнотекстового поиска объявлений с фильтрацией, пагинацией и сортировкой по релевантности.


📋 Содержание


Возможности

Функция Технология Описание
Семантический поиск pgvector + HNSW + Ollama Поиск объявлений «по смыслу» через векторную близость (cosine distance)
Полнотекстовый поиск PostgreSQL FTS (украинский конфиг) Поиск по ключевым словам с ранжированием по релевантности (ts_rank_cd)
Фильтрация метаданных SQL WHERE с параметрами Цена, район, комнаты, метро, тип сделки, статус и др.
Пагинация LIMIT / OFFSET Настраиваемый размер страницы (1–100)
Read-only безопасность default_transaction_read_only = on + валидация SQL Гарантированная защита от записи/изменения данных
Потоковый HTTP MCP Streamable HTTP Поддержка SSE-стрима + POST на порту 8080

Архитектура

┌─────────────────┐      HTTP (SSE+POST)      ┌──────────────────────────────┐
│   AI Агент      │  ───────────────────────>  │      VMK Data MCP Server      │
│  (Claude/GPT)   │      port 8080 /mcp       │      (FastMCP + Starlette)   │
└─────────────────┘                           └──────────────────────────────┘
                                                           │
                              ┌────────────────────────────┼────────────────────────────┐
                              │                            │                            │
                              ▼                            ▼                            ▼
                    ┌─────────────────┐          ┌─────────────────┐          ┌─────────────────┐
                    │   PostgreSQL   │          │    Ollama API   │          │   Логирование   │
                    │   vmk_data     │          │  nomic-embed-   │          │    (structlog)  │
                    │  + pgvector    │          │    text 768d    │          │                 │
                    └─────────────────┘          └─────────────────┘          └─────────────────┘

Поток данных при семантическом поиске

  1. Пользовательский запрос (на любом языке) переводится AI-агентом на украинский.
  2. MCP-сервер отправляет украинский текст в Ollama (/api/embed).
  3. Полученный вектор (768 float) передаётся в PostgreSQL как vector.
  4. pgvector выполняет поиск по HNSW-индексу: embedding <=> $1::vector <= $2.
  5. Результаты сериализуются в JSON и возвращаются агенту.

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

Сервер регистрирует 4 инструмента, доступных через MCP-протокол:

search_similar_listings

Векторный (семантический) поиск — находит объявления, близкие по смыслу к запросу.

Входные параметры:

  • query (string, обязательный) — текст на украинском для эмбеддинга
  • filters (object) — фильтры метаданных (см. Фильтры)
  • pagination (object)limit (1–100, по умолч. 20), offset (≥ 0)
  • min_similarity (float) — порог косинусной близости (0.0–1.0, по умолч. 0.7)

Выход: SearchResult — список объявлений с полем similarity_score.

⚠️ Параметр min_similarity преобразуется в максимальное косинусное расстояние: max_distance = 2.0 × (1.0 − min_similarity), потому что оператор <=> в pgvector возвращает расстояние в диапазоне [0, 2].


search_by_metadata

Полнотекстовый поиск (FTS) — ищет по ключевым словам в search_vector.

Входные параметры:

  • query (string, обязательный) — текстовый запрос на украинском
  • filters (object) — те же фильтры, что и для векторного поиска
  • pagination (object) — пагинация

Выход: SearchResult — список с полем rank_score (релевантность FTS).


get_listing_by_id

Получение объявления по ID — точечная выборка одной записи.

Входные параметры:

  • listing_id (integer, обязательный)id объявления

Выход: ListingResult или {"error": "..."} если не найдено.


describe_schema

Описание схемы БД — возвращает структуру таблицы property_listings (колонки, типы, индексы) для подсказок AI-агенту при формировании запросов.

Входных параметров нет.

Выход: JSON-описание схемы.


Модель данных

Таблица property_listings

Ключевые колонки, доступные для чтения (белый список USER_COLUMNS):

Колонка Тип Описание
id bigint Первичный ключ
title text Заголовок объявления
description text Описание
generated_description text AI-сгенерированное описание
price numeric Цена
currency varchar(3) Валюта: USD, EUR, UAH
deal_type varchar Тип сделки: sale, rent_long, rent_short
city varchar Город (украинский)
district varchar Район (украинский)
rooms_count int Количество комнат
total_area float Общая площадь, м²
living_area float Жилая площадь, м²
kitchen_area float Площадь кухни, м²
floor int Этаж
floors_count int Этажность дома
building_type varchar brick, panel, monolith, gas_block, wood
building_year int Год постройки
renovation_status varchar Статус ремонта
balcony_count int Количество балконов
bathroom_type varchar Тип санузла
parking_type varchar Тип парковки
heating_type varchar Тип отопления
layout_type varchar Тип планировки
window_view varchar Вид из окон
metro_station varchar Станция метро
metro_distance_type varchar walking, transport
metro_distance_meters int Расстояние до метро, м
url_source text Ссылка на источник
publish_date date Дата публикации
images_count int Количество фото
contact_phone varchar Телефон контакта
listing_status varchar active, sold, rented, removed, archived
archived_at date Дата архивации
created_at / updated_at date Служебные таймстампы
embedding vector(768) Вектор эмбеддинга (pgvector)
search_vector tsvector Полнотекстовый индекс (украинский конфиг)

Индексы базы данных

  • property_listings_embedding_idxHNSW на embedding (vector_cosine_ops)
  • property_listings_search_vector_idxGIN на search_vector

Быстрый старт

1. Клонирование и установка

git clone <repo-url>
cd data_mcp
python -m venv .venv
source .venv/bin/activate  # Linux/macOS
# .venv\Scripts\activate   # Windows
pip install -e "."

2. Настройка окружения

cp .env.example .env
# Отредактируйте .env — укажите DATABASE_URL и OLLAMA_BASE_URL

3. Запуск

python -m vmk_data_mcp.main
# или
uvicorn vmk_data_mcp.main:app --host 0.0.0.0 --port 8080

Сервер стартует на http://localhost:8080/mcp.


Конфигурация

Все параметры задаются через .env или переменные окружения:

Переменная По умолчанию Описание
DATABASE_URL postgresql://postgres:postgres@localhost:5432/vmk_data DSN для asyncpg
DB_POOL_MIN_SIZE 2 Минимум соединений в пуле
DB_POOL_MAX_SIZE 10 Максимум соединений в пуле
DB_QUERY_TIMEOUT 30 Таймаут SQL-запросов, сек
OLLAMA_BASE_URL http://192.168.1.75:11434 URL Ollama API
OLLAMA_EMBED_MODEL nomic-embed-text Модель эмбеддинга
OLLAMA_EMBED_DIMENSIONS 768 Размерность вектора
OLLAMA_REQUEST_TIMEOUT 60.0 Таймаут запроса к Ollama, сек
MCP_SERVER_NAME vmk-data-mcp Имя сервера в MCP
MCP_PORT 8080 Порт HTTP-транспорта

Развёртывание

Docker Compose (рекомендуется)

docker-compose up --build -d

docker-compose.yml использует host.docker.internal для доступа к PostgreSQL и Ollama, запущенным на хост-машине.

Linux: host.docker.internal требует extra_hosts: ["host.docker.internal:host-gateway"] (уже прописано в docker-compose.yml).

Требования к инфраструктуре

  • PostgreSQL 15+ с расширениями:
    CREATE EXTENSION IF NOT EXISTS vector;
    CREATE EXTENSION IF NOT EXISTS pg_trgm;  -- опционально
  • Ollama с моделью nomic-embed-text (768 dimensions):
    ollama pull nomic-embed-text
  • Для search_vector требуется украинская конфигурация FTS (либо simple, если украинский конфиг отсутствует — проверьте pg_ts_config).

Безопасность

Read-only гарантия

  1. На уровне соединения: каждое новое соединение получает SET default_transaction_read_only = on.
  2. На уровне строки: входящий SQL проверяется через _is_safe_query:
    • только префиксы select, with, values, explain
    • запрещён символ ; внутри строки (блокировка multi-statement атак)
  3. На уровне колонок: только USER_COLUMNS участвуют в SELECT; попытка запросить другую колонку вызывает ошибку.

SQL-инъекции

Все пользовательские данные передаются через параметризованные запросы ($1, $2 …). Ни один пользовательский параметр не интерполируется в строку SQL.


Разработка

Тесты

pytest -q

8 тестов покрывают:

  • границы пагинации (limit / offset)
  • валидацию фильтров
  • сериализацию моделей

Линтинг

ruff check src tests
ruff format src tests

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

data_mcp/
├── src/vmk_data_mcp/
│   ├── __init__.py
│   ├── main.py          # FastMCP сервер + HTTP transport
│   ├── tools.py         # Реализация 4 инструментов
│   ├── models.py        # Pydantic-модели входных/выходных данных
│   ├── db.py            # asyncpg пул, read-only защита, USER_COLUMNS
│   ├── embedder.py      # Ollama HTTP клиент для эмбеддингов
│   └── config.py        # Настройки из .env (pydantic-settings)
├── tests/
│   └── test_models.py   # Pytest
├── Dockerfile
├── docker-compose.yml
├── pyproject.toml
├── .env.example
└── README.md

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

Ollama недоступна

Сервис эмбеддингов недоступен: ConnectError(...)
  • Проверьте OLLAMA_BASE_URL
  • Убедитесь, что Ollama слушает на 0.0.0.0 (не только 127.0.0.1)
  • Проверьте firewall / Docker network

Нет результатов при семантическом поиске

  • Убедитесь, что запрос переведён на украинский перед вызовом инструмента.
  • Проверьте порог min_similarity — слишком высокий (0.95+) может исключить все записи.
  • Убедитесь, что в БД заполнена колонка embedding (не NULL).

PostgreSQL: отсутствует vector

CREATE EXTENSION vector;

Неправильная размерность эмбеддинга

Сервер ожидает OLLAMA_EMBED_DIMENSIONS=768 (модель nomic-embed-text). Если используется другая модель — обновите переменную окружения.


Лицензия

MIT