deskpet-guard
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
deskpet-guard 🐾
Agent 行为守护桌宠 —— 跨 agent 监控可疑外传行为(加密打包直传对象存储 / 敏感密钥被触达 / DNS 外泄线索), 发现即告警,在明确确认后才终止目标 agent 进程;事件写入只追加的
guard-events.jsonl, 并通过 DSH host 工具 与 MCP(stdio) 供其它 agent 查询。A desktop-pet-shaped guardian for AI agent exfiltration: read-only probing, rule-based judgement, append-only event log, two-step human-confirmed process termination (one target per confirmation), exposed to other agents via DSH host tools and an MCP stdio server.
形态 | DSH 插件(host 工具 + 面板/桌宠)· 独立 CLI · MCP server |
平台 | Windows(探针基于 |
依赖 | 运行时零依赖(只用 Node 内置),不用装构建工具链就能跑 |
许可 | BSD-3-Clause |
测试 | 全离线套件,不联网、不杀进程、不需要 DSH |

目录
Related MCP server: agents-control
它是什么 / 它不是什么
是:一个只读侦察 + 分级告警 + 一步确认后处置的小守护。它回答的问题是 "本机现在有没有 agent 正在做可疑外传动作",并把答案做成可被其它 agent 查询的公共事件源。
不是:防火墙。用户态无法阻断另一个进程的 TLS 出网 —— 能阻断的三条路 (杀进程 / 防火墙与 WFP / 内核级文件拦截)分别是"会打断用户会话""要管理员且改系统""不现实"。 详见 SECURITY.md。
一句话:它是案发现场的公告板,外加一支需要人点头的手。
缘起:为什么做这个
对某桌面 AI 客户端(ZCode v3.11.2)做过一次完整只读取证,结论是它确实存在"工作区打包加密后直传阿里云 OSS"的通道:
证据层 | 内容 | 位置 |
打包产物 | 3 个 |
|
上传意图 | 明文 | 同目录 |
上传实现 |
| 客户端 |
凭证来源 | 服务端接口 | 同上 |
加密方式 |
|
|
未证实的部分(必须保留在结论里,别当既成事实):本机 3 个包全部滞留在 pending\,
failureCount 12/222/20,DNS 缓存中 0 条 OSS 桶域名,采样时该客户端出网连接 0。
即"能力确证 + 已打包 + 上传未成功(本机证据)",不是"已确认泄露"。
关键设计推论:与其做"某客户端专杀",不如做通用 agent 行为守护 —— ① 这类行为不是某一家独有;② 用户要求"其它 agent 也能搜到并使用";③ profile 化画像表可覆盖任意 agent。
免责:本项目与上述厂商无任何关联,不含任何厂商代码,全部证据来自本机只读观察,用于防御目的。
快速开始
方式一:装进 DSH(插件形态,推荐)
标准安装(推荐,等同插件市场的"一键装"):本包带 cordis.patch.yml(dsh.bundle.patch),
所以既能从仓库装,也能在支持的市场里一键装:
# 仓库直装(pnpm 会把本包装进 web profile,并按 cordis.patch.yml 插入 loader entry)
dsh plugin --profile web add github:cny1230/deskpet-guard
# 按包名装(npm 发布后;包名就是 deskpet-guard,不带 scope)
dsh plugin --profile web add deskpet-guard
# MCP 客户端:npx deskpet-guard注入器安装(开发/热重载用,免重启):
git clone https://github.com/cny1230/deskpet-guard.git D:/deskpet-guard
# 在 DSH 会话里:
# dev_inject_plugin {"dir":"D:/deskpet-guard"} # 注入
# dev_uninject_plugin {"match":"deskpet-guard"} # 卸载⚠️ 两条路径选一条:同时用会让插件被加载两次(工具重名、面板重复)。 从注入器切到标准安装前,先
dev_uninject_plugin。
装好后你会得到:
5 个 host 工具:
guard_status/guard_events/guard_scan/guard_prepare_kill/guard_confirm_kill右下角常驻桌宠(
shell.overlay)+ 会话侧栏详情面板(conversation.view)本地 HTTP API:
GET /deskpet-guard/api/status|events、POST /deskpet-guard/api/scan|prepare-kill|confirm-killMCP server:
npx deskpet-guard(npm 发布后)或node <repo>/bin/deskpet-guard-mcp.js
配置(apply(ctx, config) 的 config):
{
"dataDir": "D:/guard-data", // 默认 $DSH_HOME/super-injector/deskpet-guard
"intervalMs": 15000, // 采样周期,最小 5000
"killMode": "audit", // "execute"(默认) | "audit" —— audit = 只要预警,拒绝任何终止
"profiles": [ /* 追加/覆盖 agent 画像,见下 */ ]
}方式二:CLI(不装 DSH 也能用)
node lib/index.js # 人读的一次采样
node lib/index.js --json # 结构化输出(含候选处置目标)
node lib/index.js --status # 最近一次落盘状态
node lib/index.js --events 20 # 最近 20 条事件
node lib/index.js --endpoint # host API 端点(面板/MCP 用)方式三:MCP(给别的 agent 用)
node bin/deskpet-guard-mcp.js # stdio MCP server
node lib/mcp.js --list # 看看工具清单与数据目录客户端配置片段与降级语义见 docs/MCP.md。
规则集
规则 | 触发条件 | 级别 | 建议 |
| 探针不可用 | medium/high | 告警(防止"假安全") |
| agent 进程连向 OSS/S3/COS。远端拿到的是 IP( | critical | 建议终止(两步确认,执行前有 PID 复用验证) |
| 10 分钟内出现打包产物 | high | 告警 |
| 5 分钟内成簇刷包 ≥3 | high | 告警 |
| 密钥/凭据文件最近被写(mtime 只能反映"写",测不到"读",见已知限制) | medium | 告警 |
| DNS 缓存残留对象存储域名 | info | 线索(非外传证据) |
| agent 存活 + 当前外发连接数 | info | 状态显示 |
| indexFiles 指向的状态文件里出现上传通道标记( | high | 告警("已表达上传意图",比"只打包了"更进一层) |
moodOf() 把 findings 归一为桌宠表情:watching(安静)/ alert(中高)/ panic(critical)。
防误报口径:egressHostPatterns 只放"对象存储/文件托管"类域名。
反例:*.log.aliyuncs.com 是阿里云日志服务,实测出现在本机 DNS 缓存里,
但不能据此判定"工作区被上传" —— test/rules.test.mjs 有专门用例锁死这条。
事件流防刷屏口径(0.3.0 起):同一现象(指纹)落库后默认冷却 1 小时(DEDUP_COOLDOWN_MS),
冷却期内不重复刷事件但计数照加;冷却期后再次出现会记一条 occurrence 递增的复发事件 ——
"同一目标反复外传"必须留痕,而不是像旧版那样永久压制。事件文件超过 5MB 改名归档为
guard-events.jsonl.1(改名而非删除,历史段仍完整可读),读取只取尾部 512KB。
多实例口径(0.3.0 起):同一数据目录下多个实例(DSH host + 多个 MCP 客户端)用锁文件选主, 只有 leader 周期采样,其余降级为只读跟随者(工具/API 仍可用,读 leader 落盘的数据); 心跳停更超过 3 个采样周期视为前任已死,自动接管。
面板与桌宠
面板挂在两个 DSH client slot 上(都是宿主白名单内的合法 slot):
slot | 形态 | 内容 |
| 右下角常驻桌宠 | 表情( |
| 会话侧栏详情面板 | 统计芯片、探针降级警示(R0)、候选处置目标(两步确认,一次一个)、最近 20 条事件流 |

数据面是本地 HTTP API(
lib/api.js),3 秒轮询,两个 slot 共用一条轮询; 处置流程的状态挂在闭包上 —— 轮询重画不会冲掉进行中的两步确认(有回归用例锁)所有系统字符串(进程名/路径/域名)都用
textContent写入 —— 不用innerHTML, 否则一个精心命名的进程就能在面板里注入标记(有测试盯着这条)面板是手写 bundle(
lib/client.js,DSHModuleLoader约定),不需要打包器 —— 见 架构上面两张图来自
tools/panel-preview.html(离线预览 harness:加载的是真实交付物lib/client.js,但宿主 slots 服务与fetch是 stub、数据为预览样例)。 用任意浏览器打开即可肉眼验收面板,不必装 DSH:start "tools/panel-preview.html?mode=panic&step=2" # step=2 会把两步确认展开 start "tools/panel-preview.html?mode=alert"
给其它 agent 用(MCP)
guard_status / guard_events / guard_scan(只读)+ guard_prepare_kill / guard_confirm_kill(变更)。
MCP 进程与 host 是两个进程,所以:
优先走 host 的本地 HTTP API(token 在 host 里签发/核销,单一事实源)
host 不可达时 只读工具降级本地(读落盘快照 / 本进程采样)
host 不可达时 终止类工具明确拒绝 —— 绝不本地签一个 host 不认的 token
细节与给 agent 的系统提示模板:docs/MCP.md。
扩展到一个新 agent
只改 lib/profiles.js(TS 镜像 src/guard/profiles.ts 同步),不用碰规则引擎:
{
id: 'my-agent',
label: 'MyAgent',
processPattern: 'myagent(\\.exe)?$', // 进程名/路径正则
dataRoots: ['{home}\\AppData\\MyAgent'], // 该 agent 的数据根
bundlePatterns: ['\\.bundle$'], // 打包产物文件名正则
indexFiles: [], // 工作区映射文件
secretFiles: ['{home}\\AppData\\MyAgent'], // 密钥/凭据文件或目录
egressHostPatterns: ['upload\\.myagent\\.example\\.com'], // 外发目标
uploadPathPatterns: [],
}运行时追加也可以(不改代码):apply(ctx, { profiles: [ {...} ] })。
test/rules.test.mjs 里有一条用例专门证明"加一条画像即可生效、无需改规则代码"。
架构与实现
lib/profiles.js agent 画像表(跨 agent 扩展点:新增 agent 只加一条定义)
lib/rules.js 规则引擎(纯函数,可离线单测)
lib/probe.js 只读探针(Windows: PowerShell Get-* / Test-Path)
lib/events.js 事件流(唯一写盘点:只追加、只写自己的数据目录)
lib/api.js 本地 HTTP API(纯函数分发,可离线单测;三重闸门)
lib/toolkit.js 工具定义适配层(defineTool 等价形状,零依赖)
lib/index.js 核心库 + CLI + DSH 插件入口(apply)
lib/client.js 面板/桌宠 bundle(手写,DSH ModuleLoader 约定,无需构建)
lib/mcp.js MCP stdio server(JSON-RPC 2.0,桥接 HTTP API)
lib/agentid.js agent 归属层(进程名/路径/cmdline/画像 → 哪个 agent)
lib/pet.js 桌宠窗口(PowerShell + WinForms,跨 agent 各一只)
lib/sampler.js 独立采样守护(0.4.0):锁选主 + 自托管 HTTP API + endpoint.json,
DSH 不在时它就是唯一采样者(解决"DSH 关了快照过期")
assets/dashboard.html 桌宠看板页面(0.4.0):接真实 API 的正式 UI,守护托管、桌宠窗口同载
assets/ 桌宠形象图(mascot-*.png,随包发布;换图 = 同名覆盖)
bin/…-mcp.js MCP 可执行入口
bin/…-sampler.js 独立采样守护入口(--stop / --status)
src/guard/*.ts TS 权威源码(类型),与 lib/*.js 由 consistency 测试锁死一致
tools/…preview.html 离线预览 harness(浏览器里肉眼验收面板,无需 DSH)
test/*.mjs 15 个离线套件;test/dom-shim.mjs 是跑面板用的极简 DOM为什么有"手写运行时 + 无构建面板"
开发环境里没有 DSH 源码检出(只有 pnpm 打包版),tsc 与 tsdown 都装不上。
于是核心逻辑做成零依赖纯 JS(lib/*.js),并把面板也写成手写 bundle:
tsdown.config.ts 与占位用的 src/client/index.ts 已删除 —— 它们存在的唯一效果就是
"跑一次 npm run build:client 把真正的面板覆盖回一行文字"(和上面那个坑同一类)。
src/guard/*.ts 保留为带类型的权威源码,两侧用 test/consistency.test.mjs 锁死语义一致。
若日后接入构建工具链:把 lib/client.js 迁回 src/client/index.ts 并重建 tsdown 配置,
同时把 test/client-bundle.test.mjs 的产物检查指向新输出。
⚠️ 一个真实踩过的坑(保留在仓库里当路标)
dev_scaffold_plugin 生成的模板落在 src/index.ts,而 tsconfig 是
rootDir: src / outDir: lib —— 一旦跑 tsc,它会把 lib/index.js(真正的守护实现)
覆盖成一个只会读 self-heal.log 的 LLM 自省循环,整套探针/规则/终止链路当场消失。
现在有三道防线:
模板挪到
src/daemon/index.ts(并改名,不再是宿主入口)tsconfig的产物目录改为build/scripts/build.sh里有硬守卫:outDir=lib或src/index.ts存在即拒绝构建
test/ 里的 client-bundle.test.mjs 也会检查 package.json 的入口/类型/bin 指针不悬空
(第一版就犯过"exports["./client"] 指向一个不存在的 lib/client.js")。
桌宠:怎么开、怎么关
桌宠是独立桌面窗口(Windows / PowerShell + WinForms,零依赖),全机只有一只 (0.4.1 起:不管开着几个客户端,后到的拉起请求都会让位;在跑的还是旧版文本宠时, 新的拉起会把它升级成带看板页的 pet2)。 它不在客户端 UI 里渲染——因为 ZCode / Claude Code 这类 agent 的插件 API 只提供 skills / commands / agents / hooks / MCP,没有"往界面插悬浮组件"的能力。
形象跟谁:看板页的"自动"模式跟随最早启动且还在跑的 agent(按进程创建时间判断), 它退出后自动落到下一个还在跑的 agent;也可以在形象下拉框里钉死某个 agent。
自动拉起:
场景 | 机制 |
DSH | 宿主插件在第一次 tick 时拉起 |
ZCode | 插件 |
任何 MCP 客户端 | 它的 MCP server 启动时顺带拉起(幂等:已有一只就跳过) |
0.4.0 起还有一层保障:桌宠/MCP 启动时都会幂等拉起独立采样守护
(node bin/deskpet-guard-sampler.js,锁选主与 DSH 宿主协调,同一时刻只有一家采样)。
DSH 关掉后守护自动接管采样并托管本地看板 —— 各 agent 的桌宠不再出现"快照过期"。
守护与 DSH 宿主并存时,先到者采样、后来者跟随;deskpet-guard-sampler --stop 让位(10 秒内接管)。
手动开/关(随时可用,不必等客户端):
node bin/deskpet-guard-pet.js # 开:桌宠(全机一只;已开着就跳过)
node bin/deskpet-guard-pet.js --client zcode # 同上(--client 只用作日志/来源记录)
node bin/deskpet-guard-pet.js --status # 只看文字状态,不开窗
node bin/deskpet-guard-pet.js --list # 桌宠在不在、来源(全局锁/进程发现)
node bin/deskpet-guard-pet.js --stop # 关掉桌宠(也清历史遗留的 per-client 锁)也可以右键桌宠 → "退出桌宠"直接关掉。Windows 上可以双击仓库根目录的
start-pet.cmd(可带参数,如 start-pet.cmd --client zcode)。
手动关掉之后:不会自己弹回来(关闭是你的明确意图,宿主不会跟你抢)。
想再开就上面任意一条命令 / 双击 start-pet.cmd;ZCode 侧重启 ZCode 也会重新拉起。
⚠️
start-pet.cmd必须保持纯 ASCII:批处理按控制台代码页读取,GBK 双字节字符的 尾字节可能撞上&/|,cmd 会把后半行当命令执行(踩过,报错很迷惑)。测试里有守卫。
测试
npm test # 15 个套件 / 213 例(= node test/all.mjs;离线:不联网、不杀进程、不需要 DSH、不需要 Windows)
npm run check # 交付 JS 的语法自检(本仓库没有编译步骤兜底)
node test/panel-ui.test.mjs # 只跑面板行为(DOM shim 里挂真面板)
node test/mcp-stdio.test.mjs # 只跑 MCP 传输层(单请求单响应 / close 不吞响应)套件 | 关注点 |
| 规则判定 / 防误报(SLS 日志域名反例)/ 画像扩展性 |
| 处置链路安全:无确认不可能误杀、token 一次性、一次确认只杀一个、执行前 PID 复用验证(进程名+创建时间对不上即拒绝) |
|
|
| HTTP API 与鉴权边界:预检拒绝、跨源拒绝、secret 路径、body 边界 |
| 假 ctx 跑 |
| JSON-RPC 往返 + 工具名/HTTP 路径跨文件一致 + host 不可达的降级语义 |
| 传输层:单请求单响应(防双 server 抢 stdin)、close 不吞最后一个响应、stdout 纯净 |
| 面板产物约定、slot 白名单与注入器自检正则、API 路径与 host 一致、不用 |
| 在 DOM shim 里跑真面板:渲染、两步确认(第一步不执行)、轮询不冲掉确认区、取消、API 不可达、dispose 停轮询 |
| 事件流:冷却去重与复发计数、大小轮转归档、真 tail 读取(大文件不整载、行不残缺)、Set 兼容 |
| 探针纯函数:PS 5.1 JSON 归一化(单元素/BOM/垃圾前缀/截断判降级)、secretFiles 通配拆分 |
已知限制(读这里再决定要不要用)
沙箱内探针会被拒:受限沙箱禁止程序打开命名管道,抓 PowerShell 输出会失败, 三个系统探针(进程 / TCP / DNS)全挂 →
R0上报降级。文件类探针不受影响 (就是它在沙箱里扫出了那 3 个.tar.gz.enc)。要看进程/连接侧,请在你自己的终端里跑。不是防火墙(见上)。
只在 Windows 上有完整探针;其它平台会明确上报
unsupported。画像表:zcode / dsh / cursor / claude-desktop 四条。zcode 与 dsh 桌面端有本机实证 (dsh 桌面端 = Electron 应用
DeepSeek Harness.exe,user-data 目录AppData/Roaming/@deepseek-ai/dsh-desktop;其上传链路未逐一实证,外发画像沿用同厂 OSS/S3/COS 口径)。cursor / claude 仅有基础画像 —— 不懂的 agent 就是没有画像,这是待办。文件名匹配是启发式:打包产物靠文件名/扩展名识别,改名可绕过。
没有基线学习:新装的 agent 一律按陌生进程处理,误报会随安装量上升。
killMode:'execute'会真的杀进程(需两步人工确认 + 一次一个)。生产环境建议先用audit跑一段时间。R1 的域名反查依赖本机 DNS 缓存:如果目标 agent 走加密 DNS(DoH)或自建解析,缓存里可能 没有对应记录 → 反查不到 → R1 漏报(此时 R5 也不会有线索)。对已知固定出口,画像里直接写 IP/CIDR 可以兜底。另外反查基于"IP → 曾解析过的域名",CDN 共享 IP 理论上可能串出误报 —— 所以 R1 的 evidence 永远带
resolvedHost(实际命中的域名),人工复核一眼可辨。R4 实际只测"写"不测"读":mtime 不反映读取行为(Windows 默认还禁用 last-access 更新)。 要测"密钥被读"需要 ETW/Sysmon 一类内核遥测,目前不做(见 Roadmap)。
安全
探针只读;不写被监控 agent 的任何目录;不碰防火墙 / hosts / 注册表 / 证书存储;host 侧不出网
事件流只追加
变更端点三重闸门(自定义头 + 同源 + JSON,或 0600 secret);预检一律 403,永不发 CORS 头
终止必须两步确认、token 一次性、一次一个目标
完整模型与已知弱点:SECURITY.md。漏洞请走私密渠道(Security advisory),不要开 public issue。
状态 / Roadmap
只读探针 + 规则引擎 + 只增事件流 + CLI
DSH host 工具(5 个)+ 本地 HTTP API + 面板/桌宠
MCP stdio 暴露层
基线/白名单学习(降低误报)
更多 agent 画像与实证
系统托盘通知 / 声音
macOS / Linux 探针
发布状态(能不能在插件市场里搜到)
渠道 | 状态 | 说明 |
GitHub 仓库 | ✅ 已发布 | https://github.com/cny1230/deskpet-guard(public,CI 绿) |
| ✅ 可用 | 本包带 |
GitHub topic | ✅ 已打 | 已被 GitHub 搜索索引; |
npm 包 | ✅ 已发布 |
|
dsh.so 收录 | ✅ 已提交两次 | 用它自己的提交页跑完 checker 后点 |
下一步(可选,非阻塞):
未来版本发布建议改用 Trusted publishing (OIDC): 由 GitHub Actions 用 OIDC 发布、不存凭据 —— 因为 npm 已宣布 2027-01 起 bypass-2FA token 不能再直连发布; 本仓库已有 CI,加一个
release.yml+ 在 npm 上把 trusted publisher 指到cny1230/deskpet-guard即可;dsh.so 的 artifact 页要等它自己的重建周期(条目已在其后台)。
用法汇总:GitHub 直装(dsh plugin --profile web add github:cny1230/deskpet-guard)、
npm 装(dsh plugin --profile web add deskpet-guard)、MCP(npx deskpet-guard)。
逐步操作与自检清单见 docs/PUBLISHING.md。
变更记录
0.3.0(2026-09-28)—— 检测主链路修复 + 处置安全加固
R1 修复(关键):远端 IP 先经 DNS 缓存反查成域名再匹配
egressHostPatterns—— 修复前 R1 拿 IP 比域名正则,真实环境永不命中(测试夹具把域名塞进了 IP 字段, 把错误假设锁进了测试)。egressHostPatterns同时支持 IPv4 字面量 / CIDR。新增 R7 上传意图标记:indexFiles 指向的状态文件里出现
pendingUpload/uploadOssForm等明文标记 → high(画像的uploadPathPatterns字段首次接入规则引擎)。处置安全:confirm 执行前做 PID 复用验证(进程名 + 创建时间与确认时不一致即拒绝, 防 10 分钟窗口内 PID 被回收复用误杀无辜进程);kill 计划列出目标子进程(仅展示)。
事件流:去重从"永久压制"改为"冷却期 + 复发计数";超 5MB 轮转归档;读取改真 tail。
多实例:同一数据目录单采样者锁,其余实例降级为只读跟随者。
修复:
underDataRoot前缀越界误匹配(.zcode-v2不再认成.zcode); cursor 画像secretFiles通配静默失效;探针输出损坏时判为降级(R0)而非空数据; R4 的目录匹配统一转义口径(与 TS 镜像一致)。
0.2.8 及以前
见 git log。
许可
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Guarded MCP server for agent-readable business truth, provenance, readiness, and discovery.
Guard wraps stdio MCP servers: risky calls wait for a person; no answer, no run. Remote: cooperative
Public MCP for agent verification, work discovery and governed interoperability.
Hosted MCP memory and agent control plane for durable conversations, jobs, and operations.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables agent clients to safely connect to tools and execution resources through MCP with authorization, approvals, audit, chat-context isolation, SSH/Docker access, and long-running command session tracking.MIT
- AlicenseNot gradedqualityCmaintenanceEnables one coding agent to inspect, configure, debug, and repair another agent over stdio MCP, with redacted reads and confirm-gated writes and restarts.MIT
- AlicenseNot gradedqualityBmaintenanceExposes ReadyAgents' local workflow engine and built-in tools over MCP stdio, enabling MCP clients to define, run, inspect, and approve YAML/JSON agent workflows.39 PyPI1Apache 2.0
- AlicenseNot gradedqualityCmaintenanceProvides an MCP stdio interface for AI agents to propose tool calls that are validated against task policy, held for human approval when required, executed in a sandboxed Linux environment, and recorded in an audit log.MIT