DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Rea Mcp Toggle — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
R

dsh-rea-mcp-toggle

Rea Mcp Toggle

Switch the REA MCP server (rea-mcp) on and off from the DeepSeek Harness Web UI, with a matching agent tool; the choice persists across restarts.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:VioletEverGarden-zc/dsh-rea-mcp-toggle#a4aa003f527b5d1328124299f51cd61bf0db24af
READMECompatibilityVersions

Compatibility and provenance

Rea Mcp Toggle is published as dsh-rea-mcp-toggle and currently resolves to version 1.0.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
10/15/2026

Versions

1.0.0stable
10/15/2026

Related plugins

Loading related plugins…

Latest
1.0.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
10/15/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in integrations-communication.

Im@xmanrui/dsh-im把微信、飞书、企微、钉钉、QQ、Telegram、WhatsApp、Slack、Discord、Matrix接入DSH。 Connect Telegram, WhatsApp, Slack, Discord, Matrix, WeChat, Feishu, WeCom, DingTalk, and QQ to DSH.Free Searchdsh-free-searchFree web search for DeepSeek Harness: 24 engines (Bing/DuckDuckGo/AnySearch/SearXNG/Exa/Tavily/Keenable/Firecrawl/Parallel keyless; Zhihu global/site via MCP and Perplexity/SerpBase/DeepSeek/You.com/Baidu/Kimi/Aliyun/Doubao with key; OpenAI/Gemini/Claude Dafeiyudsh-dafeiyuA desktop-native BigFish companion driven by DeepSeek Harness session events.Wechat Plugindsh-wechat-pluginWeChat channel for DeepSeek Harness: lock the PC, walk away, and drive the agent from your phone. No OpenClaw and no public IP required.

README

dsh-rea-mcp-toggle

一个 DeepSeek Harness(DSH)bundle 插件:在 Harness Web UI 里一键开关 REA MCP 服务器,并把同一个开关交给模型(工具 rea_mcp_toggle)。选择按 profile 保存,重启后依然生效。

适用:DSH 0.2.1-alpha.2(web profile)。零运行时依赖(只用 Node 内置模块 + dsh 宿主服务)。


1. 项目解决什么问题

REA(Reverse Engineer Anything)通过 MCP 以 stdio 方式接入 DSH。它的工具集非常大:开启时是 170 个 mcp__rea__* 工具,这些工具的 schema 会随每一次请求一起发给模型。

实测同一实例、同一时刻,Tool.listTools 的返回体大小:

REA 状态工具数tools payload
开启251722,353 字节
关闭8194,807 字节

差价 627 KB 全部是那 170 个工具的定义。它们每次都进请求,于是产生两种浪费:

  1. token 费用:不管这一轮到底用不用逆向工具,都在为这 627 KB 付费(长会话里反复累积);
  2. 进程与内存:REA 的 MCP 子进程常驻(单进程约 240 MB),只有关掉才会退出。

而 DSH 自带的「插件开关」(Plugin Manager 里把 rea-mcp 行禁用)对这一行无效——原因见第 6 节,这不是配置问题,是 patch 层的机制决定的。所以本项目提供了能真正生效、且能持久化的开关。

典型场景:平时关着,等真要分析二进制 / APK 时再打开;或者反过来,只在需要省 token 时临时关闭。


2. 主要功能

2.1 UI 开关(主入口)

会话标题栏(Session header)里的一个小按钮,与「费用明细」等控件并列:

  • 显示 REA 开 / REA 关,绿点表示当前状态;
  • 点一下切换:即时生效,不需要重启 Harness;
  • 切换失败时按钮直接变成 REA 失败(红框),鼠标悬停显示具体原因 —— 不会静默无效;
  • 鼠标悬停还会显示当前工具数与配置行 id。

2.2 模型工具 rea_mcp_toggle

action作用
status读当前开关状态、工具数、是否已持久化、状态文件路径
set切换(需 enabled: true/false);幂等,重复同向不发写、不产生副作用
probe诊断:Loader 行状态、REA 工具数、缝是否在位、服务可用性、Remote endpoint 解析情况
selftest用 Web UI 调用的同一条 Remote 网关路径自检本插件(用来区分「UI 坏了」还是「Host 坏了」)

UI 按钮与这个工具共用同一套实现(同一 service 的同一个方法),不存在两份逻辑。

2.3 状态持久化

选择保存在插件自己的状态文件里:

%DSH_PROFILE_DIR%\.rea-mcp-toggle.state.json     例如 {"enabled": false, "savedAt": "..."}

写入是原子的(临时文件 + rename)。重启后由家目录层的一行 !!js 缝读取该文件,开机即按选择生效(关闭状态下开机根本不会拉起 REA)。

2.4 工具可见性真正变化

关闭时 170 个 mcp__rea__* 工具从模型可调用工具列表中消失(不只是「不执行」);开启时全部回来。

2.5 进程生命周期

  • 开启:拉起 REA 的 stdio 子进程(每次切换恰好 1 个);
  • 关闭:dispose 该行,回收子进程、注销工具;
  • 关闭后不会自己复活(曾有一个「关闭后子进程又起来」的缺陷,已修并可复现验证)。

3. 安装方法

3.1 前置条件

  • 已安装 DSH,且 REA 已作为 MCP server 注册在家目录层 %DSH_HOME%\cordis.patch.yml,形如:

    - insert:
        - id: rea-mcp
          name: '@deepseek-ai/dsh-mcp-client'
          config:
            serverName: rea
            transport: stdio
            command: '<HARNESS_ROOT>\node\bin\node.exe'
            args: ['<NPM_GLOBAL>\node_modules\rea-agents\scripts\rea.mjs', 'mcp']
            env: { REA_MCP_INPUT_SCHEMA_PROFILE: compact }
            toolCallTimeoutMs: 900000
            failOnStartupError: false        # 硬约束:REA 坏了也不能让 harness 起不来
    
  • 该行 id 必须是 rea-mcp(本插件按这个 id 定位;其它 id 会被明确拒绝,不会误伤)。

3.2 安装本 bundle

本插件以路径链接方式安装,因此包目录内需要有指向 DSH 安装的 node_modules 链接(Node 从包的真实目录解析 bare import;本插件运行时只 import node:fs,但编译/探针脚本需要):

cd plugins\dsh-rea-mcp-toggle
node scripts/link-deps.mjs
# 通常不需要参数:脚本会自己找 harness(见下),失败时才需要显式给根目录
# node scripts/link-deps.mjs "<HARNESS_ROOT>"

脚本如何找到 harness(按顺序,每个候选都会被 marker 校验,错的目录不会静默胜出):

顺序来源说明
1命令行参数node scripts/link-deps.mjs "<root>"
2<repo>/.harness-root一行写根目录;模板见 .harness-root.example;已被 git 忽略。标准位置都描述不了的布局用这个
3DSH_HARNESS_ROOT环境变量
4平台标准安装位置Windows:%LOCALAPPDATA%\Programs、%ProgramFiles%、%ProgramFiles(x86)%、%LOCALAPPDATA% 下的 dsh-desktop / DeepSeek Harness / deepseek-harness,并在其 resources/harness 与 harness 处探测;macOS:/Applications、~/Applications;Linux:/opt、/usr/local/lib、/usr/lib
5正在运行的 Harness由进程的 node.exe 路径反推安装根,因此装在非标准目录也能找到

判定「是 harness 根」的条件:同时存在 node_modules/@deepseek-ai/{cordis,dsh,dsh-tools} 与 node_modules/js-yaml。本仓库自身被显式排除(它的 node_modules 是链接,否则会自我链接)。

然后在会话里让模型执行(需要 danger-full-access 或当次审批):

plugin_manager → install_bundle → <本目录绝对路径>

安装后必须重启一次 dsh-desktop。 Host 半边的模块是进程启动时导入的;不重启时插件行会处于 failed to import 或停在旧版本。

3.3 安装家目录层的「开关缝」(必须,一次)

这是唯一需要手改家目录层的地方。在你已有的 rea-mcp 行里加一个行级 disabled(不要放进 config 里面):

      - id: rea-mcp
        name: '@deepseek-ai/dsh-mcp-client'
        config:
          # ...原有内容保持不动...
        # ── 开关缝:由 dsh-rea-mcp-toggle 插件读取 ──
        disabled: !!js >-
          Boolean(ctx.get('profileContext')?.dir) && (() => { try { return process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:path').join(ctx.get('profileContext').dir, '.rea-mcp-toggle.state.json'), 'utf8') && JSON.parse(process.getBuiltinModule('node:fs').readFileSync(process.getBuiltinModule('node:path').join(ctx.get('profileContext').dir, '.rea-mcp-toggle.state.json'), 'utf8')).enabled === false } catch { return false } })()

改前先备份:Copy-Item .dsh\cordis.patch.yml .dsh\cordis.patch.yml.bak-<时间戳>

这段表达式是安全降级的:状态文件不存在 / JSON 损坏 / profileContext 不可用(例如离线 dsh --dump-config)时一律返回 false=保持启用,不会让 harness 起不来。

3.4 安装后自检

node scripts/acceptance.mjs        # 校验缝与状态文件在同一口径上

再在会话里执行 rea_mcp_toggle {action:"selftest"} —— 它走的就是 Web UI 的 Remote 网关路径。


4. 使用方法

4.1 日常:点按钮

标题栏的 REA 开 / REA 关 按钮,点一下即可。不需要重启。

4.2 让模型帮你切

把 REA 关掉,我在省钱          → 模型调用 rea_mcp_toggle {action:"set", enabled:false}
REA 现在开着吗?               → 模型调用 rea_mcp_toggle {action:"status"}
UI 按钮点了没反应,帮我看看     → 模型调用 rea_mcp_toggle {action:"selftest"}

4.3 关闭 / 禁用的几种情况

  • 临时关:点按钮。状态文件写 enabled:false,当前进程立即生效(工具消失、子进程回收)。
  • 永久不再启用:把手改的那段 disabled: !!js 缝从家目录层删掉(保留其余内容),该行即恢复为无条件启用。
  • 彻底卸载:见第 8 节。

5. 输入输出示例

以下均为真实运行结果(本机实测,compact schema profile)。

5.1 查询状态

输入:

{ "action": "status" }

输出(REA 关闭时):

REA MCP (rea-mcp) is OFF: the mcp__rea__* tools are not callable; the choice is saved.
entry=rea-mcp module=@deepseek-ai/dsh-mcp-client
enabled=false persisted=false tools=0 seam=true
stateFile=<PROFILE_DIR>\.rea-mcp-toggle.state.json

输出(REA 开启时):

REA MCP (rea-mcp) is ON: 170 tool(s); the choice is saved.
entry=rea-mcp module=@deepseek-ai/dsh-mcp-client
enabled=true persisted=true tools=170 seam=false
stateFile=<PROFILE_DIR>\.rea-mcp-toggle.state.json

seam=false 是正常的:即时开启会清掉该行进程内的 disabled 键(probe 里显示 rawDisabled=null),开机时缝会重新求值(那时是 seam=true)。

5.2 关闭 REA

输入:

{ "action": "set", "enabled": false }

输出:

REA MCP (rea-mcp) is OFF: the mcp__rea__* tools are not callable; the choice is saved.
entry=rea-mcp module=@deepseek-ai/dsh-mcp-client
enabled=false persisted=false tools=0 seam=false

同时 %DSH_PROFILE_DIR%\.rea-mcp-toggle.state.json 变为:

{ "enabled": false, "savedAt": "2026-10-13T17:59:27.803Z" }

5.3 开启 REA

输入:

{ "action": "set", "enabled": true }

输出(子进程握手完成后):

REA MCP (rea-mcp) is ON: 170 tool(s); the choice is saved.
enabled=true persisted=true tools=170 seam=false

5.4 幂等:重复同向不发写

连续两次 { "action": "set", "enabled": false },第二次不会重写状态文件 (实测文件 LastWriteTime 与内容完全不变),也不会新增 patch 行。

5.5 诊断

输入:

{ "action": "probe" }

输出(节选):

seam=false reaTools=0 stateFile=...\.rea-mcp-toggle.state.json
stateFileExists=true stateFileValue=false services={"loader":true,"tools":true,"typert":true,"pluginManager":true,"typertGateway":true}
row id=rea-mcp-toggle composite=include:rea-mcp-toggle module=dsh-rea-mcp-toggle rawDisabled=false effectiveDisabled=false fiberState=2 parentTree=include
row id=rea-mcp composite=include:rea-mcp module=@deepseek-ai/dsh-mcp-client rawDisabled=true effectiveDisabled=true fiberState=4 parentTree=include

读数要点:effectiveDisabled=true 且 fiberState=4(disposed)=该行确实已停; reaTools=0 = 模型侧看不到 REA 工具。

5.6 UI 自检(判断是 UI 坏还是 Host 坏)

输入:

{ "action": "selftest" }

输出:

gateway reaMcp/getState ok -> {...}
gateway reaMcp/setEnabled ok -> {...}
restoredTo=false

selftest 会先记住你的选择,结束后原样恢复(诊断不改变开关)。

5.7 安装后的效果对照

观察点关闭开启
Tool.listTools 里 mcp__rea__*0 个170 个
listTools payload≈ 94.8 KB≈ 722.4 KB
该实例的 REA 子进程0 个1 个
开销最大的部分—170 个工具 schema 进每次请求

6. 为什么不能用 profile 层的 disabled(关键设计决定)

DSH 的 patch 分层是:bundle 层 → profile 层(%DSH_PROFILE_DIR%\cordis.patch.yml)→ 家目录层(%DSH_HOME%\cordis.patch.yml)→ --patch 覆盖,后者覆盖前者。

rea-mcp 行是家目录层用 insert 声明的,而家目录层最后应用,insert 推入的是新的行对象。后果(用 Harness 自身的 readProfilePatches / composeEntries 复现,见 scripts/probe-layer-order.mjs):

  • profile 层写 { id: rea-mcp, disabled: true } → 组合结果里 rea-mcp 从不带 disabled;
  • 运行时 Entry.disabled 恒为 false;
  • 连官方 plugin_manager 对该行也只能返回 application: "overridden"。

所以本插件的做法是:状态放自己的文件,家目录层只承担一个「缝」(!!js 表达式)。表达式在读取 disabled 时才求值,因此不会被家目录层自己的 insert 盖掉。


7. 项目结构、已知限制与开发笔记

7.1 结构

dsh-rea-mcp-toggle/
├─ package.json          # bundle 清单(dsh.bundle.patch / dsh.client)
├─ cordis.patch.yml      # 只插入本插件自己的行;不碰 rea-mcp 行
├─ index.js              # Host 半边:唯一实现(Remote reaMcp + 工具 rea_mcp_toggle)
├─ state.js              # 状态文件的唯一读写者(原子写)
├─ client.js             # 浏览器半边:标题栏开关按钮
├─ locale/{zh,en}.json   # 插件在插件列表里的显示名与描述
├─ icon.svg              # 图标
├─ .gitignore            # 排除 node_modules 链接、状态文件、机器本地的 .harness-root
├─ .harness-root.example # 「harness 装在哪」的模板(真实文件 .harness-root 由使用者创建)
└─ scripts/              # 安装辅助与验证脚本(不属于运行时,不随包发布)
   └─ lib/harness-paths.mjs   # 定位 harness / profile:多级兜底,不硬编码任何本机路径

运行时零依赖:Host 半边只 import Node 内置模块(node:fs、node:path、node:url)与自身文件;scripts/ 里的脚本才需要 DSH 安装提供的包。

7.2 已知限制

  1. 作用域是「实例」:开关作用于承载它的那个 Harness 进程。若机器上残留了旧的 Harness 守护进程(桌面应用重启时偶尔不退出),那些实例不受影响 —— 用任务管理器确认 node.exe 中带 dsh\lib\bin.js 的条目数量,多于 1 个即需清理。
  2. disabled 行必须放在行级,写成 config 的子字段会导致该行永不生效(--dump-config 可看出层级)。
  3. 上游遗留(不在本项目内):@deepseek-ai/dsh-mcp-client 的 dispose() 先取子进程句柄快照再 await;若拆卸时正好有连接在飞,那次连接会在快照之后写入新句柄,其子进程不会被关闭(每关一次可能残留一个孤儿 REA 进程)。该行本身确实是停的(fiber 已 dispose、工具为 0),残留进程只占内存、不向模型暴露工具,Harness 退出时回收。
  4. selftest 需要一次重启后才可用(Host 模块按进程加载)。

7.3 三个踩过的坑(写给后来者)

  • 工具 parameters 必须是「干净」的 JSON Schema:ctx.tools.register() 收的是 raw JSON Schema,会被原样发给 provider。若把作者侧的 required: true 标记写进属性里(defineTool() 那种写法),provider 会直接报 Invalid schema for function 'rea_mcp_toggle': true is not of type 'array',每一轮都在调用工具之前就失败。正确写法是可选属性不加标记、必填项放进对象级的 required: ["action"] 数组。 仓库里保留了门禁脚本 scripts/check-tool-schema.mjs:它从 index.js 抽出 parameters 字面量,用 Harness 自己的 assertSupportedJsonSchema + 8 个参数用例(接受/拒绝各半)校验,防止再次漂移。

  • 不要继承 TypertRemoteService。它的构造器用 bindTypertRemote(this, this.name) 绑定,而 Cordis 的 Service.name 是 symbol 而非服务键字符串,导致网关校验失败:Receiver must be an instance of class ...。正确做法是普通类 + 显式绑定:

    this.typertRemote = Object.freeze({ service: this, serviceKey: 'reaMcp', namespace: 'reaMcp' })
    
  • Remote 调用返回的是 { ok, value } 信封,客户端必须 if (!result || result.ok !== true) throw ... 后取 result.value;只判断 ok === false 会把信封当成结果,表现为「按钮点了没反应」。

  • 无参端点要用空对象调用:gateway.invoke() 的入参不能省略 args,要传 args: {}。省略时参数校验会抛 Cannot convert undefined or null to object(浏览器侧的 Remote 调用方始终发 {},所以只有 Host 自检脚本会踩到)。

7.4 验证脚本

先跑一次 node scripts/link-deps.mjs '<HARNESS_ROOT>':这些脚本用 Harness 自己的实现来验证(组合算法、YAML 方言、JSON Schema 检查器),依赖包通过本包自己的 node_modules 链接解析,不硬编码任何本机路径。之后在 profile 启动的 shell 里(有 DSH_PROFILE_DIR / DSH_HOME)可以不带参数直接跑:

node --check index.js; node --check client.js; node --check state.js   # 语法
node scripts/check-tool-schema.mjs   # 工具 schema 门禁(Harness 自己的检查器 + 8 个用例)
node scripts/probe-layer-order.mjs   # 分层覆盖机制:profile 层 disabled 为何无效
node scripts/probe-composition.mjs   # 组合结果中该行是否带 disabled
node scripts/probe-seam.mjs          # 缝表达式 × Harness 真实 YAML 方言与求值器
node scripts/probe-roundtrip.mjs     # 真实写/读 × 缝读取,含「损坏文件」降级分支
node scripts/acceptance.mjs          # 缝与状态文件口径一致性

不在 profile shell 里时,用参数显式给路径:

node scripts/acceptance.mjs '<PROFILE_DIR>' '<DSH_HOME>'

8. 卸载 / 回滚

  1. plugin_manager → remove_bundle → dsh-rea-mcp-toggle;
  2. 删除家目录层里的 disabled: !!js >- ... 缝(保留该行其余内容),REA 即恢复为无条件启用;
  3. 可选:删除 %DSH_PROFILE_DIR%\.rea-mcp-toggle.state.json。

9. 许可

MIT © 2026 VioletEverGarden-zc

LICENSE 使用 MIT 标准文本,版权人为 VioletEverGarden-zc;package.json 的 license 字段同样是 MIT,三者口径一致。

10. 作者与仓库

  • 作者:VioletEverGarden-zc — https://github.com/VioletEverGarden-zc
  • 仓库:https://github.com/VioletEverGarden-zc/dsh-rea-mcp-toggle
  • 上游项目:REA(Reverse Engineer Anything)— https://github.com/morluto/rea。本插件只提供「开关」,REA 本体及其 mcp__rea__* 工具集由上游项目提供与维护(MIT)。

仓库 URL 按包名 dsh-rea-mcp-toggle 填写。若你实际建仓时用了别的名字,请同步替换 package.json 里的 repository / homepage / bugs 三处与本节链接。

11. 致谢

感谢 REA(Reverse Engineer Anything)的作者与贡献者。本插件只是替它加了一只开关,逆向能力全部来自上游;没有 REA,这个项目没有存在的理由。