# Oracle MCP 本机运行时准备

生成 Oracle MCP 前/后按本文件检查。**两套目录分开，不要混装。**

## 结论先行

| 位置 | 只放什么 |
|------|----------|
| `C:\tools\oracle-mcp` | Instant Client（及下载用的临时 rar） |
| 本机已有 npm 目录（`npm root -g`） | `oracledb`、`oracle-mcp-server` |

- Instant Client **不能**用 npm 安装；缺失时 Agent 自动从公司共享拉取 `.rar` 并解压，**已安装则整体跳过**
- **禁止**在 `C:\tools\oracle-mcp` 下执行 `npm install` / 新建 `node_modules`
- 项目目录含中文时，不要把临时 `.ps1`、Instant Client、`node_modules` 放进项目里
- Git Bash 命令行不能直接出现 UNC/中文路径；下载用「写 .ps1 → 补 UTF-8 BOM → `powershell.exe -File`」

## 三个路径（生成前先探测）

| 占位符 | 含义 | 怎么得到 |
|--------|------|----------|
| `<NODE_EXE>` | 64 位 `node.exe` | `where node` |
| `<NPM_ROOT>` | 本机 npm 的 `node_modules` 根 | `npm root -g` |
| `<NPM_PREFIX>` | npm 全局前缀 | `npm prefix -g`（`<NPM_ROOT>` 一般等于 `<NPM_PREFIX>\node_modules`） |
| `C:\tools\oracle-mcp` | Instant Client 专用目录 | **固定推荐** |
| `<PROJECT_ROOT>` | 本仓库根 | Cursor 工作区根；只放 `.mcp.json` / 可选 wrapper |

```powershell
where.exe node
node -v
npm -v
npm root -g          # → <NPM_ROOT>
npm prefix -g        # → <NPM_PREFIX>
```

以**当前** `npm root -g` 为准；历史机器若包在别的目录，用 `ORACLE_NPM_ROOT` 指向真实含 `oracledb` 的 `node_modules`。

## 目标目录结构（拆分）

### Instant Client（固定）

```text
C:\tools\oracle-mcp\
├── downloads\                                      # 可选
│   └── instantclient-basic-windows.x64-11.2.0.4.0.rar
└── instantclient-basic-windows.x64-11.2.0.4.0\
    └── instantclient_11_2\
        └── oci.dll
```

### npm 依赖（本机已有位置）

```text
<NPM_ROOT>\
├── oracledb\
└── oracle-mcp-server\
    └── build\
        └── index.js
```

### Wrapper（二选一）

| 方式 | 路径 |
|------|------|
| 推荐与项目一起 | `<PROJECT_ROOT>\.claude\oracle-mcp-wrapper.mjs` |
| 或放工具目录 | `C:\tools\oracle-mcp\oracle-mcp-wrapper.mjs`（仍用 env 找 npm 目录） |

## Instant Client（共享 → `C:\tools\oracle-mcp`）

**先检查，已存在则跳过（必遵）：**

- `C:\tools\oracle-mcp\instantclient-basic-windows.x64-11.2.0.4.0\instantclient_11_2\oci.dll` 已存在 → **已安装，跳过本节全部步骤**（不复制、不解压）
- `downloads\instantclient-basic-windows.x64-11.2.0.4.0.rar` 已存在且大小一致（约 38,686,229 字节）→ **跳过复制**，只需解压（解压目录也已存在则连解压一起跳过）

缺件时由 Agent **自动**执行下述复制与解压，不要让用户手动操作（除非共享不可达或无解压工具）。

- 共享：`\\10.111.2.7\云链共享文件\00-研发中心-公共工具`
- 文件：`instantclient-basic-windows.x64-11.2.0.4.0.rar`（约 38,686,229 字节）
- 解压后必须存在：`C:\tools\oracle-mcp\instantclient-basic-windows.x64-11.2.0.4.0\instantclient_11_2\oci.dll`

临时脚本放 `C:\Users\<用户名>\`（纯 ASCII），不要放含中文项目。

`oracle_ic_copy.ps1`（幂等：已装/已下载自动跳过）：

```powershell
$ErrorActionPreference = 'Stop'
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

$icDll = 'C:\tools\oracle-mcp\instantclient-basic-windows.x64-11.2.0.4.0\instantclient_11_2\oci.dll'
if (Test-Path -LiteralPath $icDll) {
  Write-Output 'ALREADY INSTALLED - oci.dll exists, nothing to do'
  exit 0
}

$src = '\\10.111.2.7\云链共享文件\00-研发中心-公共工具\instantclient-basic-windows.x64-11.2.0.4.0.rar'
$dstDir = 'C:\tools\oracle-mcp\downloads'
$dst = Join-Path $dstDir 'instantclient-basic-windows.x64-11.2.0.4.0.rar'

New-Item -ItemType Directory -Force -Path $dstDir | Out-Null

$srcInfo = Get-Item -LiteralPath $src
if ((Test-Path -LiteralPath $dst) -and (Get-Item -LiteralPath $dst).Length -eq $srcInfo.Length) {
  Write-Output 'RAR ALREADY DOWNLOADED - sizes match, skip copy'
} else {
  Copy-Item -LiteralPath $src -Destination $dst -Force
  if ((Get-Item -LiteralPath $dst).Length -ne $srcInfo.Length) { Write-Output 'COPY FAILED'; exit 1 }
  Write-Output 'COPY SUCCESS - sizes match'
}
```

Git Bash：补 BOM 后执行：

```bash
printf '\xEF\xBB\xBF' > /c/Users/<用户名>/oracle_ic_copy_bom.ps1 \
  && cat /c/Users/<用户名>/oracle_ic_copy.ps1 >> /c/Users/<用户名>/oracle_ic_copy_bom.ps1

MSYS2_ARG_CONV_EXCL='*' powershell.exe -NoProfile -ExecutionPolicy Bypass \
  -File 'C:\Users\<用户名>\oracle_ic_copy_bom.ps1'
```

解压到 `C:\tools\oracle-mcp`（`oci.dll` 已存在则跳过）。Agent 优先用命令行自动解压（哪个存在用哪个）：

```bat
"C:\Program Files\7-Zip\7z.exe" x "C:\tools\oracle-mcp\downloads\instantclient-basic-windows.x64-11.2.0.4.0.rar" -o"C:\tools\oracle-mcp" -y
```

```bat
"C:\Program Files\WinRAR\WinRAR.exe" x -y "C:\tools\oracle-mcp\downloads\instantclient-basic-windows.x64-11.2.0.4.0.rar" "C:\tools\oracle-mcp\"
```

两者都不存在时，才提示用户用 WinRAR/7-Zip 手动解压。解压后校验 `oci.dll` 存在。用完删临时 `.ps1`。

连通性：`ping -n 2 10.111.2.7`；库：`Test-NetConnection 10.111.20.30 -Port 1521`（test）。

## npm 依赖（装到本机 npm 目录）

```powershell
npm root -g

# 先检查：两条均 True → 已安装，跳过 npm install
Test-Path (Join-Path (npm root -g) 'oracledb')
Test-Path (Join-Path (npm root -g) 'oracle-mcp-server\build\index.js')

# 缺失才装（内联内网源，禁止 npm config set registry）
npm install -g oracledb@^5.5.0 oracle-mcp-server@^0.1.3 --registry http://172.16.30.100:8081/repository/npm-group/

Test-Path (Join-Path (npm root -g) 'oracledb')
Test-Path (Join-Path (npm root -g) 'oracle-mcp-server\build\index.js')
```

装后两条均应为 `True`。npm 安装一律 `--registry` 内联内网源、不改全局配置，规则同 [SKILL.md](SKILL.md)。预估约 2～5 分钟。

**错误示例（禁止）：**

```powershell
# ❌ 不要
Set-Location C:\tools\oracle-mcp
npm install
```

若包实际在旧目录（如 `D:\software\node_modules`），可跳过 `-g`，把 `ORACLE_NPM_ROOT` 指到该 `node_modules`。

## Wrapper

从本 skill 复制 [oracle-mcp-wrapper.mjs](scripts/oracle-mcp-wrapper.mjs) 到 `<PROJECT_ROOT>\.claude\`（推荐）。

冒烟：

```powershell
$env:ORACLE_NPM_ROOT = (npm root -g)
$env:ORACLE_IC_HOME = 'C:\tools\oracle-mcp'
$env:ORACLE_USER = 'ZQYL_LS_TEST2'
$env:ORACLE_PASSWORD = 'test123456'
$env:ORACLE_HOST = '10.111.20.30'
$env:ORACLE_PORT = '1521'
$env:ORACLE_SERVICE = 'testdg1'
& '<NODE_EXE>' '<PROJECT_ROOT>\.claude\oracle-mcp-wrapper.mjs'
```

stderr 应类似：

```text
[Wrapper] Instant Client: C:\tools\oracle-mcp\instantclient-basic-windows.x64-11.2.0.4.0\instantclient_11_2
[Wrapper] npm root: D:\soft\npm-global\node_modules
```

## Agent 检查清单（写 Oracle mcp 时）

- [ ] `npm root -g` → `<NPM_ROOT>`
- [ ] `where node` → `<NODE_EXE>`
- [ ] 存在 `C:\tools\oracle-mcp\...\instantclient_11_2\oci.dll`
- [ ] 存在 `<NPM_ROOT>\oracledb` 与 `<NPM_ROOT>\oracle-mcp-server\build\index.js`
- [ ] 已复制 wrapper 到 `.claude\`
- [ ] mcp.json：`ORACLE_NPM_ROOT` + `ORACLE_IC_HOME` + `ORACLE_USER/PASSWORD/HOST/PORT/SERVICE`（**不要** `ORACLE_CONNECTION_STRING` / 裸 npx / `ORACLE_MCP_HOME`）
- [ ] 缺件时：Instant Client 按本节自动从共享拉取并解压（已存在则跳过）；npm 依赖 `npm install -g … --registry http://172.16.30.100:8081/repository/npm-group/`（已存在则跳过）；Instant Client 只进 `C:\tools\oracle-mcp`

## 故障要点

| 现象 | 处理 |
|------|------|
| `ORACLE_NPM_ROOT is required` | mcp.json 设为 `npm root -g` 输出 |
| Missing oracledb | `npm install -g`；核对 `ORACLE_NPM_ROOT` |
| Missing oci.dll | 按本节自动从共享拉取 rar 并解压到 `C:\tools\oracle-mcp`（已存在则跳过） |
| 在 `C:\tools\oracle-mcp` 误装 npm | 删该处 `node_modules`，改 `npm install -g` |
| bash exit 127 / UNC | 用 ps1 + BOM + `-File` |
