docs(P19MCP1): 落地MCP只读工具链基准与校验脚本

这个提交包含在:
2026-03-10 14:20:59 +08:00
父节点 f5f40f7673
当前提交 fdf3c43244
共修改 4 个文件,包含 214 行新增和 5 行删除
+12
查看文件
@@ -0,0 +1,12 @@
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-postgres",
"postgresql://<READONLY_USER>:<PASSWORD>@<HOST>:<PORT>/<DB>"
]
}
}
}
+90
查看文件
@@ -0,0 +1,90 @@
# MCP Tools (Project)
Generated: 2026-03-09
Current Phase: `P19+MCP-1`
Source: 官方 MCP package 文档 + `P19+MCP-1` 执行合同 + 仓库内校验脚本。当前 shell 无法使用 `codex mcp list --json`,因此本目录不以运行时 CLI 枚举作为唯一事实源。
## Enabled Servers
- `postgres`
## Candidate Servers (Not Enabled)
- `github` — github deferred;官方 `@modelcontextprotocol/server-github` 当前暴露读写混合工具集,不满足 `Read-only Tools Baseline`,因此本期不启用,也不纳入 enabled servers。
## Tools
- `postgres:query` — 执行数据库只读排障、schema 核对、账本校验与对账查询;所有查询均应运行在 `READ ONLY` 事务语义下。
## Resources
- `postgres://<host>/<table>/schema` — schema resources,用于读取表结构、字段类型与列定义,不用于业务写入。
## Server: postgres
### 用途
- 数据库只读排障
- Prisma / SQL 迁移核对
- 预算、ERP、资产、采购等账本或主数据只读核验
### 输入与能力范围
- 通过连接串连接 PostgreSQL
- 暴露 `postgres:query` 工具
- 暴露 schema resources 用于表结构读取
- 允许执行 `SELECT` / 只读检查类 SQL
### 允许操作
- 查询表结构与字段定义
- 查询计数、汇总、余额、绑定关系、Outbox 状态
- 为本地回归或审计结论提供只读证据
### 禁止操作
- 禁止 `INSERT / UPDATE / DELETE / DDL`
- 禁止修改预算、工作流、资产、采购、报销等核心业务状态
- 禁止绕过仓库内已有的本地验证命令
- 禁止把 MCP 当作应用运行时依赖
### 凭据要求
- 必须使用只读数据库账号
- 必须使用最小权限连接串
- **不提交真实密钥/连接串**,包括但不限于数据库密码、主机地址、PAT、API Token
### 示例配置
- 仓库示例文件:`.mcp.json.example`
- 仅提供 `postgres` 示例,不提供 `github` 启用段
- 占位连接串固定写为:`postgresql://<READONLY_USER>:<PASSWORD>@<HOST>:<PORT>/<DB>`
### 回滚方式
- 删除本机未跟踪的 `.mcp.json`
- 停止在本地 CLI 中启用 `postgres` MCP
- 保留 `docs/mcp-tools.md` 作为事实源与治理文档,不影响业务系统运行
## Server: github (Deferred)
### 当前不启用原因
- 官方 GitHub MCP server 当前为读写混合工具集
- 现阶段无法以官方能力保证“只读基线”
- 若贸然启用,容易突破 `P19+MCP-1` 的只读边界
### 本期固定结论
- `github` 当前不进入 enabled servers
- `github` 当前不纳入“可立即使用工具目录”
- 本期不提交 GitHub MCP 示例启用配置
### 未来启用前置条件
- 需要新的路线合同显式解锁,如 `P19+MCP-2` 或后续治理 phase
- 需要确认只读模式、最小权限 PAT 策略、审计与回滚边界
- 需要把读写操作边界从 `P19+MCP-1` 的只读基线中拆分出来单独治理
## Local Activation Checklist
1. 确认本机支持 MCP 的 CLI 环境可用;若 `codex mcp list --json` 不可用,仍以本文和 `.mcp.json.example` 为唯一仓库事实源。
2. 将 `.mcp.json.example` 复制为本机未跟踪的 `.mcp.json`。
3. 将占位连接串替换为**只读数据库账号**连接串。
4. 确认不会把 `.mcp.json`、密码或其他真实凭据提交进仓库。
5. 仅启用 `postgres`,不得自行把 `github` 提升为 enabled server。
6. 使用 MCP 后,仍必须继续执行仓库内本地验证命令与回归脚本。
## Safety Rules
- MCP 仅用于只读排障、数据库验证与审计辅助。
- MCP 不得写数据库,不得修改业务状态,不得代替测试。
- `docs/mcp-tools.md` 是 MCP 工具目录事实源;若未来配置与本文冲突,以本文与执行合同为准,先修订合同再变更配置。
- `github deferred` 在本期为硬边界,不得在实现过程中偷偷启用。
## Rollback
- 停止使用本机 `.mcp.json` 中的 `postgres` server。
- 删除本机凭据或改回占位配置。
- 保留文档、示例配置与校验脚本,作为后续 phase 的治理基线。
@@ -1,6 +1,6 @@
ID,Title,Description,Acceptance,Test_Method,Tools,Dev_Status,Review1_Status,Regression_Status,Files,Dependencies,Notes ID,Title,Description,Acceptance,Test_Method,Tools,Dev_Status,Review1_Status,Regression_Status,Files,Dependencies,Notes
P19MCP1-0,P19MCP1执行合同建档,创建并校验MCP只读工具基线执行合同CSV,CSV通过校验且字段完整并冻结只读MCP范围,python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,manual,TODO,TODO,TODO,issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,[],P19MCP1只做只读MCP目录与使用边界 不引入运行时业务能力 P19MCP1-0,P19MCP1执行合同建档,创建并校验MCP只读工具基线执行合同CSV,CSV通过校验且字段完整并冻结示例配置优先与只读MCP范围,python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,manual,DONE,DONE,DONE,issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,[],P19MCP1只做治理文档 示例配置与校验脚本 不引入运行时业务能力
P19MCP1-1,MCP工具目录建档,新增docs/mcp-tools.md并用目录生成流程固化postgres与github的可用工具清单,docs/mcp-tools.md可稳定重建且仅包含postgres github两类只读MCP工具,manual: 使用mcp-tools-catalog生成docs/mcp-tools.md并人工核对内容,manual,TODO,TODO,TODO,docs/mcp-tools.md | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,"[""P19MCP1-0""]",若工具目录需脚本辅助 只能新增文档生成或校验脚本 P19MCP1-1,MCP工具目录建档,新增docs/mcp-tools.md并固化只读工具目录与候选server边界,docs/mcp-tools.md可稳定重建且enabled servers仅postgres github仅作为deferred candidate记录,python3 scripts/validate-mcp-tools.py,manual,DONE,DONE,DONE,docs/mcp-tools.md | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,"[""P19MCP1-0""]",当前shell中codex mcp list不可作为唯一事实源 因此以官方文档和仓库校验脚本共同收口
P19MCP1-2,MCP使用边界与回滚策略,补MCP的用途 权限 禁止事项 审计边界与失败退回策略,MCP边界文档与集成边界文档一致且明确禁止写库改状态绕过本地验证,python3 scripts/validate-feature-matrix.py,manual,TODO,TODO,TODO,docs/integration-boundaries.md | docs/mcp-tools.md | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,"[""P19MCP1-1""]",首次启用仍限定只读排障和PR协作 不接应用运行时 P19MCP1-2,MCP使用边界与回滚策略,补MCP的用途 禁止事项 凭据边界 GitHub deferred原因与本机回滚策略,MCP边界文档与集成边界文档一致且明确只读边界以postgres为唯一真实启用server,python3 scripts/validate-mcp-tools.py && python3 scripts/validate-feature-matrix.py,manual,DONE,DONE,DONE,docs/integration-boundaries.md | docs/mcp-tools.md | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,"[""P19MCP1-1""]",GitHub官方server当前为读写混合工具集 本期不启用
P19MCP1-3,MCP文档校验与治理脚本,如有必要新增最小校验脚本以验证mcp工具目录存在且格式可复建,仓库内存在可复用的MCP目录校验流程且不改变业务接口,manual: 运行新增校验脚本或文档生成命令并确认无错误,manual,TODO,TODO,TODO,scripts | docs/mcp-tools.md | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,"[""P19MCP1-2""]",禁止为MCP引入新的服务端运行时依赖 P19MCP1-3,MCP文档校验与治理脚本,新增示例配置与最小校验脚本以验证目录文档和本地启用基线闭环,docs mcp-tools .mcp.json.example validate-mcp-tools.py AGENTS.md形成可重复校验闭环且不改变业务接口,python3 scripts/validate-mcp-tools.py,manual,DONE,DONE,DONE,.mcp.json.example | scripts/validate-mcp-tools.py | AGENTS.md | docs/mcp-tools.md | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,"[""P19MCP1-2""]",不提交真实.mcp.json 不提交任何PAT token或数据库连接串
P19MCP1-4,P19MCP1文档矩阵与验收收口,完成MCP工具目录 集成边界 Feature Matrix与回归说明的统一收口,文档收口完成且无业务回归并可作为后续AI phase前置条件,python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv && python3 scripts/validate-feature-matrix.py,manual,TODO,TODO,TODO,docs/mcp-tools.md | docs/integration-boundaries.md | docs/feature-matrix.md | scripts/validate-feature-matrix.py | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,"[""P19MCP1-3""]",P19MCP1完成后才允许按合同讨论真实MCP使用 P19MCP1-4,P19MCP1文档矩阵与验收收口,完成MCP工具目录 集成边界 Feature Matrix与事实源校验的统一收口,Feature Matrix更新为P5-P19+IM-1+ERP-3+R10+MCP-1且总数为230并通过全部校验,python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv && python3 scripts/validate-mcp-tools.py && python3 scripts/validate-feature-matrix.py && git diff --check,manual,DONE,DONE,DONE,docs/mcp-tools.md | docs/integration-boundaries.md | docs/feature-matrix.md | scripts/validate-feature-matrix.py | scripts/validate-mcp-tools.py | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv,"[""P19MCP1-3""]",P19MCP1完成后P19+AI-1可将docs/mcp-tools.md视为稳定前置事实源
1 ID Title Description Acceptance Test_Method Tools Dev_Status Review1_Status Regression_Status Files Dependencies Notes
2 P19MCP1-0 P19MCP1执行合同建档 创建并校验MCP只读工具基线执行合同CSV CSV通过校验且字段完整并冻结只读MCP范围 CSV通过校验且字段完整并冻结示例配置优先与只读MCP范围 python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv manual TODO DONE TODO DONE TODO DONE issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv [] P19MCP1只做只读MCP目录与使用边界 不引入运行时业务能力 P19MCP1只做治理文档 示例配置与校验脚本 不引入运行时业务能力
3 P19MCP1-1 MCP工具目录建档 新增docs/mcp-tools.md并用目录生成流程固化postgres与github的可用工具清单 新增docs/mcp-tools.md并固化只读工具目录与候选server边界 docs/mcp-tools.md可稳定重建且仅包含postgres github两类只读MCP工具 docs/mcp-tools.md可稳定重建且enabled servers仅postgres github仅作为deferred candidate记录 manual: 使用mcp-tools-catalog生成docs/mcp-tools.md并人工核对内容 python3 scripts/validate-mcp-tools.py manual TODO DONE TODO DONE TODO DONE docs/mcp-tools.md | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv ["P19MCP1-0"] 若工具目录需脚本辅助 只能新增文档生成或校验脚本 当前shell中codex mcp list不可作为唯一事实源 因此以官方文档和仓库校验脚本共同收口
4 P19MCP1-2 MCP使用边界与回滚策略 补MCP的用途 权限 禁止事项 审计边界与失败退回策略 补MCP的用途 禁止事项 凭据边界 GitHub deferred原因与本机回滚策略 MCP边界文档与集成边界文档一致且明确禁止写库改状态绕过本地验证 MCP边界文档与集成边界文档一致且明确只读边界以postgres为唯一真实启用server python3 scripts/validate-feature-matrix.py python3 scripts/validate-mcp-tools.py && python3 scripts/validate-feature-matrix.py manual TODO DONE TODO DONE TODO DONE docs/integration-boundaries.md | docs/mcp-tools.md | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv ["P19MCP1-1"] 首次启用仍限定只读排障和PR协作 不接应用运行时 GitHub官方server当前为读写混合工具集 本期不启用
5 P19MCP1-3 MCP文档校验与治理脚本 如有必要新增最小校验脚本以验证mcp工具目录存在且格式可复建 新增示例配置与最小校验脚本以验证目录文档和本地启用基线闭环 仓库内存在可复用的MCP目录校验流程且不改变业务接口 docs mcp-tools .mcp.json.example validate-mcp-tools.py AGENTS.md形成可重复校验闭环且不改变业务接口 manual: 运行新增校验脚本或文档生成命令并确认无错误 python3 scripts/validate-mcp-tools.py manual TODO DONE TODO DONE TODO DONE scripts | docs/mcp-tools.md | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv .mcp.json.example | scripts/validate-mcp-tools.py | AGENTS.md | docs/mcp-tools.md | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv ["P19MCP1-2"] 禁止为MCP引入新的服务端运行时依赖 不提交真实.mcp.json 不提交任何PAT token或数据库连接串
6 P19MCP1-4 P19MCP1文档矩阵与验收收口 完成MCP工具目录 集成边界 Feature Matrix与回归说明的统一收口 完成MCP工具目录 集成边界 Feature Matrix与事实源校验的统一收口 文档收口完成且无业务回归并可作为后续AI phase前置条件 Feature Matrix更新为P5-P19+IM-1+ERP-3+R10+MCP-1且总数为230并通过全部校验 python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv && python3 scripts/validate-feature-matrix.py python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv && python3 scripts/validate-mcp-tools.py && python3 scripts/validate-feature-matrix.py && git diff --check manual TODO DONE TODO DONE TODO DONE docs/mcp-tools.md | docs/integration-boundaries.md | docs/feature-matrix.md | scripts/validate-feature-matrix.py | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv docs/mcp-tools.md | docs/integration-boundaries.md | docs/feature-matrix.md | scripts/validate-feature-matrix.py | scripts/validate-mcp-tools.py | issues/2026-03-09_10-25-00-p19-mcp-1-l4-readonly-tools-baseline.csv ["P19MCP1-3"] P19MCP1完成后才允许按合同讨论真实MCP使用 P19MCP1完成后P19+AI-1可将docs/mcp-tools.md视为稳定前置事实源
+107
查看文件
@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""Validate MCP baseline documents for P19+MCP-1."""
from __future__ import annotations
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
DOC_PATH = ROOT / "docs" / "mcp-tools.md"
EXAMPLE_PATH = ROOT / ".mcp.json.example"
AGENTS_PATH = ROOT / "AGENTS.md"
def fail(message: str) -> int:
print(f"[ERR] {message}")
return 1
def require(text: str, needle: str, label: str, errors: list[str]) -> None:
if needle not in text:
errors.append(f"missing {label}: {needle}")
def main() -> int:
errors: list[str] = []
if not DOC_PATH.exists():
errors.append(f"missing file: {DOC_PATH}")
if not EXAMPLE_PATH.exists():
errors.append(f"missing file: {EXAMPLE_PATH}")
if not AGENTS_PATH.exists():
errors.append(f"missing file: {AGENTS_PATH}")
if errors:
for error in errors:
print(f"[ERR] {error}")
return 1
doc_text = DOC_PATH.read_text(encoding="utf-8")
agents_text = AGENTS_PATH.read_text(encoding="utf-8")
require(doc_text, "## Enabled Servers", "section", errors)
require(doc_text, "- `postgres`", "enabled postgres", errors)
require(doc_text, "## Candidate Servers (Not Enabled)", "section", errors)
require(doc_text, "`github`", "candidate github", errors)
require(doc_text, "postgres:query", "tool", errors)
require(doc_text, "READ ONLY", "readonly phrase", errors)
require(doc_text, "不提交真实密钥/连接串", "secret hygiene", errors)
require(doc_text, "github deferred", "github deferred", errors)
if "docs/mcp-tools.md" not in agents_text:
errors.append("AGENTS.md missing docs/mcp-tools.md reference")
try:
example = json.loads(EXAMPLE_PATH.read_text(encoding="utf-8"))
except json.JSONDecodeError as exc:
errors.append(f"invalid json in .mcp.json.example: {exc}")
example = {}
servers = example.get("mcpServers") if isinstance(example, dict) else None
if not isinstance(servers, dict):
errors.append(".mcp.json.example missing mcpServers object")
else:
if set(servers.keys()) != {"postgres"}:
errors.append(f".mcp.json.example must contain only postgres server, got: {sorted(servers.keys())}")
postgres = servers.get("postgres")
if not isinstance(postgres, dict):
errors.append("postgres server config missing or invalid")
else:
command = postgres.get("command")
args = postgres.get("args")
if command != "npx":
errors.append(f"postgres command must be npx, got: {command}")
if not isinstance(args, list):
errors.append("postgres args must be a list")
else:
flattened = " ".join(str(item) for item in args)
if "@modelcontextprotocol/server-postgres" not in flattened:
errors.append("postgres args missing official server package")
if "<READONLY_USER>" not in flattened:
errors.append("postgres args missing readonly user placeholder")
if "<PASSWORD>" not in flattened or "<HOST>" not in flattened or "<PORT>" not in flattened or "<DB>" not in flattened:
errors.append("postgres args missing connection placeholders")
example_text_upper = EXAMPLE_PATH.read_text(encoding="utf-8").upper()
for forbidden in ["GITHUB", "TOKEN"]:
if forbidden in example_text_upper:
errors.append(f".mcp.json.example contains forbidden token: {forbidden}")
if "postgresql://localhost/" in EXAMPLE_PATH.read_text(encoding="utf-8"):
errors.append(".mcp.json.example must not contain a concrete localhost connection string")
if errors:
print("[ERR] MCP tools validation failed")
for error in errors:
print(f" - {error}")
return 1
print("[OK] MCP tools baseline validated (docs/mcp-tools.md, .mcp.json.example, AGENTS.md)")
return 0
if __name__ == "__main__":
raise SystemExit(main())