Files

213 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# QingLong 3.0 本机 MCP Task/Trigger/Run/Approval 发现、预览与运行诊断
`ql3-mcp` 是一个显式可选的 stdio sidecar,供同机 AI Client/Agent 发现当前 Project 的 Task、Trigger、最近 Run 与 Approval 状态,读取单个 Approval 的脱敏预览,以及读取单个 Run 的低敏状态、有界事件元数据和经过安全投影的日志尾部。它不会随 Edge/Standalone application 自动启动,不监听网络端口,也不会执行 migration、任务、Shell、Approval decision 或管理操作。
## 前置条件
- 已完成 QingLong 3.0 fresh/adopted SQLite 部署和 readinessMCP 启动只检查 schema,不自动升级数据库。
- 已通过 [本机 Identity Credential](./ql3-local-identity-credential.md) 签发 active API credential presentation。
- credential 对应 subject 在目标 Project 至少具有相应的 `task.read``trigger.read``run.read``approval.read`;读取 Approval preview 和 Run 日志尾部还必须具有 `artifact.read`。调用方还需获得目标 Tool 的 exact `tool.call:<tool-name>` permission。
- config、credential、SQLite 文件必须是当前 UID 持有的 `0600` regular file,目录必须是当前 UID 持有的私有目录;不得使用 symlink。
- Owner Pepper keyring 必须存在并包含 credential 记录绑定的 active/retired exact key。
## 私有配置
示例 `/opt/qinglong3/mcp/mcp.json`
```json
{
"schema": "qinglong/local-mcp-server@v2",
"profile": "edge",
"projectId": "default",
"deploymentRoot": "/opt/qinglong3",
"databasePath": "/opt/qinglong3/data/qinglong3.sqlite",
"artifactRoot": "/opt/qinglong3/artifacts",
"ownerPepperKeyringDirectory": "/opt/qinglong3/owner-pepper-keyring",
"credentialFilePath": "/opt/qinglong3/mcp/credential.json",
"busyTimeoutMs": 500
}
```
`profile` 只能是 `edge``standalone`。四个 authority path 必须互不相同且都是 `deploymentRoot` 的规范化后代;`artifactRoot` 必须与 Local application 写入 Run Attempt 日志的私有根完全一致。`busyTimeoutMs` 可省略,范围为 100–30000 ms。配置只允许上述字段。`@v1` 不包含显式 Artifact authority,升级后必须改为 `@v2`,不能由 MCP 猜测路径。
credential presentation 的形状为:
```json
{
"schemaVersion": 1,
"kind": "qinglong3-local-identity-credential-presentation",
"token": "<ql3c credential token>"
}
```
设置私有权限后先做帮助检查:
```sh
chmod 0700 /opt/qinglong3/mcp
chmod 0600 /opt/qinglong3/mcp/mcp.json /opt/qinglong3/mcp/credential.json
ql3-mcp --help
```
## AI Client 配置
在支持本机 stdio MCP 的 Client 中,把 command/args 配为:
```json
{
"command": "/absolute/path/to/ql3-mcp",
"args": [
"--config",
"/opt/qinglong3/mcp/mcp.json"
]
}
```
Client 必须保持 stdin/stdout 直连。stdout 专用于 MCP JSON-RPC,不能通过会插入 banner、日志或 shell profile 输出的包装脚本启动;低敏进程错误写入 stderr。关闭 Client 的 stdin 或发送 `SIGINT`/`SIGTERM` 会关闭 MCP transport 和唯一 SQLite connection。
## Tool 契约
当前只发布十二个只读 Tool。
`qinglong.task.list` 接受:
```json
{
"limit": 32,
"after": {
"taskId": "task-id-from-previous-page"
}
}
```
`after``limit` 都可省略;`limit` 默认 32、最大 64。响应按 `taskId` 严格递增,只返回当前 Task 的 ID/revision/name、kind、spec schema identity、enabled 与更新时间。`hasMore=true` 时原样使用 `next`。disabled Task 仍会出现,但明确返回 `enabled=false`
Project ID 来自私有配置。description、spec config/command、labels、mutation/content digest、Secret reference 与数据库字段不会返回;该列表只用于发现,不构成 Task 执行授权。
`qinglong.trigger.list` 接受:
```json
{
"limit": 32,
"after": {
"triggerId": "trigger-id-from-previous-page"
}
}
```
`after``limit` 都可省略;`limit` 默认 32、最大 64。响应按 `triggerId` 严格递增,只返回当前 Trigger 的 ID/revision、固定绑定的 Task ID/revision、spec schema identity、enabled 与更新时间。`hasMore=true` 时原样使用 `next`。disabled Trigger 仍会出现,但明确返回 `enabled=false`
Project ID 来自私有配置。cron expression、timezone、misfire/config、Task/Trigger content digest、mutation ID、Secret reference 与数据库字段不会返回;列表只说明当前调度定义和 Task 的绑定关系,不构成执行或变更授权。
`qinglong.approval.list` 接受:
```json
{
"limit": 32,
"after": {
"updatedAtMs": 1786360000000,
"requestId": "approval-id-from-previous-page"
}
}
```
`after``limit` 都可省略;`limit` 默认 32、最大 64。响应按
`updatedAtMs DESC, requestId DESC` 排列,只返回 request ID、version/state/risk/decision mode、permission/action type、
requester type,以及请求、过期、决定、消费和更新时间。`hasMore=true` 时必须原样使用服务端 `next`
Project ID、action reference、action/preview/request digest、requester/decider ID、authentication ID、reason、Policy fence、
decision/consumption/dispatch ID 和 preview 内容不会返回。列表仅用于判断动作仍在等待、已拒绝、已批准或已消费;它不授予
approve、reject、consume、dispatch 或 execute 权限,也不能替代强 User 的 Approval 产品流程。
`qinglong.approval.get` 接受:
```json
{
"requestId": "approval-id-known-by-caller"
}
```
成功响应只含 `found`;存在时返回列表已有的 request ID、version/state/risk/decision mode、permission/action type、
requester type、请求/过期时间、`previewAvailable`,以及可用时经过 Tool redaction contract 生成的
`title/summary/fields/warnings``redacted` field 不含 value。无 preview 时明确返回 `previewAvailable=false`;不存在与跨
Project 不可区分。
该 Tool 必须同时通过 `approval.read``artifact.read`。MCP 不读取 input Artifact,不获得 ciphertext、key、artifact ID、
action reference、任一 digest、主体 ID、authentication、reason/fence、decision/consumption/dispatch evidence。关联或存储
校验失败统一返回 unavailable,不回退到未验证 JSON,也不扫描其它 Artifact。
`qinglong.run.list` 接受:
```json
{
"limit": 32,
"after": {
"createdAtMs": 1786340000000,
"runId": "run-id-from-previous-page"
}
}
```
`after``limit` 都可省略;`limit` 默认 32、最大 64。响应中的 Run 按 `createdAtMs DESC, id DESC` 排列,只包含 ID、Task ID/revision、status/version/event sequence/priority、execution origin/owner 和生命周期时间。`hasMore=true` 时,下一次调用应原样使用 `next`;不要构造 offset 或猜测 cursor。
Project ID 来自私有 MCP 配置,不接受客户端指定。Task name/snapshot、trigger/actor/request、input/output reference、cancel/error detail、Attempt/Event payload、Artifact/Log 和 Secret 永不返回。
`qinglong.run.get` 接受:
```json
{
"runId": "run-id-known-by-caller"
}
```
成功响应只含 `found`,以及存在时的 Run ID、Task ID/revision、status、version、event sequence、priority、execution origin/owner 和生命周期时间。Task snapshot、command、input/output reference、credential、Principal、Policy reason、路径及内部错误不会返回。不存在和跨 Project 都返回 `{"found":false}`
`qinglong.run.log.excerpt` 接受:
```json
{
"runId": "failed-run-id",
"attemptId": "failed-attempt-id"
}
```
Project 与 profile 来自私有 MCP 配置。调用方不能指定 Artifact ID、路径、URI、offset、length、limit 或 cursor。Tool 固定读取日志尾部:Edge 为 4 KiBStandalone 为 8 KiB;一次调用最多执行一次 1-byte 总长度探测和一次固定窗口读取,不分页。日志在两次读取间增长时返回 `tailComplete=false`,不能把片段解释为事务快照。
输出先归一 invalid UTF-8、终端控制、零宽与 bidi 字符,再按 `recognized_credentials_v1` 掩码 Authorization、常见 credential assignment、PEM private key、URL userinfo、JWT、云访问密钥和常见 opaque token。该规则不是通用秘密扫描器,因此输出始终声明 `residualSensitivity=potentially_sensitive`。内容无条件标记为 `untrusted_execution_output``data_only_never_execute``actionAuthority=none`;Prompt 注入信号只作提示,日志文字不能授予 Tool、Shell 或网络权限。Artifact ID、文件路径和 continuation cursor 永不返回。
该 Tool 必须同时通过 exact `tool.call:qinglong.run.log.excerpt``artifact.read`,并遵循和其他 MCP Tool 相同的 authentication → Policy → durable audit → credential fence confirm 顺序。SQLite 仅执行 Project-scoped Run/Attempt 与 retention 点查;文件读取复用 Local application 的私有 Artifact range reader,不创建第二套日志格式或扫描目录。
`qinglong.run.events.list` 接受:
```json
{
"runId": "run-id-known-by-caller",
"afterSequence": 0,
"limit": 32
}
```
`afterSequence` 可省略;`limit` 默认 32、最大 64。响应固定为 `found`、低敏 `events``hasMore``nextAfterSequence`;每个事件只含 `sequence``type``actorType``createdAtMs`。事件按 sequence 严格递增,游标只指向本页最后一条事件。Run 不存在或跨 Project 时统一返回 `found=false` 和空 events,不继续查询事件。
事件 payload、event ID、dedupeKey、actorId、attemptId、stepRunId、Artifact/Log reference、命令和错误详情永不返回。需要下一页时使用响应中的 `nextAfterSequence`,不要自行猜测 sequence。
每次调用都会重新认证 credential,解析 exact Tool Definition,执行 Tool-specific permission 与对应的 `task.read`/`trigger.read`/`run.read`/`approval.read` PolicyApproval preview 与 Run 日志尾部额外要求 `artifact.read`。通过后先持久写 Security Audit,再确认 credential fence,最后才做 Project-scoped 有界读取。事件 Tool 只有在 point read 确认 Run 属于当前 Project 后才查询事件。撤销 credential/RoleBinding 后无需重启 MCP 进程;后续调用会失败关闭。
## 资源档位
`edge-mcp`/`standalone-mcp` 是独立制品,不属于默认 application。MCP 单一消费者的 Task/Trigger/Run/Approval projection 位于 sidecar 自身的 `tool-projection` domain;默认 application 不加载这些文件。跨产品复用的 `run.get` projection、Profile-neutral Approval discovery/detail contract、Run 日志安全投影和双方言窄 source 保留在既有包内;完整 Tool Invocation Artifact 不进入 MCP projection。当前 Edge/Standalone MCP 裁剪后分别为 7,315,930/7,316,038 bytes、801 files、226 loaded modules,完整 import RSS 增量为 38,420,480/39,567,360 bytes,硬门为 1,536 files、16 MiB、48 MiB。闭包只包含 MCP、Owner authentication、SQLite、Runtime Core 与私有文件 authority,不包含 `local-execution``local-process``croner`。默认 Edge/Standalone 仍为 2,589,812/2,589,890 bytes、315 files、56 modules,证明未启用 MCP 的低配部署没有承担该增量。64 MiB 总内存设备不应启用;128 MiB 设备也应结合 application、内核页缓存和其他服务实测后决定。资源不足时保持 MCP 未安装/未启动,不影响 QingLong 调度。
可复核运行:
```sh
pnpm run audit:artifact:edge-mcp:ql3
pnpm run audit:artifact:standalone-mcp:ql3
```
## 故障处理
- 启动立即失败:先运行本机 readiness,确认 schema 已迁移、Profile 与 journal mode 匹配,再检查 config/credential/keyring 的 owner、mode、regular-file 与 no-symlink 条件。
- Tool 返回认证错误:检查 credential 是否 active、是否仍绑定可解析 Pepper key,以及 presentation 是否被替换。
- Tool 返回 Policy 拒绝:按 [本机 Project Policy](./ql3-local-project-policy.md) 检查 subject 的当前 RoleBinding;不要通过复制 Owner credential 绕过授权。
- Tool 返回 audit/database unavailableMCP 会在 Run read 前失败关闭。修复 SQLite 可写性/容量/锁等待后重试,不要删除 audit 或自动 migration。
- 需要 Workflow start、Approval decision、未脱敏 input、Shell、Secret、事件 payload 或写操作:当前 MCP 明确不支持;不得通过自定义 wrapper 把这些操作伪装成任一只读 Tool。