Skip to main content
Glama
arptra

local-corporate-kb

by arptra

Локальная корпоративная база знаний для Qwen Code

Это локальный MVP корпоративного RAG: документы индексируются Python-процессом, embeddings сохраняются в проверяемый файловый кэш, а при поиске целиком находятся в RAM. Qwen Code остаётся единственной генеративной моделью и получает найденные фрагменты через read-only MCP tools по локальному stdio или удалённому Streamable HTTP. MCP-сервер не формулирует финальные ответы, не исполняет shell-команды и не изменяет документы.

Проект рассчитан на Python 3.12 и standalone FastMCP==3.4.4. Запуск после установки не зависит от uv: все runtime-скрипты вызывают Python из .venv напрямую. Для разработки доступна воспроизводимая установка через uv.lock, а для корпоративных машин — отдельная установка через обычный pip.

Отдельные пошаговые инструкции:

Архитектура

Confluence export
       ↓
knowledge/*.md, *.html, *.txt
       ↓
loader + normalizer + structural chunker
       ↓
local feature hashing (по умолчанию) или локальная embedding-модель
       ↓
NumPy matrix in RAM
       ↓
MCP stdio / Streamable HTTP
       ↓
Qwen Code CLI

В удалённом режиме тот же индекс один раз загружается в память серверного процесса, после чего к нему одновременно подключаются Qwen Code CLI с разных машин:

Qwen CLI ─┐
Qwen CLI ─┼─ HTTPS / Bearer token ─ MCP Streamable HTTP ─ in-memory index
Qwen CLI ─┘

DocumentLoader безопасно обходит только KB_KNOWLEDGE_DIR, нормализует Markdown/TXT и переводит экспортированный HTML в Markdown-подобный текст. StructuralChunker сохраняет путь заголовков, списки, таблицы и code fences. KnowledgeService координирует кэш и работает только через интерфейс KnowledgeStore; MCP-слой не знает о NumPy.

В RAM находятся документы, чанки, отображение chunk_id -> index и нормализованная NumPy-матрица [chunk_count, embedding_dimension]. Cosine similarity считается как matrix @ query_vector.

На диске в .cache/kb/ находятся только:

  • manifest.json — версии схемы, идентичность модели, chunking config и knowledge hash;

  • documents.json — нормализованные документы и metadata;

  • chunks.json — чанки без отдельной копии embedding;

  • embeddings.npy — матрица без pickle.

Это не Vector DB: нет отдельного сервиса хранения, индекса ANN или SQL. Удалённый HTTP — только read-only MCP-фасад; поиск выполняется полным cosine scan по NumPy-матрице в памяти, а диск используется для ускорения старта.

Related MCP server: sage-mcp

Первый запуск

Подключение сотрудника к удалённой базе

RAG, индекс и документы находятся только на сервере. Для старых версий Qwen сотруднику передаётся один файл clients/corporate_kb_stdio_proxy.py. Qwen запускает его локально через uv как stdio MCP, а Python-процесс ходит к удалённому серверу через обычные HTTP GET-запросы. Node.js, npx, mcp-remote, Nginx, копия проекта, .venv, документы и индекс на клиенте не нужны.

Готовый settings находится в examples/qwen-uv-stdio-settings.example.json, а полная инструкция для сотрудника — в README.client.md.

Новые версии Qwen также могут подключаться к /mcp напряму через Streamable HTTP; скрипт install.sh оставлен как опциональный способ для таких клиентов. Скопируйте из неё mcpServers в ~/.qwen/settings.json и замените четыре placeholder:

  • REPLACE_WITH_ABSOLUTE_UV_PATH — результат which uv или where uv (в Windows uv.exe);

  • REPLACE_WITH_ABSOLUTE_PATH — каталог, в котором сотрудник сохранил единственный .py-файл;

  • REPLACE_WITH_SERVER_IP_OR_DOMAIN — адрес удалённого сервера;

  • REPLACE_WITH_SERVER_TOKEN — Bearer-токен.

Qwen запускает этот файл как локальный MCP по stdio командой uv run. Скрипт содержит inline dependency на FastMCP, поэтому uv сам создаёт изолированное кэшированное окружение. Локальный MCP обращается к удалённому RAG только через обычные авторизованные JSON GET endpoints /api/v1/*. node, npx, mcp-remote, локальная копия документов и локальный индекс не нужны.

Установка серверной части

Убедитесь, что доступен Python 3.12. На корпоративной машине рекомендуется pip-вариант: он не читает uv.lock, не запускает uv и не зависит от установленной в системе версии uv. Hugging Face, PyTorch и sentence-transformers в базовую установку не входят:

./scripts/setup-pip.sh
source ./scripts/activate-venv.sh

Для разработки с точными версиями из lock-файла остаётся вариант:

./scripts/setup-venv.sh
source ./scripts/activate-venv.sh

Оба варианта создают одинаковую .venv; runtime-команды используют только .venv/bin/python.

Полностью локальный режим по умолчанию использует hash provider и не требует модели или сети:

./scripts/dev.sh index-hash
./scripts/dev.sh search-hash

Hash provider строит локальные lexical vectors из слов и символьных триграмм. Он пригоден для полностью автономного поиска по совпадающей терминологии, но не понимает смысл и синонимы так же хорошо, как semantic embedding model.

Для качественного semantic search сначала положите заранее полученные и одобренные model files в локальный каталог. Этот проект не скачивает их. Например:

models/Qwen3-Embedding-0.6B/

После этого активируйте окружение, укажите только локальный путь и постройте индекс:

./scripts/dev.sh install-pip-semantic
source ./scripts/activate-venv.sh
export KB_EMBEDDING_PROVIDER=sentence_transformers
export KB_EMBEDDING_MODEL="$KB_PROJECT_ROOT/models/Qwen3-Embedding-0.6B"
export KB_EMBEDDING_LOCAL_FILES_ONLY=true

./scripts/dev.sh index-semantic
./scripts/dev.sh search "Какой сервис владеет дневными лимитами?"

local_files_only=true, HF_HUB_OFFLINE=1 и TRANSFORMERS_OFFLINE=1 запрещают обращения к Hugging Face. Если model files отсутствуют, индексирование завершится понятной ошибкой без попытки скачивания. По умолчанию выбирается CUDA, затем MPS, затем CPU.

scripts/start-mcp.sh по умолчанию запускает MCP с KB_EMBEDDING_PROVIDER=hash, поэтому обычное подключение Qwen полностью offline. Для локальной semantic-модели явно передайте provider и путь в environment Qwen-конфигурации. Все runtime wrappers вызывают Python из готовой .venv напрямую: после установки они не обращаются к package registry и не меняют окружение.

CLI

./.venv/bin/python -m corporate_kb.cli index
./.venv/bin/python -m corporate_kb.cli index --force
./.venv/bin/python -m corporate_kb.cli search "Как рассчитывается дневной лимит?" --top-k 5
./.venv/bin/python -m corporate_kb.cli search "Как рассчитывается дневной лимит?" --service limits-service
./.venv/bin/python -m corporate_kb.cli documents
./.venv/bin/python -m corporate_kb.cli stats
./.venv/bin/python -m corporate_kb.cli eval --top-k 5

У search, documents, stats и eval есть --json. В этом режиме stdout содержит только JSON, а логи остаются в stderr.

Если кэша нет или он несовместим, обычный поиск при KB_AUTO_INDEX=false завершится практичным сообщением Run: ./scripts/dev.sh index. Это предотвращает неожиданную сетевую активность во время MCP discovery.

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

Если MCP-серверы хранятся в отдельном каталоге, установите туда автономную runtime-копию. Скрипт создаёт подкаталог corporate-kb, копирует только необходимые файлы, создаёт собственный .venv, ставит locked runtime dependencies без dev-пакетов, строит hash-индекс и печатает готовый server entry для Qwen:

./scripts/install-mcp-server.sh /absolute/path/to/mcp-servers

Если версия uv на целевой машине отличается или uv запрещён политиками, установите ту же runtime-копию через pip:

./scripts/install-mcp-server.sh /absolute/path/to/mcp-servers --pip

Для закрытого окружения можно сначала только скопировать файлы, затем настроить корпоративный Python package registry и завершить установку командами, которые напечатает скрипт:

./scripts/install-mcp-server.sh /absolute/path/to/mcp-servers --copy-only

Скопируйте examples/qwen-settings.example.json в .qwen/settings.json проекта и замените все /ABSOLUTE/PATH/... реальными абсолютными путями. Не рассчитывайте на раскрытие ${PROJECT_ROOT} в JSON. В command указан абсолютный путь к .venv/bin/python, а в args — запуск модуля corporate_kb.mcp.server. Поэтому Qwen не зависит от глобальных python, uv, PATH, shell activation или wrapper-скрипта.

Минимальная форма server entry:

{
  "command": "/absolute/path/to/repository/.venv/bin/python",
  "args": ["-m", "corporate_kb.mcp.server"],
  "cwd": "/absolute/path/to/repository",
  "env": {
    "PYTHONPATH": "/absolute/path/to/repository/src"
  }
}

Альтернатива через CLI (выполняйте из корня этого репозитория, подставив абсолютные пути):

qwen mcp add \
  --scope project \
  --timeout 120000 \
  --include-tools kb_search,kb_get_document,kb_list_documents,kb_stats \
  -e KB_KNOWLEDGE_DIR=/absolute/path/to/repository/knowledge \
  -e KB_CACHE_DIR=/absolute/path/to/repository/.cache/kb \
  -e KB_EMBEDDING_PROVIDER=hash \
  -e KB_EMBEDDING_LOCAL_FILES_ONLY=true \
  -e HF_HUB_OFFLINE=1 \
  -e TRANSFORMERS_OFFLINE=1 \
  -e PYTHONUNBUFFERED=1 \
  -e PYTHONNOUSERSITE=1 \
  -e PYTHONPATH=/absolute/path/to/repository/src \
  -e KB_AUTO_INDEX=false \
  local-corporate-kb \
  /absolute/path/to/repository/.venv/bin/python \
  -m corporate_kb.mcp.server

stdio — транспорт по умолчанию, поэтому --transport http здесь не нужен. Синтаксис команды сверен с официальной документацией Qwen Code, но в среде разработки этого репозитория qwen не был установлен, и команда локально не выполнялась. JSON-конфигурация также задаёт cwd, trust: false и клиентский фильтр из четырёх tools.

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

qwen
/mcp

Тестовый запрос:

Используй corporate knowledge MCP.
Найди, какой сервис владеет дневными лимитами,
объясни правило и обязательно укажи использованные источники.

Сервер предоставляет только:

  • kb_search — поиск с top_k, min_score и metadata filters;

  • kb_get_document — полный нормализованный документ по document_id;

  • kb_list_documents — metadata документов без embeddings;

  • kb_stats — состояние индекса и абсолютные пути.

Ручной запуск stdio server:

KB_LOG_LEVEL=DEBUG ./.venv/bin/python -m corporate_kb.mcp.server

stdout зарезервирован для MCP-протокола; все application logs направляются в stderr.

Удалённый MCP по HTTP

Удалённый режим заранее загружает готовый индекс и только после этого открывает порт. Поэтому все подключённые Qwen CLI используют один прогретый процесс и не строят embeddings при каждом запросе. Endpoint реализует рекомендованный для удалённых MCP-серверов Streamable HTTP, а не устаревший SSE.

1. Подготовить сервер

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

cd /opt/corporate-kb
./scripts/setup-pip.sh --no-dev
./scripts/dev.sh index-hash

Сгенерируйте отдельный секрет длиной не менее 32 символов:

openssl rand -hex 32

Для прямого запуска внутри доверенной сети или VPN задайте секрет и запустите listener на всех сетевых интерфейсах:

export KB_MCP_HTTP_BEARER_TOKEN='PASTE_GENERATED_TOKEN'
export KB_MCP_HTTP_HOST='0.0.0.0'
export KB_MCP_HTTP_PORT='8000'
export KB_AUTO_INDEX='false'

./scripts/start-mcp-http.sh

Публичный health check не раскрывает тексты документов:

curl http://10.0.0.5:8000/health

Для stdio-клиента сервер также предоставляет защищённый read-only JSON API. Например, проверка поиска использует обычный GET и тот же Bearer-токен:

curl -G 'http://10.0.0.5:8000/api/v1/search' \
  -H 'Authorization: Bearer PASTE_GENERATED_TOKEN' \
  --data-urlencode 'query=какой сервис владеет дневными лимитами' \
  --data-urlencode 'top_k=5'

Доступны /api/v1/search, /api/v1/document, /api/v1/documents и /api/v1/stats. Они используют тот же прогретый индекс, что и MCP tools, не строят embeddings на клиенте и не изменяют документы.

Сам /mcp требует заголовок Authorization: Bearer .... Ограничения по Host, Origin, домену или IP нет: сервер принимает клиента с любого адреса, если передан правильный токен. KB_AUTO_INDEX=false гарантирует, что удалённый процесс не начнёт неожиданную переиндексацию.

Проверяйте с клиентской машины не только /health, но и настоящий MCP initialize:

curl -i --max-time 15 \
  'http://10.0.0.5:8000/mcp' \
  -H 'Authorization: Bearer PASTE_GENERATED_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  --data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl-test","version":"1.0"}}}'

Ожидается HTTP/1.1 200. 401 означает неверный токен, 404 — неверный путь, а 421 — что запущена старая сборка с Host allowlist. Прямой FastMCP listener, запущенный через Python или uv, использует обычный HTTP. https:// указывайте только при наличии TLS reverse proxy; иначе Qwen обычно сообщает TypeError: fetch failed.

2. Подключить Qwen CLI

Перед раздачей впишите в корневой install.sh публичный HTTPS-адрес сервера и созданный токен:

default_mcp_url="https://kb.company.example/mcp"
default_mcp_token="THE_SERVER_TOKEN"

Сотруднику передаётся только этот один файл. В любом каталоге он выполняет:

bash install.sh

Скрипт не скачивает репозиторий, документы или Python-зависимости и не создаёт каталог RAG. Он только добавляет подключение corporate-kb в пользовательскую конфигурацию уже установленного Qwen Code. После запуска сотрудник перезапускает qwen и проверяет соединение через /mcp.

Bearer-токен внутри готового скрипта является секретом: раздавайте файл через защищённый корпоративный канал. Для отзыва доступа замените токен на сервере и выпустите новый скрипт.

3. Доступ через интернет

Не передавайте Bearer-токен по открытому интернету через обычный HTTP. Оставьте backend на 127.0.0.1:8000, а наружу опубликуйте его как HTTPS через Nginx, Caddy, ingress или корпоративный API gateway:

export KB_MCP_HTTP_BEARER_TOKEN='PASTE_GENERATED_TOKEN'
export KB_MCP_HTTP_HOST='127.0.0.1'
./scripts/start-mcp-http.sh

Минимальные существенные параметры location для Nginx:

location /mcp {
    proxy_pass http://127.0.0.1:8000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    proxy_read_timeout 3600s;
}

После этого клиент подключается к https://kb.example.com/mcp. TLS-сертификат и сетевой доступ настраиваются на reverse proxy; порт 8000 не должен быть открыт наружу.

Когда документы изменились, выполните ./scripts/dev.sh index-hash и перезапустите HTTP-процесс. Уже работающий процесс намеренно продолжает обслуживать согласованную старую версию индекса до рестарта.

Добавление Confluence-страницы

Экспортируйте страницу в HTML либо сохраните её как Markdown и положите внутрь knowledge/. Поддерживаются .md, .markdown, .html, .htm, .txt. Скрытые каталоги, .git, .cache, __pycache__, node_modules, бинарные и неподдерживаемые файлы игнорируются. После изменения перестройте индекс; при обычном запуске несовпадение knowledge_hash также инвалидирует кэш.

Пример front matter:

---
document_type: service
service: limits-service
domain: payments
status: current
authority: confluence
authority_priority: 80
owner: limits-team
source_id: "confluence-12345"
source_url: "https://confluence.example.com/pages/12345"
last_reviewed: "2026-07-20"
custom_field: "неизвестные поля тоже сохраняются"
---

# Limits Service

Без front matter заголовок берётся из первого H1 или имени файла, source_id — из относительного пути, status=current, authority=local_file, authority_priority=50.

Кэш и конфигурация

Пересобрать кэш:

./scripts/dev.sh index

Полностью удалить его можно командой rm -rf .cache/kb, после чего снова выполнить kb index. Запись каждого файла атомарна, а manifest.json заменяется последним. Повреждение JSON/NumPy, несовпадение схемы, модели, dimension, query instruction, chunking config или knowledge hash приводит к понятной invalidation, а не к неясной NumPy-ошибке.

Все параметры перечислены в .env.example. Основные:

  • KB_EMBEDDING_PROVIDER=sentence_transformers|hash;

  • KB_EMBEDDING_MODEL=./models/Qwen3-Embedding-0.6B — локальный каталог model files;

  • KB_EMBEDDING_LOCAL_FILES_ONLY=true — fail-closed запрет сетевой загрузки модели;

  • KB_EMBEDDING_DEVICE=auto|cpu|mps|cuda;

  • KB_EMBEDDING_DIMENSION=1024;

  • KB_CHUNK_SIZE_TOKENS=700, KB_CHUNK_HARD_MAX_TOKENS=900, KB_CHUNK_OVERLAP_TOKENS=80;

  • KB_AUTO_INDEX=false.

  • KB_MCP_HTTP_HOST, KB_MCP_HTTP_PORT, KB_MCP_HTTP_PATH;

  • KB_MCP_HTTP_BEARER_TOKEN — обязательный секрет для HTTP-режима;

Относительные пути разрешаются относительно текущего project working directory; kb stats показывает итоговые абсолютные пути.

Проверки

./scripts/dev.sh lint
./scripts/dev.sh typecheck
./scripts/dev.sh test
./scripts/dev.sh check

Обычный shell-скрипт scripts/dev.sh также объединяет повседневные команды:

./scripts/dev.sh install
./scripts/dev.sh install-pip
./scripts/dev.sh install-semantic
./scripts/dev.sh install-pip-semantic
./scripts/dev.sh test
./scripts/dev.sh lint
./scripts/dev.sh typecheck
./scripts/dev.sh index-hash
./scripts/dev.sh search-hash
./scripts/dev.sh index
./scripts/dev.sh search
./scripts/dev.sh index-semantic
./scripts/dev.sh eval
./scripts/dev.sh serve
./scripts/dev.sh serve-http

Тесты всегда инжектируют hash provider и не требуют интернета, Hugging Face, GPU, Qwen Code, Docker или внешней БД. Интеграционные тесты проверяют как in-memory MCP transport, так и HTTP handshake через ASGI без открытия сетевого порта.

Ограничения MVP и развитие

  • Полный brute-force cosine scan подходит для небольшой локальной базы, но не для миллионов чанков.

  • Любое изменение документа полностью перестраивает индекс; per-document incremental rebuild нет.

  • Нет Confluence REST API, OAuth, фоновой синхронизации и HTML-адаптеров под каждый вариант экспорта.

  • Нет reranker, hybrid/BM25 retrieval и отдельной оценки authority при ранжировании.

  • Точный token counter реальной модели не используется для предварительного chunking: интерфейс TokenCounter отделён, поэтому его можно подключить без связи chunker с SentenceTransformer.

  • Статический Bearer-токен даёт всем клиентам одинаковые права; для персональных учётных записей, отзыва сессий и аудита нужен внешний gateway/IdP либо полноценный OAuth.

Для перехода на настоящую Vector DB нужно реализовать PostgresKnowledgeStore или QdrantKnowledgeStore с тем же контрактом KnowledgeStore, выбрать реализацию при сборке KnowledgeService и сохранить API сервиса/MCP без изменений. Следующим этапом стоит добавить инкрементальный cache manifest, batch upsert, hybrid retrieval и production evaluation corpus.

Install Server
F
license - not found
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    D
    maintenance
    A local RAG-powered documentation search system that uses vector embeddings and Qdrant to enable semantic search across markdown, HTML, and other file formats. It provides an MCP interface for AI tools like Cursor to intelligently query and retrieve information from local knowledge bases.
    Last updated
    MIT
  • F
    license
    -
    quality
    C
    maintenance
    Hybrid semantic search (dense vector + BM25) over local knowledge bases and codebases, exposed as MCP tools for AI agents to search and list knowledge bases.
    Last updated
  • A
    license
    A
    quality
    B
    maintenance
    Local-first RAG indexing and semantic search MCP server. Enables document retrieval and context-aware queries using local embedding models.
    Last updated
    3
    25
    MIT
  • F
    license
    A
    quality
    B
    maintenance
    A local-first document retrieval engine that mounts as an MCP tool for agents to index files, search for relevant passages, and let the agent's own LLM answer.
    Last updated
    4

View all related MCP servers

Related MCP Connectors

  • Local-first RAG engine with MCP server for AI agent integration.

  • Persistent memory and knowledge management for AI agents with semantic search and 50+ tools.

  • Universal memory for AI agents and tools. Save, organize and search context anywhere.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/arptra/kb-rag-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server