docs(mcp): ulthon-mcp 技能文档、AGENTS 索引与 README 特性更新

This commit is contained in:
augushong
2026-08-16 23:33:40 +08:00
parent bba7dec278
commit 9f5d862b71
4 changed files with 205 additions and 0 deletions

View File

@@ -0,0 +1,186 @@
---
name: "ulthon-mcp"
description: "内置 MCP Server/mcp 端点的使用方式密钥管理与授权、AI 客户端Claude Code/Cursor/Cline 等)配置、命令行联调与调用问题排查。"
---
# 内置 MCP Server/mcp
## 何时调用
- 需要让 AI 客户端Claude Code、Cursor、Cline 等)通过 MCP 协议直接操作后台(查列表、改数据、调用业务接口)。
- 需要创建、授权、禁用 MCP 密钥。
- 需要排查 MCP 调用问题401/403/503、Tool not found、会话丢失等
## 机制概览
### 密钥认证
- 客户端请求 `/mcp` 时携带 `Authorization: Bearer <密钥明文>`
- 服务端对明文做 sha256 后与 `ul_system_mcp_key.key` 比对,仅 `status=1` 且未软删的密钥有效。
- 无密钥或密钥错误返回 401`mcp.enable=false` 返回 403服务端未安装 MCP SDK 依赖返回 503。
### 工具集(权限语义)
- 每个密钥通过授权页绑定一组权限节点(`ul_system_mcp_key_node`)。
- 实际可用的工具集 = 密钥授权节点 ∩ 创建者实时权限。权限判定与后台鉴权同源(同一条 `getAdminAllowedNodes` 判定链),不是另写一套规则。
- 创建者权限被回收后,对应工具自动消失(`initialize` 响应的 `capabilities.tools` 键随之消失,调用会返回 Tool not found
- 权限变更最多有约 60 秒延迟(节点权限查询缓存)。
### 调用分发
- `tools/call` 不直接执行业务代码,而是以创建者身份自请求对应的 admin 控制器。节点 `system.quick/index` 分发到 `/admin/system.quick/index`
- 分发使用一次性 token5 分钟有效期,用完即删)并携带 `mcp_internal` 标记,供 CSRF 中间件豁免识别。
- 自请求恒带 `X-Requested-With: XMLHttpRequest``Content-Type: application/json`,保证 `index` 这类方法走 JSON 分支。
- 响应判定HTTP 200 且 body 为 JSON 即成功layui 的 `code=0` 与 success 的 `code=200` 均算成功,原始 JSON 原样返回200 但非 JSON 加 `[HTML页面内容]` 前缀;非 200 加 `[ERROR]` 前缀并提取错误 msg。
### 审计
- 每次调用在 `ul_system_mcp_log` 落一行记录(工具名、参数、成败、耗时),同时密钥的 `use_num` 原子自增。
- 越权或权限已回收的调用同样记审计(`is_success=0`)且 `use_num` 照常自增。`use_num` 的语义是调用次数,不是成功次数。
### 工具名编码
- 权限节点名不能直接做 MCP 工具名,编码规则:`.` 替换为 `-``/` 替换为 `--`
- 例:`system.quick/index` 对应工具名 `system-quick--index`;动作段的驼峰保留,`system.auth/toggleUser` 对应 `system-auth--toggleUser`
- 工具描述中携带原始节点名,按描述可反查权限节点。
## 后台操作
入口:系统管理 → MCP密钥管理`system.mcp_key`)。
- 新增:保存成功后弹窗展示密钥明文,仅此一次,关闭弹窗后无法再查看(数据库只存哈希)。
- 授权:编辑页内配置可调用的权限节点,只显示创建者本人拥有的节点。
- 禁用/删除:立即失效,客户端再调用返回 401。
- 审计MCP调用日志`system.mcp_log`)页查看每次调用的参数与结果。
## 客户端配置
端点地址为 `https://域名/mcp`,认证方式为 Bearer 密钥。示例中 `<key>` 替换为密钥明文。
### Claude Code
CLI 一条命令添加:
```bash
claude mcp add --transport http <name> https://域名/mcp --header "Authorization: Bearer <key>"
```
或 JSON 配置:
```json
{
"mcpServers": {
"<name>": {
"type": "http",
"url": "https://域名/mcp",
"headers": {
"Authorization": "Bearer ${MCP_KEY}"
}
}
}
}
```
### Cursor
```json
{
"url": "https://域名/mcp",
"headers": {
"Authorization": "Bearer ${env:MCP_KEY}"
}
}
```
注意插值语法差异Cursor 用 `${env:VAR}`Claude Code 用 `${VAR}`,两者不通用。
### Cline
```json
{
"type": "streamableHttp",
"url": "https://域名/mcp",
"headers": {
"Authorization": "Bearer <key>"
}
}
```
### Claude Desktop
Claude Desktop 不直接支持 HTTP MCP需要 mcp-remote 桥接:
```bash
npx -y mcp-remote https://域名/mcp --transport http-only --header "Authorization:${AUTH_HEADER}"
```
## 命令行联调tools:http:call
`tools:http:call` 可以不依赖任何 MCP 客户端直接验证 `/mcp` 端点。两个要点:
- 必须加 `--super-token=false`,否则 super token 会覆写 Authorization 头,密钥认证永远失败。
- 协议要求除 `initialize` 外的请求必须带 `Mcp-Session-Id` 头,取自 initialize 响应头。
第一步initialize
```bash
php think tools:http:call --url=/mcp --method=POST --super-token=false \
-H '{"Content-Type":"application/json","Authorization":"Bearer <key>"}' \
--body '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"cli","version":"1.0"}}}'
```
从输出 JSON 的 `response.headers` 中取出 `Mcp-Session-Id`
第二步tools/list
```bash
php think tools:http:call --url=/mcp --method=POST --super-token=false \
-H '{"Content-Type":"application/json","Authorization":"Bearer <key>","Mcp-Session-Id":"<会话ID>"}' \
--body '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
```
第三步tools/call
```bash
php think tools:http:call --url=/mcp --method=POST --super-token=false \
-H '{"Content-Type":"application/json","Authorization":"Bearer <key>","Mcp-Session-Id":"<会话ID>"}' \
--body '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"system-quick--index","arguments":{"page":1,"limit":10}}}'
```
PowerShell 或多层 docker exec 场景下 JSON 引号会被剥壳,稳妥做法是把请求体写入文件,再引用文件内容传给 `--body`
```powershell
Set-Content -Encoding UTF8 runtime\agents\mcp-body.json '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"system-quick--index","arguments":{"page":1,"limit":10}}}'
$hdr = '{"Content-Type":"application/json","Authorization":"Bearer <key>","Mcp-Session-Id":"<会话ID>"}'
php think tools:http:call --url=/mcp --method=POST --super-token=false -H $hdr --body (Get-Content -Raw runtime\agents\mcp-body.json)
```
## 安全注意
- 密钥等价于"创建者权限子集"的凭证:持有密钥的人可以在授权节点范围内执行创建者能做的操作,按敏感凭证保管。
- 授权页只显示创建者拥有的节点,密钥权限不可能超过创建者。
- 创建者权限回收后工具自动收缩,无需重新配置密钥授权。
- 每次调用都有审计记录(含参数),可在 MCP调用日志页追溯。
- 密钥明文只在新增弹窗展示一次,遗失后无法找回,只能删除旧密钥重建。
## 已知行为与限制
- 每次 MCP 调用产生两行日志:`system_log`(以创建者身份记录的系统日志)与 `system_mcp_log`MCP 审计)。
- 演示模式IS_DEMO=true站点 MCP 写操作全部不可用。
- `tools/call` 是服务端自请求,一次调用占用两个 FPM workerFPM 部署需保证 `pm.max_children > 1`
- 生产环境建议显式配置 APP_HOST`.env``app.app_host`):分发回环地址优先取该配置,未配置时按入站请求头还原,反向代理场景可能不准。
- 自定义覆写过 Csrf 中间件的项目,需自行同步保留 `mcp_internal` 豁免逻辑,否则 MCP 写操作会被 CSRF 拦截。
- 页面型节点要拿 assign 数据(下拉选项、默认值等),需在 `tools/call` 的 arguments 里显式传 `"get_page_data": 1`。不要依赖自动注入,自动注入会破坏 `index` 的 JSON 分支。
- `GET /mcp` 返回 405只实现 Streamable HTTP 的 POST 请求/响应模式,不做 SSE 监听流,也没有 resources、prompts 能力。
- 协议版本协商固定回 `2025-11-25`
## 存量项目升级指引
通过 `admin:update` 拉取 MCP 功能代码后,需手动安装 SDK 依赖:
```bash
composer require mcp/sdk guzzlehttp/psr7
```
- 依赖要求 PHP >= 8.1。
- 未安装依赖时 `/mcp` 返回 503带友好提示不影响站点其他功能后台密钥管理页零 SDK 依赖,可正常使用。

View File

@@ -325,3 +325,17 @@ php think admin:update --fetch-only
### 11.5 后续提醒
AI 在涉及框架更新操作前,应先查阅该规则文件了解当前项目的更新策略。
## 12. MCP 依赖升级提示
上游引入内置 MCP Server`/mcp` 端点)后,存量项目通过 `admin:update` 拉到相关代码不会自动获得 composer 依赖:
- MCP 端点依赖 `mcp/sdk``guzzlehttp/psr7`,需手动执行:
```bash
composer require mcp/sdk guzzlehttp/psr7
```
- 依赖要求 PHP >= 8.1。
- 未安装依赖时 `/mcp` 返回 503带友好提示不影响站点其他功能后台 MCP 密钥管理页零 SDK 依赖,可正常使用。
- 密钥管理、客户端配置与联调方式详见 [ulthon-mcp](../ulthon-mcp/SKILL.md) 技能。

View File

@@ -110,6 +110,7 @@ Skills 是"按场景调用的工作流说明",统一以 `.agents/skills/*/SKIL
- 内置定时器与定时任务扩展含多节点协调、run_type 调度):[ulthon-timer](./.agents/skills/ulthon-timer/SKILL.md)
- 页面 / 接口同体:[ulthon-page-api-dual-mode](./.agents/skills/ulthon-page-api-dual-mode/SKILL.md)
- 登录认证Session + Token[ulthon-auth-session-token](./.agents/skills/ulthon-auth-session-token/SKILL.md)
- 内置 MCP Server密钥/授权/客户端配置/命令行联调):[ulthon-mcp](./.agents/skills/ulthon-mcp/SKILL.md)
- 权限与角色管理RBAC CLI[ulthon-permission-cli](./.agents/skills/ulthon-permission-cli/SKILL.md)
- 菜单管理admin:menu:\* CLI[ulthon-admin-menu-cli](./.agents/skills/ulthon-admin-menu-cli/SKILL.md)
- 测试工作流(设计哲学/决策/约束/运行/编写/回归保护):[ulthon-testing](./.agents/skills/ulthon-testing/SKILL.md)

View File

@@ -133,6 +133,10 @@ php think admin:update
* 通过`注解方式`来实现`auth`权限节点管理
* 基于`auth`注解动态扫描生成权限节点,修改注解即生效,无需手动同步
* 完善的后端权限验证以及前面页面按钮显示、隐藏控制
* 内置 MCP Server
* AI 客户端Claude Code、Cursor、Cline 等)可通过 MCP 协议直接操作后台
* Bearer 密钥认证,密钥可用工具为授权节点与创建者实时权限的交集
* 每次调用均有审计日志
* 完善的菜单管理
* 分模块管理
* 无限极菜单