Skip to main content
Glama
vdobhal

Oracle MCP Chatbot

by vdobhal

Oracle MCP Chatbot — On-Prem Oracle DB + Oracle ATP

一个安全的 Model Context Protocol 服务器对,让 AI 聊天机器人能够针对 Oracle 数据库回答自然语言问题:它发现元数据、生成仅 SELECT 的 SQL、验证 SQL、在硬限制下执行、掩码敏感值,并记录所有内容。

使用 FastMCP 3、python-oracledb(thin 模式)和 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 的浏览器 UI 见 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

列、类型、可空性、主键/外键、业务描述

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 — 对象白名单。每个数据库选择两种模式之一。

严格模式,即 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 中的名称模式分类,因此白名单在模式变化时保持正确。

通配符模式,即 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 高于所有权限级别,因此密码和卡号对任何角色(包括管理员)都不可访问。

部署

每个数据库运行一个服务器。这种拆分是一个安全边界:on-prem 进程从不持有 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 钱包的 thin 模式。解压钱包并设置:

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 的口令,不是数据库密码——这是一个常见且令人困惑的错误。它仅适用于 thin 模式;thick 模式改为读取无密码的 cwallet.sso,同时配置两者会在启动时被拒绝。对于仅 TLS 的 ATP(无钱包),将钱包变量留空,并把 OCI 控制台中的完整连接字符串粘贴到 ATP_DSN。

钱包以只读方式绑定挂载,从不打包进镜像。

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

Thin 模式不需要 Oracle Client。仅在其缺少的功能上使用 thick 模式;参见 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 配置

生产前

参考实现有意在四个方面有所保留。完整列表请阅读 docs/deployment-checklist.md;主要事项:

  • 设置 ORACLE_MCP_ROLE_BINDING_MODE=env。 .env.example 中的 argument 默认值仅用于开发;在该模式下模型可以声明任何角色。

  • 替换示例白名单:将 config/policy/*.yaml 中的示例白名单替换为你真实的精选视图,并有意对每一列进行分类。

  • 将机密移至 vault。 Compose 环境变量对任何能运行 docker inspect 的人可见。

  • 将 HTTP 传输置于认证网关之后。 FastMCP 的 HTTP 传输本身不认证调用者;绑定到 loopback 是权宜之计,而非控制措施。

另有设计上未实现的功能:速率限制、按用户身份传播,以及管理员原始 SQL 的审批工作流。

许可证

作为参考实现提供。在生产使用前请对照你自己的安全标准进行审查。

Related MCP Connectors

Related MCP Servers