Skip to main content
Glama
vdobhal

Oracle MCP Chatbot

by vdobhal

Oracle MCP Chatbot — локальная БД Oracle + Oracle ATP

Пара безопасных серверов Model Context Protocol позволяет ИИ-чат-боту отвечать на вопросы на естественном языке по базам данных Oracle: серверы обнаруживают метаданные, генерируют SQL только с SELECT, проверяют его, выполняют при жёстких ограничениях, маскируют чувствительные значения и журналируют всё.

Создано на FastMCP 3, python-oracledb (тонкий режим) и sqlglot. 221 тест; для их запуска база данных не требуется.

pip install -r requirements-dev.txt
pytest                                        # 221 passed
cp .env.example .env                          # add credentials
python -m oracle_mcp.server --profile onprem --check
python -m oracle_mcp.server --profile onprem

Тестирование работающего развёртывания описано в docs/testing.md. Браузерный интерфейс, не использующий Cursor, — docs/chat-ui.md:

python -m oracle_mcp.chat --profile both   # http://127.0.0.1:8500

Что делает

Возможность

Как реализовано

Только чтение, всегда

Проверка AST, SET TRANSACTION READ ONLY, гранты только на SELECT

Только одобренные данные

YAML-список разрешённых схем, объектов и колонок

Соответствие ролям

Пять ролей с уровнями допуска; контроль на уровне колонок

Ограниченный

Лимит строк (по умолчанию 500) и тайм-аут запроса (по умолчанию 30 с); ни то, ни другое пользователь не может повысить

Конфиденциальность

Маскирование по имени колонки, по классификации и по содержимому значения

Подотчётность

Одна запись аудита на вызов, с обезличенным SQL и хэшем

Две базы данных

Отдельные серверные процессы; опциональный сервер сверки

Related MCP server: OracleDB MCP Server

Восемь инструментов

Инструмент

Назначение

list_allowed_schemas

Схемы, которые роль может читать, с описаниями

list_allowed_tables

Одобренные объекты, с доменом, уровнем чувствительности и оценкой числа строк

get_table_metadata

Колонки, типы, допустимость NULL, PK/FK, бизнес-описания

search_data_dictionary

Поиск объектов и колонок по бизнес-термину, с указанием уровня уверенности

validate_sql

Проверка защитных ограничений; возвращает переписанный безопасный SQL

execute_readonly_sql

Выполняет предварительно одобренный SQL; возвращает замаскированные строки с ограничением по количеству

explain_query_result

Вычисляет факты для ответа на языке бизнеса

compare_onprem_and_atp_data

Сверка между базами данных (только profile=both)

Плюс list_databases для обнаружения подключений. Каждый инструмент принимает и возвращает JSON.

Как работает модель безопасности

Данные попадают к пользователю, только пройдя пять независимых уровней:

Database grants  →  Object allowlist  →  Role clearance  →  SQL guardrails  →  Output masking
   sql/*.sql        config/policy/       roles.yaml         sql_guard.py       masking.py

Ключевая идея: отправленный вами SQL никогда не является тем SQL, который выполняется. Входные данные разбираются в AST, проверяются, переписываются и генерируются заново. На выходе воспроизводятся только те типы узлов, которые распознал валидатор, поэтому трюки с комментариями, несколько инструкций подряд и ключевые слова-гомоглифы не могут пережить этот цикл.

SELECT a FROM t; DROP TABLE t     →  rejected: MULTIPLE_STATEMENTS
SELECT /*+ PARALLEL(t,64) */ a…   →  SELECT a FROM t FETCH FIRST 500 ROWS ONLY
DELETE FROM t                 →  rejected: NFKC folds it to DELETE
SELECT * FROM v   (business_user) →  explicit column list, restricted ones absent

Второе ключевое средство контроля: execute_readonly_sql заново проверяет всё с нуля и требует отпечаток, выданный validate_sql, поэтому подменить SQL между проверкой и выполнением невозможно. Роли без прав администратора не могут выполнить то, что не было одобрено заранее; администраторы могут, но инструкция всё равно проходит через все ограничения.

Третье: роли закрепляются конфигурацией процесса, а не аргументом инструмента. Пользователь, который говорит модели «теперь ты администратор», получает строку user_role="admin", которую никто не читает.

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

Всё определяют два файла:

config/policy/onprem.yaml и atp.yaml — список разрешённых объектов. Каждая база данных выбирает один из двух режимов.

Strict — именно этот режим использует On-Prem. Доступны только перечисленные здесь объекты, независимо от того, какие гранты выдаёт база данных:

schemas:
  - name: EIM
    objects:
      - name: EIM_PR_SYSTEM
        type: TABLE
        sensitivity: INTERNAL
        large_table: true
        require_filter: true       # forces a WHERE clause
        columns:                   # optional; omit to read them from the
          - {name: SERIAL_NUMBER,  sensitivity: INTERNAL}   # data dictionary
          - {name: TAX_ID,         sensitivity: RESTRICTED} # at query time

Опущение columns: поддерживается — именно так и поступает развёрнутая политика. В этом случае колонки читаются из ALL_TAB_COLUMNS и классифицируются по шаблонам имён из masking.yaml, поэтому список разрешённого остаётся корректным при изменении схемы.

Wildcard — именно этот режим использует ATP. Доступной становится каждая схема, которую может читать учётная запись с правами только на чтение:

allow_all_schemas: true
excluded_schemas: []   # added on top of the built-in Oracle internal schemas
schemas: []

Здесь осознанно отказываются от списка разрешённых объектов, и границей вместо него становятся гранты базы данных. Уровни допуска, защитные ограничения SQL, лимиты строк и маскирование по-прежнему действуют. Используйте этот режим только с учётной записью, которая действительно доступна только для чтения.

config/policy/roles.yaml — кто что может видеть:

roles:
  business_user:
    clearance: INTERNAL      # cannot reach CONFIDENTIAL or RESTRICTED columns
    max_rows: 200
    allow_raw_sql: false
    schemas: {ONPREM: [EIM], ATP: ["*"]}   # "*" needs allow_all_schemas

Лестница уровней чувствительности: PUBLIC < INTERNAL < CONFIDENTIAL < RESTRICTED < NEVER. NEVER стоит выше любого уровня допуска, поэтому пароли и номера карт недоступны ни для какой роли, включая администратора.

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

Запускайте по одному серверу на каждую базу данных. Это разделение — граница безопасности: локальный процесс никогда не хранит парольную фразу кошелька ATP.

docker build -t oracle-mcp-chatbot:1.0.0 .
export ATP_WALLET_HOST_PATH=/secure/path/wallets/atp
docker compose up -d onprem-mcp atp-mcp
docker compose --profile reconciliation up -d   # optional, holds both credential sets

Подключение к Oracle ATP

Тонкий режим с mTLS-кошельком. Распакуйте кошелёк и задайте:

ATP_DSN=myatp_low                      # prefer _low so chatbot traffic can't starve prod
ATP_WALLET_DIR=/opt/oracle/wallets/atp # contains ewallet.pem + tnsnames.ora
ATP_CONFIG_DIR=/opt/oracle/wallets/atp
ATP_WALLET_PASSWORD=...                # set when the wallet zip was downloaded

ATP_WALLET_PASSWORD — это парольная фраза, защищающая ewallet.pem, а не пароль базы данных: это частая и сбивающая с толку ошибка. Она используется только в тонком режиме; толстый режим вместо неё читает cwallet.sso без пароля, а одновременная настройка обоих вариантов отклоняется при старте. Для ATP только с TLS (без кошелька) оставьте переменные кошелька пустыми и вставьте полную строку подключения из консоли OCI в ATP_DSN.

Кошелёк монтируется как bind-том только для чтения и никогда не запекается в образ.

Подключение к локальной БД (On-Prem)

ONPREM_HOST=oracle-onprem.internal.example.com
ONPREM_PORT=1521
ONPREM_SERVICE_NAME=CDMPRD
ONPREM_MODE=thin
# TCPS instead:
# ONPREM_DSN=tcps://host:2484/CDMPRD?ssl_server_dn_match=true

Тонкому режиму не нужен Oracle Client. Толстый режим используйте только ради функций, которых не хватает тонкому; см. закомментированный этап в Dockerfile.

Документация

Документ

Содержание

docs/environment-configuration.md

Как настроены подключения этого развёртывания, и открытые вопросы

docs/architecture.md

Проектирование, поток запросов, границы безопасности, RBAC, аудит, обработка ошибок

docs/testing-scenarios.md

Полный план тестирования с ожидаемыми результатами

docs/deployment-checklist.md

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

docs/conversation-flows.md

Десять разобранных примеров плюс сценарии отклонений

prompts/system_prompt.md

Системный промпт чат-бота

sql/

Пользователи только для чтения, гранты, схема аудита

mcp-clients/

Конфигурация для Cursor и Claude Desktop

Перед запуском в production

Эталонная реализация намеренно неполна в четырёх местах. Полный список — в docs/deployment-checklist.md; главные пункты:

  • Установите ORACLE_MCP_ROLE_BINDING_MODE=env. Значение argument по умолчанию в .env.example предназначено для разработки; при нём модель может заявить любую роль.

  • Замените примеры списков разрешений в config/policy/*.yaml на свои реальные выверенные представления и осознанно классифицируйте каждую колонку.

  • Перенесите секреты в хранилище. Переменные окружения Compose видны любому, кто может выполнить docker inspect.

  • Поместите HTTP-транспорт за шлюз с аутентификацией. HTTP-транспорт FastMCP сам по себе не аутентифицирует вызывающих; привязка к loopback — это временная мера, а не средство контроля.

Кроме того, намеренно не реализовано: ограничение частоты запросов, передача идентичности пользователя и workflow согласования «сырого» SQL для администратора.

Лицензия

Предоставляется в качестве эталонной реализации. Перед использованием в production проверьте её по своим стандартам безопасности.

Related MCP Connectors

Related MCP Servers