文件
hyb-oa/scripts/validate-mcp-tools.py
T

108 行
4.0 KiB
Python
可执行文件

#!/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())