# 数据库 MCP

KCode 不内置自研数据库驱动工具。数据库能力通过 `pi-mcp-adapter` 接入成熟 MCP server，KCode 只负责配置脚手架、运行时规则和只读边界。

## 初始化

在业务项目根目录执行：

```powershell
kcode db
```

该命令写入或更新项目级 `.mcp.json`，保留已有 MCP server，并新增：

```text
kcode-postgres   PostgreSQL，只读查询和 schema resource
kcode-sqlserver  SQL Server，只读 schema/query 工具
kcode-oracle     Oracle，通过 MIT 的 mcp-db-connect 读取只读 YAML 配置
```

KCode 使用 `pi-mcp-adapter` 提供的单一 `mcp` 代理工具。进入 `kcode start` 后先搜索工具：

```text
mcp({ search: "database schema table" })
mcp({ server: "kcode-sqlserver" })
mcp({ describe: "kcode_sqlserver_execute_query" })
```

`args` 必须是 JSON 字符串，按 `pi-mcp-adapter` 协议调用：

```text
mcp({ tool: "kcode_sqlserver_execute_query", args: "{\"query\":\"SELECT TOP 10 * FROM T_META_OBJECTTYPE\"}" })
```

## 凭证

凭证只允许放在当前终端环境变量或用户本地私有配置中。禁止写入 `.mcp.json`、仓库文档、阶段产物、evidence、更新日志或提交说明。数据库连接必须绑定具体业务库、账套库或服务名；禁止给 LLM 使用能枚举所有库或跨库查询的账号。

PostgreSQL：

```powershell
$env:KCODE_POSTGRES_URL="postgresql://readonly_user:***@localhost:5432/<实际苍穹业务库>"
```

本地 Docker `postgres15` 示例业务库为 `prod_kmlttest`。默认 `postgres` 库只能用于连接连通性验证，不能用于判断苍穹元数据表是否存在。

PostgreSQL launcher 会拒绝未包含数据库名的 URL，也会拒绝 `postgres`、`template0`、`template1` 等维护库。

SQL Server：

```powershell
$env:KCODE_SQLSERVER_HOST="localhost"
$env:KCODE_SQLSERVER_USER="readonly_user"
$env:KCODE_SQLSERVER_PASSWORD="***"
$env:KCODE_SQLSERVER_DATABASE="AIS20230806005219"
```

`KCODE_SQLSERVER_DATABASE` 必须是具体 AIS 业务账套库。账号只授予该库只读权限，不能授予跨库枚举、系统库读取或写权限。需要端口、证书或行数限制时，在 `.mcp.json` 的 `kcode-sqlserver.env` 中补充 `SQLSERVER_PORT`、`SQLSERVER_ENCRYPT`、`SQLSERVER_TRUST_CERT`、`SQLSERVER_MAX_ROWS` 等 MCP server 支持的可选项。

Oracle：

```powershell
$env:KCODE_ORACLE_PASSWORD="***"
```

Oracle 的 host、port、serviceName、username 写在 `.pi/kd/mcp-db-connect.yml` 中；`serviceName` 必须绑定具体业务库或服务。默认生成只读模板：

```yaml
connections:
  oracle_default:
    type: oracle
    host: localhost
    port: 1521
    serviceName: ORCLPDB1
    username: readonly_user
    passwordEnv: KCODE_ORACLE_PASSWORD
    clientMode: thin
    mode: readonly
```

需要超时、最大行数或响应大小限制时，修改 `.pi/kd/mcp-db-connect.yml` 的 `security.defaultMaxRows`、`security.queryTimeoutMs` 或连接级 `maxRows`。

## 权限边界

- LLM 只允许执行元数据读取和只读查询。
- 每个 MCP 连接只允许绑定一个具体业务库、账套库或服务名；禁止使用能访问所有库的超级账号或跨库账号。
- `INSERT`、`UPDATE`、`DELETE`、`MERGE`、`DROP`、`ALTER`、`CREATE`、数据修复和 DDL 只能生成 SQL 文本，由用户自行执行。
- 存储过程默认只生成脚本不执行；只有可证明为纯查询存储过程且用户明确授权时，才允许走只读查询路径。
- 报表 SQL、存储过程、数据修复脚本可以由 LLM 编写，但执行证据必须由用户提供。
- 数据库账号应使用只读账号；KCode 规则不能替代数据库权限。

## 标识使用规则

Agent 必须先判断本次实现走哪一层访问，再选择标识类型：

| 场景 | 应使用 | 禁止 |
| :--- | :--- | :--- |
| 苍穹/星瀚/旗舰版/企业版表单插件、操作插件、单据模型、DynamicObject 读写 | FormId、实体/分录标识、字段标识 | 把数据库列名当字段标识 |
| 苍穹/星瀚/旗舰版/企业版下推、单据转换、字段赋值、保存校验 | 源/目标 FormId、实体/分录标识、字段标识、操作标识 | 只拿表名和列名写模型代码 |
| 企业版报表 SQL、存储过程、直接查库；苍穹/星瀚/旗舰版 KSQL、报表、直接查库 | 数据库表名、数据库字段名、必要 JOIN 关系 | 把字段标识直接当 SQL/KSQL 列名 |
| 第三方对接字段映射 | 第三方字段名 + 金蝶字段标识；若用 SQL 再补表名/列名 | 只写中文字段名或只写 API 文档字段 |
| 元数据查询和证据生成 | FormId/FID、父对象、FKERNELXML/fdata、解析后的 evidence | 直接根据示例 SQL 推断真实字段 |

当需求没有说明“用模型 API 读写”还是“用 SQL/报表/存储过程”时，Agent 必须先澄清数据访问方式或继续查证，不能自行选择。字段标识、实体标识、表名和数据库字段名可以同时出现在 evidence 中，但使用时必须按访问层选择。

## 金蝶元数据

企业版 SQL Server 和 Oracle 使用同一套企业版元数据表结构，表名和字段名保持一致；差异只在 SQL 方言，例如 SQL Server 使用 `TOP`，Oracle 使用 `FETCH FIRST ... ROWS ONLY`，参数占位符也不同。

企业版 SQL Server 常用元数据查询：

```sql
SELECT TOP 50
  a.FID,
  a.FBASEOBJECTID,
  b.FNAME,
  c.FNAME AS FSUBSYSTEM
FROM T_META_OBJECTTYPE a
JOIN T_META_OBJECTTYPE_L b ON a.FID = b.FID AND b.FLOCALEID = 2052
LEFT JOIN T_META_SUBSYSTEM_L c ON a.FSUBSYSID = c.FID AND c.FLOCALEID = 2052
WHERE a.FMODELTYPEID IN (100, 400, 500)
  AND b.FNAME LIKE N'%采购%'
ORDER BY b.FNAME;
```

加载企业版表单 XML 元数据：

```sql
SELECT
  CAST(a.FKERNELXML AS NVARCHAR(MAX)) AS FKERNELXML,
  a.FBASEOBJECTID
FROM T_META_OBJECTTYPE a
WHERE a.FID = @P1;
```

MCP 查询返回的 XML 或 JSON 结果必须再解析成结构化数据源证据：

```powershell
kcode metadata .\meta\poorder-mcp.json --evidence
```

或在 Pi 内调用：

```text
kd_metadata_parse path=meta/poorder-mcp.json form=PUR_PurchaseOrder name=采购订单
```

解析结果会输出并写入 `evidence/data-source.md`，包含 FormId/FID、继承链、实体/分录标识、数据库表名、字段标识、数据库字段名和插件引用。后续计划或编码必须使用该结构化证据，不能直接凭原始 `FKERNELXML`、示例 SQL 或记忆推断字段。

企业版 Oracle 对应查询：

```sql
SELECT
  a.FID,
  a.FBASEOBJECTID,
  b.FNAME,
  c.FNAME AS FSUBSYSTEM
FROM T_META_OBJECTTYPE a
JOIN T_META_OBJECTTYPE_L b ON a.FID = b.FID AND b.FLOCALEID = 2052
LEFT JOIN T_META_SUBSYSTEM_L c ON a.FSUBSYSID = c.FID AND c.FLOCALEID = 2052
WHERE a.FMODELTYPEID IN (100, 400, 500)
  AND b.FNAME LIKE '%采购%'
ORDER BY b.FNAME
FETCH FIRST 50 ROWS ONLY;
```

Oracle 加载企业版表单 XML 元数据：

```sql
SELECT
  a.FKERNELXML,
  a.FBASEOBJECTID
FROM T_META_OBJECTTYPE a
WHERE a.FID = :P1;
```

苍穹/星瀚/旗舰版 Cosmic PostgreSQL 元数据表：

```sql
SELECT current_database(), current_schema();

SELECT fid, fnumber, fmodeltype, fparentid, fdata
FROM t_meta_entitydesign
WHERE name LIKE '%采购%'
LIMIT 50;
```

查询前必须确认 `current_database()` 是实际业务库。具体字段名、表结构和 FormId 仍必须以当前项目数据库查询结果或官方 metadata evidence 为准，不能用示例 SQL 当作事实。

PostgreSQL MCP 查询结果同样需要解析：

```powershell
kcode metadata .\meta\entitydesign-result.json --evidence
```

`t_meta_entitydesign.fdata` 是苍穹/Cosmic `EntityMetadata` XML，解析器会读取 `MainEntity/BillEntity/BaseEntity/EntryEntity`、字段 `Key/ParentId/Name` 和实体 `TableName`。如果 XML 未提供显式 `FieldName`，解析器不会把字段 `Key` 当作数据库字段名；SQL/KSQL 编码前必须用当前库 schema 或官方元数据确认真实列名。

旗舰版在 KCode 中属于 Cosmic 家族。插件、操作、单据模型、DynamicObject 和下推代码使用 FormId、实体/分录标识和字段标识；KSQL、报表、存储过程、直接查库或数据修复脚本才使用数据库表名和数据库字段名。旗舰版可以优先使用 `kd_cosmic_metadata product=flagship ...` 取得官方元数据；项目提供本地 `t_meta_entitydesign.fdata` 或 MCP 查询结果时，必须用 `kcode metadata` 或 `kd_metadata_parse` 解析成 `evidence/data-source.md` 后再编码。随包 `kd_table product=flagship` 只能作为旗舰版表结构线索，不能替代当前项目元数据或当前业务库 schema 证据。

## 本地验证记录

2026-06-08 已完成以下 MCP 连接验证：

- SQL Server：`@bilims/mcp-sqlserver@2.0.3` 通过 MCP `execute_query` 对本地企业版库执行 `SELECT TOP 5 FID, FBASEOBJECTID FROM T_META_OBJECTTYPE`，返回 5 行。
- PostgreSQL 连通性：`@modelcontextprotocol/server-postgres@0.6.2` 通过 MCP `query` 对 Docker `postgres15` 默认库执行 `SELECT current_database(), current_schema()`，返回 `postgres/public`；该结果只证明连接可用，不证明元数据库正确。
- PostgreSQL 元数据：Docker `postgres15` 的实际苍穹业务库为 `prod_kmlttest`，其中 `public.t_meta_entitydesign` 已确认存在。后续 KCODE_POSTGRES_URL 必须指向实际业务库，例如 `...:5432/prod_kmlttest`。
- Oracle：按用户确认本轮不连接实测；配置和文档保留，企业版元数据表结构按 SQL Server 同名表处理，实际 SQL 使用 Oracle 方言。
