Metadata-Version: 2.4
Name: opc-mcp
Version: 0.2.9
Summary: MCP server for order center database access
Author-email: zhouxinhai <your.email@example.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/zhouxinhai/opc-mcp
Project-URL: Repository, https://github.com/zhouxinhai/opc-mcp
Project-URL: Issues, https://github.com/zhouxinhai/opc-mcp/issues
Keywords: mcp,database,oracle,mysql,order-center
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Database
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp[cli]>=1.0.0
Requires-Dist: mysql-connector-python>=9.7.0
Requires-Dist: pymysql>=1.1.0
Requires-Dist: jaydebeapi>=1.2.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: pydantic>=2.0
Requires-Dist: sqlparse>=0.5.0
Dynamic: license-file

# OPC-MCP

订单中心数据库 MCP 服务，通过 MCP 协议暴露数据库查询能力，供 AI 助手动态查询和排查订单问题。

## 功能特性

- **配置驱动工具** — 在 `config.yaml` 中定义 SQL 模板，自动生成 MCP 工具
- **`run_query`** — 动态执行任意 SELECT 查询，支持命名参数、LIKE 自动检测、分页
- **`query_table_desc`** — 查询表结构信息（列名、数据类型、注释），表名大小写不敏感
- **PrefabSQL 工具集** — SQL 代码双向溯源（sqlId ↔ 表名）
- **多连接池** — 支持多个数据库（opc、smc 等），连接池名称大小写不敏感
- **多驱动支持** — 支持 OceanBase MySQL 模式 (`ob_mysql`) 和 Oracle 模式 (`ob_oracle`)
- **安全防护** — 仅允许 SELECT 语句，拒绝多语句注入，参数化查询

---

## 环境要求

| 驱动模式      | 依赖要求                            |
| ------------- | ----------------------------------- |
| `ob_mysql`  | Python 3.11+，无需额外依赖          |
| `ob_oracle` | Python 3.11+**+ Java JDK 9+** |

> ⚠️ **重要提示**：使用 `ob_oracle` 驱动连接 OceanBase Oracle 模式租户时，必须安装 Java JDK 9 或更高版本。这是因为 Oracle 模式使用 jaydebeapi + JDBC 驱动，需要 Java 运行环境。

### 验证 Java 环境

```bash
java -version
# 应显示 9 或更高版本，如：openjdk version "11.0.x"
```

---

## 安装

### 方式一：uvx 直接运行（推荐）

```bash
# 直接运行，无需安装
uvx opc-mcp --config /path/to/config.yaml
```

### 方式二：uv tool 安装

```bash
# 安装到 uv 工具环境
uv tool install opc-mcp

# 启动服务
opc-mcp --config /path/to/config.yaml
```

### 方式三：pip 安装

```bash
pip install opc-mcp
opc-mcp --config /path/to/config.yaml
```

### 方式四：本地开发安装

```bash
git clone https://gitee.com/zhouxinhai/opc-mcp.git
cd opc-mcp
uv sync
uv run opc-mcp --config config.yaml
```

---

## 配置

### 创建配置文件

创建 `config.yaml` 文件：

```yaml
server:
  host: "0.0.0.0"
  port: 8000

db_connect_info:
  opc:
    host: "10.44.46.76"
    port: 8090
    user: "OC@oboc_test_utf8#bs_test03:100003"
    password: "your_password"
    database: OC
    pool_size: 5
    driver: ob_oracle  # OceanBase Oracle 模式租户

  smc:
    host: "10.44.46.76"
    port: 8999
    user: "SMC@arcdbcs#BS_OB_04_B_Test"
    password: "your_password"
    database: SMC
    pool_size: 5
    driver: ob_mysql   # OceanBase MySQL 模式租户

# PrefabSQL 缓存配置（可选）
prefab_sql:
  enabled: true
  pool: smc
  sql: |
    SELECT SQL_ID, SQL_STATEMENT
    FROM SMC_PREFAB_SQL_STATEMENT
    WHERE upper(sql_jndi) = 'ORDER'
    ORDER BY SQL_ID

tools:
  query_opc_dict_def:
    description: "查询订单中心字典定义表 or_dict_def"
    pool: opc
    sql: |
      SELECT a.DICT_TYPE, a.DICT_TYPE_NAME, a.DICT_CLASS, a.DICT_CLASS_NAME,
             a.DICT_ID, a.DICT_NAME, a.DICT_ALIASES, a.VALUE,
             a.CREATE_DATE, a.REMARK, a.OP_DATE
      FROM or_dict_def a
      WHERE 1=1
        AND a.DICT_TYPE = :dict_type
        AND a.DICT_CLASS = :dict_class
        AND a.DICT_ID = :dict_id
        AND a.DICT_NAME LIKE :dict_name
    params:
      dict_type:
        type: int
        description: "字典类型 NUMBER"
        required: false
      dict_class:
        type: int
        description: "字典类别 NUMBER"
        required: false
      dict_id:
        type: str
        description: "字典项目 VARCHAR2"
        required: false
      dict_name:
        type: str
        description: "字典项目名称 VARCHAR2，支持模糊匹配"
        required: false
        like: true
    limit:
      default: 50
      max: 100
    offset:
      default: 0
```

### 驱动类型说明

| 驱动          | 说明                             | 适用场景                                    |
| ------------- | -------------------------------- | ------------------------------------------- |
| `ob_mysql`  | 使用 mysql-connector-python 连接 | OceanBase MySQL 模式租户                    |
| `ob_oracle` | 使用 jaydebeapi + JDBC 连接      | OceanBase Oracle 模式租户（需 Java JDK 9+） |

> **错误提示**：如果配置了不支持的驱动类型，启动时会报错：
>
> ```
> Pool 'xxx': driver 'invalid_driver' 不支持。
> 支持的驱动类型:
>   - ob_mysql:  OceanBase MySQL 模式租户
>   - ob_oracle: OceanBase Oracle 模式租户 (使用 jaydebeapi + JDBC, 需 Java JDK 9+)
> ```

### 自定义 JDBC 驱动路径

默认情况下，JDBC 驱动已打包在项目中。如需使用其他版本或自定义路径：

```bash
# 方式一：指定具体 jar 文件
export JDBC_JAR_PATH=/path/to/oceanbase-client-2.4.12.jar

# 方式二：指定 jar 目录
export JDBC_JAR_PATH=/path/to/lib/

uvx opc-mcp --config config.yaml
```

---

## 启动服务

### 启动命令

```bash
# Streamable HTTP 模式（默认，推荐）
uvx opc-mcp --config /path/to/config.yaml

# SSE 模式
uvx opc-mcp --config /path/to/config.yaml --mode sse

# stdio 模式（本地进程通信）
uvx opc-mcp --config /path/to/config.yaml --mode stdio

# 指定日志级别
uvx opc-mcp --config /path/to/config.yaml --log-level DEBUG
```

### 连接地址

| 模式                    | 连接方式                      |
| ----------------------- | ----------------------------- |
| Streamable HTTP（默认） | `http://localhost:8000/mcp` |
| SSE                     | `http://localhost:8000/sse` |
| stdio                   | 通过 stdin/stdout 通信        |

---

## MCP 客户端配置

### Streamable HTTP 模式（推荐）

先启动服务：

```bash
uvx opc-mcp --config /path/to/config.yaml
```

MCP 配置：

```json
{
  "mcpServers": {
    "opc-mcp": {
      "type": "http",
      "url": "http://localhost:8000/mcp"
    }
  }
}
```

### SSE 模式

先启动服务：

```bash
uvx opc-mcp --config /path/to/config.yaml --mode sse
```

MCP 配置：

```json
{
  "mcpServers": {
    "opc-mcp": {
      "type": "sse",
      "url": "http://localhost:8000/sse"
    }
  }
}
```

### stdio 模式（无需预先启动）

MCP 配置（智能体自动启动服务）：

```json
{
  "mcpServers": {
    "opc-mcp-stdio": {
      "command": "uvx",
      "args": [
        "opc-mcp",
        "--config", "/path/to/config.yaml",
        "--mode", "stdio"
      ]
    }
  }
}
```

> **说明**：stdio 模式下，智能体会在调用时自动启动 opc-mcp 进程，无需手动运行服务。

---

## MCP 工具说明

### run_query

动态执行 SELECT 查询，支持命名参数和分页。

**参数：**

| 参数   | 类型    | 必填 | 说明                                    |
| ------ | ------- | ---- | --------------------------------------- |
| sql    | string  | 是   | SELECT SQL，使用 `:param_name` 占位符 |
| params | object  | 否   | 命名参数，key 大小写不敏感              |
| pool   | string  | 否   | 连接池名称，默认 `opc`                |
| limit  | integer | 否   | 返回行数限制，默认 50，最大 200         |
| offset | integer | 否   | 分页偏移量，默认 0                      |

**示例：**

```json
{
  "sql": "SELECT * FROM or_dict_def WHERE dict_type = :dict_type AND dict_class = :dict_class",
  "params": {"dict_type": 18, "dict_class": 1},
  "pool": "opc"
}
```

支持 JOIN、GROUP BY、子查询、UNION、聚合等复杂查询。LIKE 条件自动检测并包裹 `%`。

### query_table_desc

查询表的列结构信息。

**参数：**

| 参数       | 类型   | 必填 | 说明               |
| ---------- | ------ | ---- | ------------------ |
| table_name | string | 是   | 表名，大小写不敏感 |
| pool       | string | 是   | 连接池名称         |

**示例：**

```json
{
  "table_name": "or_dict_def",
  "pool": "opc"
}
```

**返回：**

```json
{
  "table_name": "OR_DICT_DEF",
  "count": 5,
  "columns": [
    {"table_name": "OR_DICT_DEF", "column_name": "DICT_TYPE", "data_type": "NUMBER", "comments": "字典类型"},
    {"table_name": "OR_DICT_DEF", "column_name": "DICT_NAME", "data_type": "VARCHAR2", "comments": "字典名称"}
  ]
}
```

---

## PrefabSQL 工具集

用于 SQL 代码双向溯源的工具集。从数据库加载 SQL 配置到本地 SQLite 缓存，支持：

- **正向追踪**：sqlId → SQL 语句 → 操作类型 → 涉及的表
- **反向溯源**：表名 → 相关 sqlId 列表

### create_prefab_sql_cache

创建或刷新本地 SQLite 缓存。

**参数：**

| 参数          | 类型    | 必填 | 说明                     |
| ------------- | ------- | ---- | ------------------------ |
| force_refresh | boolean | 否   | 强制刷新缓存，默认 false |

**返回：**

```json
{"status": "success", "count": 1234, "cache_path": "~/.prefab-sql/cache.db"}
```

### query_sql_by_id

根据 sqlId 查询 SQL 语句。

**参数：**

| 参数   | 类型   | 必填 | 说明                  |
| ------ | ------ | ---- | --------------------- |
| sql_id | string | 是   | SQL ID（如 10511206） |

**返回示例：**

```json
{
  "status": "found",
  "data": {
    "sql_id": "10511206",
    "sql_statement": "insert into\n  or_message_delay_req(\n    delay_message_id,\n    opt_type,\n    message_type,\n    comb_order_id,\n    sub_order_id,\n    order_line_id,\n    stage_id,\n    operation_id,\n    message_content,\n    topic_name_id,\n    create_date,\n    delay_time,\n    status,\n    delay_cause_code,\n    delay_cause_desc,\n\torder_id,\n    OP_DATE\n  )\nvalues(\n    :delay_message_id,\n    :opt_type,\n    :message_type,\n    :comb_order_id,\n    :sub_order_id,\n    :order_line_id,\n    :stage_id,\n    :operation_id,\n    :message_content,\n    :topic_name_id,\n    sysdate,\n    :delay_time,\n    0,\n    :delay_cause_code,\n    :delay_cause_desc,\n\t:order_id,\n    SYSDATE\n  );",
    "operation_type": "INSERT",
    "tables": [
      "OR_MESSAGE_DELAY_REQ"
    ]
  }
}
```

### find_sql_by_table

根据表名查找相关的 sqlId。

**参数：**

| 参数       | 类型    | 必填 | 说明                           |
| ---------- | ------- | ---- | ------------------------------ |
| table_name | string  | 是   | 表名（精确匹配，大小写不敏感） |
| limit      | integer | 否   | 返回数量限制，默认 100         |

**返回示例：**

```json
{
  "status": "success",
  "table_name": "or_cust_order",
  "count": 2,
  "data": [
    {
      "sql_id": "10510327",
      "sql_statement": "  SELECT\n    co.ORDER_ID ,\n    so.SUB_ORDER_ID ,\n    oio.OBJ_NUMBER ,\n    oio.OBJ_TYPE ,\n    co.REGION_CODE \nFROM\n    OR_ORDER_ITEM_OBJECT oio\nINNER JOIN OR_ORDER_ITEM oi\n    ON oio.ORDER_ITEM_ID = oi.ORDER_ITEM_ID\nINNER JOIN OR_CUST_ORDER co\n    ON oi.ORDER_ID = co.ORDER_ID and  co.STATUS NOT IN (4, 5)  and co.ORDER_TYPE = 1 \nINNER JOIN OR_SUB_ORDER so\n    ON so.SUB_ORDER_ID = oi.BUSI_ORDER_ID AND so.STATUS NOT IN (2, 3)     \nWHERE\n    oio.OBJ_NUMBER = :objNumber \n    AND (oio.OBJ_TYPE = :objType)            \n    AND co.REGION_CODE = :regionCode       \nGROUP BY\n    co.ORDER_ID,\n    so.SUB_ORDER_ID,\n    oio.OBJ_NUMBER,\n    oio.OBJ_TYPE,\n    co.REGION_CODE",
      "operation_type": "SELECT",
      "tables": [
        "OR_SUB_ORDER",
        "OR_CUST_ORDER",
        "OR_ORDER_ITEM"
      ]
    },
    {
      "sql_id": "10511007",
      "sql_statement": "select ORDER_ID,STATUS,to_char(STATUS_DATE,'yyyymmddhh24miss') as STATUS_DATE,INTACT_ID,PRE_ORDER_ID,ORDER_TEAM_ID,CUST_ID,BUSI_TYPE_CODE,CHANNEL_ID,DEAL_PRIORITY,CANCEL_ORDER_ID,CANCEL_REASON,to_char(CREATE_DATE,'yyyymmddhh24miss') as CREATE_DATE,CREATE_OPRT_ID,CREATE_ORG_ID,to_char(OP_DATE,'yyyymmddhh24miss') as OP_DATE,OPRT_ID,ORG_ID,SERVICE_NUMBER,SUBS_ID,REGION_CODE,OPRT_REGION_CODE,ORDER_TYPE,REMARK,SALES_ID,SALES_ROLE_TYPE,ORDER_SRC_TYPE,FORM_NUMBER,THIRD_SN,SRC_SYS,IS_NOTIFY,MGMT_REGION_CODE,MGMT_COUNTY_CODE,OP_SN,BATCH_ID from OR_CUST_ORDER where ORDER_ID = :orderId",
      "operation_type": "SELECT",
      "tables": [
        "OR_CUST_ORDER"
      ]
    }
  ]
}
```

### prefab_sql_stats

获取缓存统计信息。

**返回示例：**

```json
{
  "status": "success",
  "stats": {
    "total_count": 2774,
    "by_operation_type": {
      "SELECT": 1320,
      "INSERT": 596,
      "DELETE": 361,
      "UPDATE": 361,
      "UNKNOWN": 136
    },
    "cache_path": "C:\\Users\\admin\\.prefab-sql\\cache.db",
    "metadata": {
      "last_update": "2026-05-26T16:16:34.117190",
      "record_count": 2774,
      "cache_path": "C:\\Users\\admin\\.prefab-sql\\cache.db"
    }
  }
}
```

---

## diagnose 技能（可选）

opc-mcp 提供配套的 diagnose 技能，用于订单中心数据库排障诊断。

### 安装技能

将 diagnose 技能目录复制到智能体的技能目录：

```
.claude/skills/diagnose/
  SKILL.md          # 技能定义
  examples/         # 示例规则文件
```

### 使用技能

```bash
/diagnose @<规则文件路径> <入口参数值>
```

示例：

```bash
/diagnose @.claude/skills/diagnose/examples/运维排查_test1.md 客户订单id是`OD5910002026051817511027690041`
```

---

## 发布到 PyPI

### 构建

```bash
uv run python -m build
```

### 上传

```bash
uv run twine upload dist/*
```

---

## 常见问题

### Q1：ob_oracle 模式启动报错？

确保已安装 Java JDK 9+：

```bash
java -version
# 应显示 9 或更高版本
```

### Q2：MCP 连接失败？

- Streamable HTTP/SSE 模式：确认服务已启动
- stdio 模式：检查 config.yaml 路径是否正确（使用绝对路径）

### Q3：数据库查询报错？

- 检查 config.yaml 中的数据库连接信息
- 确认表名、字段名是否正确（Oracle 字段名大小写不敏感）

### Q4：如何更新版本？

```bash
uvx opc-mcp@latest --config /path/to/config.yaml
```

---

## 项目结构

```
opc-mcp/
├── lib/                          # JDBC 驱动（打包时包含）
│   └── oceanbase-client-*.jar
├── src/opc_mcp/
│   ├── main.py                   # 入口，服务创建与启动
│   ├── config.py                 # 配置模型
│   ├── pool_manager.py           # 连接池管理
│   ├── handlers.py               # 工具执行逻辑
│   ├── register.py               # MCP 工具注册
│   ├── tools.py                  # SQL 校验、参数绑定
│   ├── prefab_sql_cache.py       # PrefabSQL 缓存
│   └── sql_parser.py             # SQL 解析
├── config.yaml                   # 配置示例
├── pyproject.toml                # 项目配置
└── README.md                     # 本文档
```

---

## 版本历史

| 版本  | 变更                                               |
| ----- | -------------------------------------------------- |
| 0.2.0 | 支持多驱动模式 (ob_mysql/ob_oracle)，JDBC 驱动打包 |
| 0.1.2 | 新增 PrefabSQL 工具集                              |
| 0.1.1 | 初始版本                                           |

---

## License

MIT
