QuAzI

Custom Framework MCP

Community QuAzI
Updated

MCP‑сервер и краулер для документации Xafari

Custom Framework MCP

MCP-сервер для внутренней документации построенной на основе Markdown-документации. Строит легковесный индекс и предоставляет инструменты для поиска и объяснений.Так же включает crawler, который может скачивать документацию Xafari с официального сайта, извлекать чистый текст и примеры кода.

Зачем нужен MCP

MCP (Model Context Protocol) позволяет IDE и агентам обращаться к локальным даннымкак к «инструментам». Вместо ручного поиска по сайту документации, ассистентвызывает методы search_docs, get_page и get_examples, а сервер отвечаетструктурированными данными. Это ускоряет работу, дает воспроизводимые ответы иснижает зависимость от внешних источников.

Как MCP ускоряет работу:

  • Меньше ручного поиска: вместо переходов по сайту и копипасты — один вызов search_docs/get_page.
  • Мгновенная выборка: локальный индекс и кэш дают ответы быстрее, чем браузер + поиск.
  • Точнее ответы: инструменты возвращают структуру (заголовки, ссылки, код), а не разрозненный текст.
  • Повторяемость: один и тот же запрос даёт одинаковый результат — удобно для командной работы.
  • Автодогрузка: если страницы нет в кэше, get_page может скачать её автоматически.
  • Офлайн-режим: можно работать без доступа к сайту после первичного краула.

Как работает MCP в этом проекте

  • Краулер
    • Скачивает HTML, извлекает читабельный markdown и сохраняет в data/pages.
    • Кэширует страницы и использует ETag/Last-Modified при повторных запусках.
    • Из markdown строится индекс pages.json + index.json для быстрого поиска.
  • MCP-сервер читает индекс и отвечает на вызовы инструментов через stdio/http.
  • IDE подключается к серверу и использует инструменты прямо в чате.

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

  1. Запустить краулер и собрать локальный индекс:
    • npm run crawl
  2. Запустить MCP-сервер (stdio):
    • npm run start
  3. Запустить HTTP-режим (опционально):
    • npm run start:http
  4. Пересобрать индекс без краулинга:
    • npm run reindex

Переменные окружения

  • DOCS_BASE_URL (например: https://documentation.galaktika-soft.com/xafari/)
  • MAX_PAGES_PER_SESSION (по умолчанию: 10000)
  • FETCH_ON_MISS (по умолчанию: true, только если задан DOCS_BASE_URL)
  • DATA_DIR (по умолчанию: ./data)
  • REQUEST_TIMEOUT_MS (по умолчанию: 15000)
  • USER_AGENT
  • LOG_FILE (по умолчанию: logs/mcp.jsonl, путь относительно DATA_DIR)
  • LOG_STDOUT (по умолчанию: false) — если true, логи дублируются в stdout (удобно в Docker)
  • CODE_LANGUAGES (по умолчанию: cs,js,ts,json,yaml,xml,html,css)
  • HTTP_PORT (по умолчанию: 3333)
  • TOOLS_PREFIX — если задана (непустая), инструменты будут иметь имена вида ${TOOLS_PREFIX}search_docs, ${TOOLS_PREFIX}get_page, ...

Примеры кода

  • Примеры сохраняются только для языков из CODE_LANGUAGES.
  • Языки нормализуются: c#/csharpcs, javascriptjs, typescriptts, ymlyaml.
  • Если язык не разрешен — блок кода не сохраняется.

Fetch on miss

get_page может автоматически догружать страницу, если ее нет в кэше.Управляется флагом FETCH_ON_MISS (по умолчанию true если задан DOCS_BASE_URL).

Подключение MCP в IDE на примере Cursor

stdio-режим (локальный запуск)

  1. Откройте настройки MCP в Cursor.
  2. Добавьте новый сервер со следующими параметрами:
    • name: custom-framework-mcp
    • command: node
    • args: ["C:\\Projects\\custom-framework-mcp\\src\\index.js"]
    • cwd: C:\\Projects\\custom-framework-mcp

Пример ~/.cursor/mcp.json

{
  "mcpServers": {
    "custom-framework-mcp": {
      "command": "node",
      "args": ["C:\\Projects\\custom-framework-mcp\\src\\index.js"],
      "cwd": "C:\\Projects\\custom-framework-mcp"
    }
  }
}

stdio-режим (через Docker)

Если сервис запущен в Docker, можно использовать docker exec:

{
  "mcpServers": {
    "custom-framework-mcp": {
      "command": "docker",
      "args": ["exec", "-i", "mcp-service", "node", "/app/src/index.js"]
    }
  }
}

HTTP-режим (SSE)

Если сервис запущен в HTTP-режиме (например, через docker compose), используйте SSE transport:

{
  "mcpServers": {
    "custom-framework-mcp": {
      "url": "http://localhost:3333/sse"
    }
  }
}

Примечание: HTTP-режим требует, чтобы сервис был запущен с npm run start:http или через docker compose (который автоматически запускает HTTP-сервер).

  1. Перезапустите MCP-сервер в Cursor.

Чтобы проверить в окне чата напишите

list tools

Запросите какую-либо документацию с источника

Запуск через docker compose

git clone https://github.com/QuAzI/custom-framework-mcp.git
cd custom-framework-mcp
docker compose up -d

Запуск через npx

Локально в репозитории:

  • npm install
  • npx . — запустит MCP-сервер (stdio) через src/index.js.

Чтобы запускать из любого каталога:

  • npm link
  • npx --no-install custom-framework-mcp

Запуск прямо из GitHub (без публикации в npm):

  • npx github:QuAzI/custom-framework-mcp

Опции краулера:

  • npm run crawl — по умолчанию скачивает только новые страницы.
  • npm run crawl -- --force — перекачать все страницы.
  • npm run crawl -- --no-only-new — отключить режим "только новые".

Примечание:

  • --no-only-new делает полный обход с кешем (ETag/Last-Modified), а --force перекачивает все без учета кеша.

GitLab CI/CD (внешний репозиторий документации → индекс → деплой на VM)

В репозитории есть пример пайплайна .gitlab-ci.yml для сценария:

  • скачать документацию из внешнего git-репозитория
  • собрать индекс из markdown (npm run reindex, данные в DATA_DIR/pages)
  • задеплоить на VM по SSH и перезапустить docker compose, чтобы HTTP-сервер поднялся с актуальными pages.json/index.json

CI/CD variables (настраиваются в GitLab → Settings → CI/CD → Variables)

Переменные для скачивания документации:

  • DOCS_REPO_URL — URL внешнего репозитория документации (SSH или HTTPS)
  • DOCS_REF — ветка/тег (по умолчанию: main)
  • DOCS_SUBDIR — подкаталог в репозитории документации с markdown-деревом (по умолчанию: docs)
  • DOCS_SSH_PRIVATE_KEYопционально, SSH ключ для доступа к docs repo (если DOCS_REPO_URL по SSH)
  • DOCS_HTTP_TOKENопционально, токен для доступа по HTTPS (используется через ~/.netrc)
  • DOCS_HTTP_USERопционально, логин для ~/.netrc (по умолчанию: oauth2, удобно для GitLab)

Переменные для деплоя на VM:

  • DEPLOY_HOST — хост VM (DNS/IP)
  • DEPLOY_USER — пользователь на VM
  • DEPLOY_PATH — каталог на VM, где лежит сервис
  • DEPLOY_SSH_PRIVATE_KEY — SSH ключ для деплоя
  • DEPLOY_SSH_PORTопционально, порт SSH (по умолчанию: 22)
  • DEPLOY_COMPOSE_SERVICEопционально, имя сервиса compose (по умолчанию: mcp-service)
  • DEPLOY_HEALTHCHECK_URLопционально, URL для проверки после деплоя (например http://<host>:3333/health)

Ожидаемая структура на VM (DEPLOY_PATH)

Пайплайн предполагает, что на VM уже есть каталог сервиса с docker-compose.yml и исходниками (а CI обновляет только data/):

DEPLOY_PATH/
  docker-compose.yml
  package.json
  src/
  data/              # обновляется из CI (pages/, pages.json, index.json, assets/)

После доставки data.tgz CI выполняет:

  • docker compose up -d --remove-orphans
  • docker compose restart mcp-service (чтобы сервер перечитал индекс, т.к. он кэшируется в памяти процесса)

Расписание (Schedule)

Чтобы документация/индекс обновлялись регулярно:

  1. GitLab → CI/CD → Schedules → Create a new schedule
  2. Выберите ветку master
  3. Добавьте нужные variables (например DOCS_REPO_URL, DOCS_REF, DOCS_SUBDIR)

Job deploy_vm в .gitlab-ci.yml уже настроен так, чтобы запускаться только для master и schedule (и не запускаться в Merge Request pipeline).

MCP-инструменты

  • search_docs(query, limit?)
    • Ищет по индексу документации и возвращает список результатов с title, url, excerpt, headings.
    • limit ограничивает количество результатов (1–20, по умолчанию 5).
  • get_page(slug | url)
    • Возвращает полный контент страницы (markdown-текст, headings, codeBlocks, links, breadcrumbs).
    • slug — короткая форма (например, doc_recursive_helper).
    • url — полный адрес страницы документации.
  • get_examples(topic, limit?)
    • Ищет страницы по теме и извлекает фрагменты кода.
      • Делает search_docs(topic, limit) по индексу.
      • Берёт первые подходящие страницы и вытаскивает их codeBlocks.
      • Возвращает список примеров с slug, title, url, code.
    • limit ограничивает количество примеров (1–20, по умолчанию 5).
  • explain_concept(name)
    • Возвращает краткое описание концепта и ссылку на наиболее релевантную страницу.
      • Делает search_docs(name, 3).
      • Берёт самый релевантный результат и возвращает:
        • summary — это excerpt из результата,
        • page — основная ссылка,
        • related — оставшиеся 1–2 страницы.
    • В related добавляет похожие разделы документации.

stdio-режим

stdio — MCP-сервер общается с IDE через стандартные потоки ввода/вывода. Это нативный режим MCP: быстрее, проще в настройке, без сети и портов. Подходит для локального использования.

Транспорт и формат обмена:

  • Общение по stdin/stdout.
  • Формат: JSON-RPC 2.0, построчно или через Content-Length.
    • Построчно — каждое сообщение это одна JSON-строка, разделенная \n. Сервер читает строки и парсит каждую как отдельный JSON-RPC запрос.
    • Через Content-Length — перед сообщением идут заголовки (как в LSP). Сервер сначала читает длину, потом ровно столько байт JSON-тела.

Использовать можно не только из IDE, но и как локальную сервис-утилиту:

  • CLI/скрипты: можно запускать сервер и слать ему JSON-RPC из скриптов (например, на CI или для массового прогрева кэша).
  • Мост/прокси: stdio удобнее как backend для собственного HTTP-прокси — он проще, чем держать внутри сервера HTTP-слой.
  • Интеграции: другой агент/процесс может общаться с MCP через pipe/stdin-stdout, без открытого порта.
  • Безопасность: нет открытых портов, меньше требований к сетевой конфигурации.

Примеры stdio-запросов

{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "search_docs",
        "arguments": {
            "query": "Performance Enhancement"
        }
    }
}

HTTP-режим

http — режим, в котором MCP-сервер поднимает HTTP-endpoint и принимает запросы по сети. Удобно для внешних клиентов и инструментов (например, HTTPYac), но требует поднять отдельный процесс и порт.

  • Сервер поднимается командой npm run start:http (порт HTTP_PORT, по умолчанию 3333).
  • Каждый инструмент доступен через POST /tools/{toolName} с JSON-телом аргументов.
  • Для проверки доступен GET /health.

Примеры HTTP-запросов

Подходят для инструментов типа HTTPYac, плагинов HTTP Request в IDE.

POST http://localhost:3333/tools/search_docs
Content-Type: application/json

{
  "query": "Как работает модуль Performance Enhancement?",
  "limit": 5
}
POST http://localhost:3333/tools/search_docs
Content-Type: application/json

{
  "query": "подключение к DevExpress XAF",
  "limit": 5
}
POST http://localhost:3333/tools/get_page
Content-Type: application/json

{
  "slug": "doc_recursive_helper"
}
POST http://localhost:3333/tools/get_page
Content-Type: application/json

{
  "url": "https://documentation.galaktika-soft.com/xafari/doc_recursive_helper"
}
POST http://localhost:3333/tools/get_examples
Content-Type: application/json

{
  "topic": "Business Components",
  "limit": 5
}
POST http://localhost:3333/tools/explain_concept
Content-Type: application/json

{
  "name": "Security System"
}

Формат хранения

  • Сырые страницы сохраняются в data/pages/*.md с метаданными в заголовке.
  • pages.json формируется из markdown-файлов после завершения краулинга (по умолчанию это NDJSON: один JSON-объект на строку, чтобы файл можно было читать потоково даже при больших объёмах).
  • При сохранении учитываются breadcrumbs: страницы попадают в поддиректории по темам.
  • Ассеты (PDF/картинки) сохраняются в data/assets, ссылки в markdown остаются абсолютными.

Ручное пополнение документации

  1. Создайте .md в data/pages (подкаталоги = breadcrumbs).
  2. Добавьте YAML-front-matter с минимумом полей:
    ---
    slug: my_custom_doc
    url: https://example.local/my_custom_doc
    title: Мой документ
    breadcrumbs:
      - Custom
      - Docs
    ---
    
  3. Добавьте тело документа ниже фронт-маттера.
  4. Пересоберите индекс без краулинга:
    • npm run reindex

Логи

Структурированные логи пишутся в data/logs/mcp.jsonl (JSON Lines) при DATA_DIR=./data и дефолтном LOG_FILE=logs/mcp.jsonl.

MCP Server · Populars

MCP Server · New