canpoint-ui-mcp — UI 规范查询 MCP
「成果不出门、能力出门」:数据源是本仓库 docs/ 下两套 Design DNA(研学小程序 /
研学后台),服务端用显式 allowlist 投影对外提供 token、组件规格、生成纪律与
截图色彩校验;蓝湖溯源、逐画板中间测量、裁决证据明细等内部数据永不出服务端。
0. 三层发布架构(对齐 canpoint-mcp)
使用方(Claude Code / Cursor / Codex)
│ npx -y canpoint-ui-mcp ← 第 1 层:npm 包装器(零依赖,按自身版本钉死 PyPI 版本)
▼
uvx --from canpoint-ui-mcp==X.Y.Z canpoint-ui-mcp
│ stdio MCP(本仓库 ui_query_mcp.py) ← 第 2 层:PyPI 薄客户端(只含客户端代码,wheel 白名单强制)
│ Bearer usk_xxx(UI_SPEC_API_KEY)
▼
http://175.27.156.19:47393/mcp
远程 FastAPI + FastMCP streamable-http ← 第 3 层:服务端(本仓库 app/,Docker 部署,不进 wheel)
- 工具(6 个,三层同名同签名):
list_platforms/get_tokens/list_components/get_component_spec/get_generation_rules/verify_ui - 健康检查:
GET /health(不鉴权,DNA 未全部就绪时返回 503 degraded) - env 前缀保持
UI_SPEC_*不变(兼容服务器已部署的.env):服务端用UI_SPEC_HOST/PORT/KEY_FILE/DNA_*,客户端用UI_SPEC_SERVER_URL/API_KEY/TIMEOUT/LOG_LEVEL
1. 使用方接入(两种方式)
A. npx 方式(推荐,stdio 薄客户端)
前置:已安装 uv(提供 uvx)。
Claude Code(项目 .mcp.json):
{
"mcpServers": {
"canpoint-ui": {
"command": "npx",
"args": ["-y", "canpoint-ui-mcp"],
"env": {
"UI_SPEC_SERVER_URL": "http://175.27.156.19:47393",
"UI_SPEC_API_KEY": "usk_<服务管理员发放的key>"
}
}
}
}
Cursor(mcp.json)同款。Windows 下若 npx 启动失败,把 command 改为
cmd、args 改为 ["/c", "npx", "-y", "canpoint-ui-mcp"](env 表不变)。
不经 npm 直接用 PyPI 包:uvx canpoint-ui-mcp(同样注入两个 env)。
B. 直连 http 方式(streamable-http)
{
"mcpServers": {
"canpoint-ui": {
"type": "http",
"url": "http://175.27.156.19:47393/mcp",
"headers": { "Authorization": "Bearer usk_<key>" }
}
}
}
2. 175 服务器部署流程(服务端)
构建上下文是仓库根(镜像需要 COPY docs/),Dockerfile 位于 mcp-server/ 下。
# 首次部署
git clone git@github.com:mjwyr/ui-knowledge.git /software/ui-knowledge
cd /software/ui-knowledge/mcp-server
cp .env.example .env # 按需编辑(密钥路径等;env 前缀 UI_SPEC_* 不变)
cp keys.example.json keys.json # 编辑发放真实 key(usk_ 前缀随机串)
cd /software/ui-knowledge
docker build -f mcp-server/Dockerfile -t canpoint-ui-mcp:latest .
# 启动(.env 与 keys.json 只读挂载,logs 落宿主机)
docker rm -f canpoint-ui-mcp 2>/dev/null
docker run -d --name canpoint-ui-mcp --restart unless-stopped \
-p 47393:8002 -e TZ=Asia/Shanghai \
-v /software/ui-knowledge/mcp-server/.env:/app/mcp-server/.env:ro \
-v /software/ui-knowledge/mcp-server/keys.json:/app/mcp-server/keys.json:ro \
-v /software/ui-knowledge/mcp-server/logs:/app/mcp-server/logs \
canpoint-ui-mcp:latest
# 验证
curl -s http://127.0.0.1:47393/health # 期望 {"status":"ok","data":{"mini":true,"admin":true}}
更新(数据或代码变更后):
cd /software/ui-knowledge && git pull
docker tag canpoint-ui-mcp:latest canpoint-ui-mcp:prev-$(date +%Y%m%d) # 回滚锚点
docker build -f mcp-server/Dockerfile -t canpoint-ui-mcp:latest .
docker rm -f canpoint-ui-mcp && docker run -d ...(同上启动命令)
回滚:docker tag canpoint-ui-mcp:prev-YYYYMMDD canpoint-ui-mcp:latest 后重跑
docker rm -f + docker run。
3. 客户端包发布流程(PyPI + npm)
发布用一键脚本,版本号以 pyproject.toml 为唯一事实来源(自动同步到
npm/package.json):
cd mcp-server
python scripts/publish.py --dry-run # 试跑(构建+白名单校验,不真实发布)
python scripts/publish.py --set-version <版本> --platform all # 正式发布
python scripts/publish.py --bump patch # 升补丁版本后双平台发布
脚本内置防线:
- 版本重复探测:发布前 HTTP 探测 PyPI/npm,该版本已存在则拒发;
- wheel 内容白名单:构建后逐条检查 zip 内容,
app/、tests/、scripts/、npm/、Dockerfile、requirements*.txt、keys*.json、.env等任何一条命中 即拒发(服务端与密钥绝不进包); - npm 官方源钉死:全局 registry 是 npmmirror 只读镜像,脚本显式
--registry https://registry.npmjs.org/; - 镜像同步:npm 发布成功后自动
PUT https://registry.npmmirror.com/-/package/canpoint-ui-mcp/syncs触发 npmmirror 同步(同步完成前镜像侧 npx 仍拿旧版本)。
凭据位置(均不进 git):
- PyPI:
PYPI_TOKEN环境变量,或本机已登录的uv(uv publish直接发); - npm:
NPM_TOKEN环境变量(脚本写临时npm/.npmrc,用后即删),或~/.npmrc已登录态(npm login;Automation 类型 token 免 OTP)。
npm 包装器按自身版本号钉死 PyPI 包版本(uvx --from canpoint-ui-mcp==<npm版本>),
两平台必须同版本发布。
4. key 发放 / 吊销流程
- 编辑服务器上的
/software/ui-knowledge/mcp-server/keys.json:- 发放:追加
{"id":"姓名","key":"usk_<随机串>","enabled":true,"note":"用途"}(随机串生成:python -c "import secrets;print('usk_'+secrets.token_urlsafe(32))"); - 吊销:把对应条目
enabled改为false或直接删除。
- 发放:追加
docker restart canpoint-ui-mcp(key 表在启动时加载)。- key 表缺失/为空/解析失败时服务 fail-closed:进程照常启动、
/health可访问,但/mcp拒绝一切请求。
5. 审计日志
-
服务端:
mcp-server/logs/ui_audit.log(容器内/app/mcp-server/logs/,按天轮转、 保留 30 天;服务端运行日志为同目录ui_spec_server.log)。每次工具调用一行:2026-09-08 12:00:00,123 key_id=张三 tool=get_tokens args=platform=mini category=color status=ok took=5ms -
客户端:
logs/ui_client.log(相对客户端进程工作目录,按天轮转、保留 30 天), 每次工具调用记 tool + 参数摘要(截断 80 字符)+ 结果状态 + 耗时;只写文件与 stderr,绝不写 stdout(stdio 协议流)。 -
安全红线:绝不记录 key 值本身;绝不记录 base64 图片数据(
verify_ui只记 platform 与图片字节数);args 摘要单行化截断 80 字符。
6. 本地开发与测试
cd mcp-server
python --version # 需要 3.10+
pip install -r requirements.txt # 服务端依赖(客户端只需 mcp/httpx)
python -m unittest discover -s tests -v
# 本地起服务端
python -m app.main # 或 uvicorn app.main:app --port 8002
# 本地起 stdio 客户端(连远程或本地服务端)
UI_SPEC_SERVER_URL=http://127.0.0.1:8002 UI_SPEC_API_KEY=usk_xxx python ui_query_mcp.py
环境变量见 .env.example(复制为 .env,不进 git);本地 keys.json 可参照
keys.example.json 制作(不进 git)。
7. 安全设计(投影 allowlist + wheel 白名单)
数据投影——出门的:色彩 token、typography 阶梯、spacing、shape、elevation、 layout/density(admin_chrome 几何、表格密度 token、breakpoints_fact、小程序 chrome)、组件规格、生成纪律(version_policy 结论、missing_states、裁决结论、 设计事实)、design_style 定性字段、visual_effects 结论字段。
永不出门的(app/views.py 结构性排除 + 字符串消毒双保险,测试断言):
meta.source_references、measured_palette 聚合、measurement 配置、
meta 其余溯源字段(lanhu_project / original_assets / sampling 说明等)、
任何含 lanhuapp / alipic / image_id / intermediate 路径的字符串、
adjudications 的 values/source 证据明细。
发布物收敛——PyPI wheel 只含 ui_query_mcp.py、logging_config.py、
clients/(见 pyproject [tool.setuptools] 白名单),客户端依赖收敛为
mcp>=1.6,<2 + httpx;scripts/publish.py 构建后强制校验,违规拒发。
API key 只从环境变量读取,绝不嵌入可分发包;UI_SPEC_SERVER_URL 拒绝内嵌
basic auth(key 是唯一客户端凭据)。
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file canpoint_ui_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: canpoint_ui_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac025790642aeb4fc05e2e992beb85c0cf3063b7c43361d5d2b10724f74c6306
|
|
| MD5 |
5d748273b69c7db3178c33f0a8cc92a3
|
|
| BLAKE2b-256 |
39b060ed8cf4983abbff2df9cade5e4f2d992c2cfb82181f64d2d9091e14f98d
|