dsh-mcp-security
v0.1.2
Published
Fail-closed MCP tool baseline and runtime approval security for DeepSeek Harness.
Downloads
446
Readme
MCP 安全
English | 中文
为官方 DSH MCP Client 注册的工具提供 MCP 安全设置页和 fail-closed Host 策略。
0.1.2 有什么新变化
全部改动都在插件自身,存量部署不做配置调整即可继续工作。完整细节见变更记录。要点:
调用时重验(可选探针)。 为高危 Server 声明
probe目标后,每次受覆盖调用都会经一次性连接强制重取其实时tools/list并在分派前与基线比对——服务端静默换装再也无法躲在滞后的注册表后面。基线原子接受。 接受按钮只发送你审阅过的指纹;由宿主用自己的快照执行交换,注册表已变化时拒绝接受。
理由会告诉你变了什么。 被拒绝的调用现在显示:
MCP 安全:检测到工具定义漂移(描述变化:mcp__security_demo__echo)。调用已阻止,请先在"设置 → MCP 安全"中检查差异并接受新基线。
(来自真实端到端运行截图验证),而不是一句静态的"检测到漂移"。
策略
- 仅覆盖公共名称采用
mcp__<serverName>__<rawName>格式的工具。 - 首次观察到的定义集合处于未信任状态。插件绝不会自动创建或更新已接受基线。
- 已接受基线是所有可见 MCP Server 和工具的一份完整快照,包括公共名称、原始名称、描述、输入 Schema 和输出 Schema。
- 基线缺失、格式错误、指纹无效或发生漂移时,所有受覆盖调用都会在 MCP 分派前被拒绝。
- Server 或工具的增删,以及工具描述、输入 Schema 或输出 Schema 的变化,都会使完整基线失效。
- 快照内同一 Server 下出现重复工具名时,快照整体不可用(分页竞态/服务端异常绊网),调用一律拒绝。
- 基线匹配时,每次调用仍需获得一次显式批准。没有可用的批准支持、取消或拒绝都会阻止调用。
- 非 MCP 工具继续经过其余
tools/pre-execute策略。
接受基线只记录用户已经检查并信任当时可见的定义;它不能证明初始 Server 或其定义安全,不能认证 Server 实现,也不会批准任何工具调用。请检查完整的已接受列表,不要只依赖后续的“没有差异”结果:如果用户最初接受了有害定义,该定义在可见内容改变前仍会保持基线匹配。
拒绝与批准理由会携带字段级差异摘要(哪个工具、哪些字段发生变化),不再只有一句静态提示;完整差异仍以设置页为准。
基线接受(原子交换)
设置页的“接受当前完整基线”只向 Host 发送一个意图(用户审阅的指纹)。Host 在写入提交路径上用自己的注册表快照执行交换:快照指纹必须仍与用户审阅的指纹一致,否则接受被拒绝并写入 accept-refused 审计记录。这消除了“用户审阅 A、落盘 B”的竞态窗口;接受结果以 baseline-accepted / accept-refused 审计记录留痕。
调用时重验(可选探针,per-server opt-in)
注册表比对只能看到 DSH MCP Client 已刷新的定义;服务端静默换装且客户端未刷新时,本地注册表是滞后的。对高危 Server,可在插件配置中为其声明一个探针目标。此后该 Server 的每次受覆盖调用前,插件都会通过一条一次性的探针连接(initialize → tools/list → 断开)强制重取该 Server 的实时工具列表,并与已接受基线做字段级比对:
- 比对一致:放行进入常规单次批准,且不受滞后注册表的影响;
- 比对出漂移、重复工具名、基线缺失或指纹无效:拒绝调用;
- 探针连接失败或超时:默认 fail-closed 拒绝;配置
probeFailOpen: true可降级回注册表比对判定。
探针配置与 DSH mcp-client 的配置字段一致(便于直接镜像),支持 stdio 与 streamable-http:
- insert:
- id: mcp-security
name: 'dsh-mcp-security'
config:
probeFailOpen: false
probe:
- serverName: security_demo
timeoutMs: 4000 # 单次探针超时(含进程启动),200–60000
transport: stdio
command: node
args: [server.js]
cwd: /path/to/server
env: {} # 追加到净化后的最小环境
- serverName: remote_demo
transport: streamable-http
url: https://example.com/mcp
headers: {}代价与边界:配置了探针的 Server,每次调用额外支付一次连接 + tools/list 的往返延迟(stdio 含子进程启动);探针不经过 DSH MCP Client,属于插件自建的第二条独立观测通道,不改变 tools/call 的分派路径。
设置界面
设置页显示:
- 安全状态以及当前 Server 和工具数量;
- 已接受定义与当前定义之间的所有字段级差异,包括旧值和新值;
- 完整的已接受基线,包括采集时间、指纹、Server、工具、描述和 Schema;
- 完整的当前工具定义;
- 最近的预执行、探针与结果审计记录。
已接受列表和当前列表中的每个工具都可以单独展开。设置页会用 WebCrypto 在本地重算已接受基线的指纹并自校验,基线损坏时显示“指纹校验失败”而不是误导性的“漂移”。只有当用户明确接受一个不包含任何可见 MCP 工具的工具代际时,空基线快照才是有效基线。
观察与强制执行时机
Bundle 启动时,Host 发布当前 ToolRuntime 定义;此后注册表 tools/change 事件会使快照缓存失效(五秒轮询保留为兜底)。在每个受覆盖的 tools/pre-execute 执行期间,Host 使用缓存失效后的最新快照做注册表比对;配置了探针的 Server 则以探针重取的实时定义为准。这两条路径都发生在 MCP Client 分派 tools/call 之前。
不配置探针时,插件观察 DSH MCP Client 当前注册的定义,不直接观察 MCP Server 远端状态。对于 stdio、SSE 和其他受支持的传输方式,只有 MCP Client 刷新已注册工具后,远端定义变化才会变得可检测。可能需要 Server 发送工具列表通知、重新连接、重启 MCP Client 或重启 DSH Host。在同步完成前,本地注册表仍保存旧定义——这正是对关键 Server 配置探针的原因。
覆盖范围
该策略覆盖当前 DSH ToolRuntime 中使用官方公共命名格式注册的官方 MCP 工具。直接调用 MCP SDK、其他进程中的 Client、使用独立 MCP Client 的 subagent,以及其他应用程序发起的调用都不会经过此运行时,因此不受该策略覆盖。探针只覆盖在插件配置中显式声明的 Server。
快照用于检测 Server 公布的能力变化。Server 可以保持名称、描述和 Schema 不变,同时改变实现行为、目标地址、数据处理方式或副作用;基线无法发现这类变化(C 类行为替换在元数据层原理上不可检)。结果侧校验会在基线携带输出 Schema 时,用已批准 Schema 校验实际返回并阻止不符结果——但当前 DSH 的 tools.schemas() 不向下暴露输出 Schema(快照中该字段恒为 null),该校验在 Host 暴露输出 Schema 后自动激活;tools/result 审计已记录结果形状指纹作为低噪声证据。快照还使用配置的 serverName 标识 Server,而不是通过密码学方式验证 Server 或二进制文件身份;同名 Server 换 endpoint / 换凭证当前不触发基线失效。端点认证、TLS 验证、网络策略、Server 来源验证和行为监控仍需由其他控制措施负责。
审计语义
预执行策略写入 approval-required 和 denied 记录;探针路径写入 probe-ok / probe-error / denied;基线接受写入 baseline-accepted / accept-refused;结果侧校验写入 result-schema-mismatch。executed 和 error-or-denied 汇总最终 ToolRuntime 结果(附结果形状指纹)。结果记录仅用作审计证据,无法撤销远端副作用。审计写入按 300ms 或 10 条合并提交;Settings 命名空间最多保留 200 条审计记录,页面显示最新的 100 条。
模型体验
Bundle 不添加工具或提示词。MCP 工具仍然对模型可见。基线缺失、无效、发生漂移或探针判漂移时,调用会在分派前失败,拒绝理由包含具体差异摘要;基线匹配时,调用通过现有批准界面获得单次授权。
