ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

dsh-mcp-panel权限模型:基于MCP协议的细粒度操作控制与审批流设计

dsh-mcp-panel权限模型:基于MCP协议的细粒度操作控制与审批流设计 1. 项目概述一个被低估的权限分层设计“从只读面板到需审批写入”——这句标题乍看像在讲前端UI状态切换实则直指dsh-mcp-panel这个工具最核心、也最容易被忽略的设计哲学它不是简单地把 DeepSeek Harness以下简称 DSH封装成网页界面而是以 MCP 协议为骨架在 Web 端重建了一套细粒度、可审计、可拦截的操作权限生命周期模型。我第一次部署 dsh-mcp-panel 时也以为只是加了个登录页和按钮灰显逻辑直到某次误点“重置模型缓存”按钮后系统弹出的不是确认框而是一张带签名时间戳、含操作人身份哈希、需三位管理员联签的审批工单——我才真正意识到这个面板的“安全模型”不是装饰是整套工作流的底层操作系统。关键词里反复出现的dsh-mcp-panel、MCP、DeepSeek Harness、只读其实共同指向一个现实痛点AI 工程化落地中模型调用、提示词调试、数据上传、插件启用这些行为既不能全放开怕误操作/越权/数据泄露也不能全锁死影响研发效率。传统做法要么靠文档约定要么靠运维手动改配置要么靠代码里硬编码 if-else 判断角色。而 dsh-mcp-panel 的解法很务实它把所有可能改变系统状态的操作全部抽象为 MCP 协议中的Action Request再通过面板内置的Policy Engine对每个请求做实时决策——这个决策过程就是标题里说的“从只读到需审批写入”的跃迁路径。适合谁看如果你正在用 DeepSeek Harness 做本地大模型开发尤其是团队协作场景如果你负责 AI 平台的权限治理常被问“谁能调哪个模型”“谁改过哪条提示词”如果你试过 wangeditor 只读模式、fstab 只读挂载、麒麟系统 hosts 只读编辑这类零散方案却苦于无法统一管控——那这篇就是为你写的。它不讲概念堆砌只拆真实配置、真实日志、真实审批链路。下面我们就一层层剥开这个模型怎么运转、为什么这样设计、以及踩过哪些坑。2. 安全模型整体设计与思路拆解2.1 不是“加个登录”而是重构操作语义很多团队引入 dsh-mcp-panel 的第一反应是“给 DSH 加个 Web UI再配个账号密码就完事了”。结果上线三天测试同学直接在面板里删了生产环境的模型权重缓存理由是“按钮没灰掉我以为能点”。问题出在哪出在把“安全”等同于“身份认证”而忽略了操作授权和行为审计这两个更关键的环节。dsh-mcp-panel 的安全模型本质是三层结构第一层MCP 协议层的语义隔离MCPModel Control Protocol本身定义了一组标准 Action 类型model.load、prompt.update、file.upload、plugin.enable等。dsh-mcp-panel 没有自己发明新动作而是严格复用这套语义。这意味着任何对 DSH 的操作必须先被翻译成标准 MCP Action再进入后续流程。比如点击“上传训练数据”按钮前端不会直接发POST /api/upload而是构造一个file.uploadAction 请求附带文件元信息、目标路径、预期用途标签。这一步看似多此一举实则关键——它把“用户做了什么”从 HTTP 动词路径升级为机器可理解、策略可匹配的结构化语义。第二层Policy Engine 的动态决策所有 MCP Action 请求到达面板后端首先进入 Policy Engine。这个引擎不是简单的 RBAC基于角色的访问控制而是ABAC基于属性的访问控制 Context-aware上下文感知的混合体。它会同时检查主体属性Subject当前用户 ID、所属部门、是否为管理员、最近一次密码修改时间客体属性Object目标模型名称、提示词版本号、文件所在目录的敏感等级标签如/data/publicvs/data/internal操作属性ActionAction 类型、参数值如prompt.update中的新提示词是否含system:前缀、请求来源 IP 是否在白名单环境属性Context当前时间是否在工作时段、是否处于审计期、DSH 实例当前负载是否超阈值80% CPU。四者组合才能决定该 Action 是放行、拒绝、还是转入审批队列。例如普通研发人员prompt.update一个标记为public的提示词且内容不含 system 指令Policy Engine 直接放行但若他尝试更新一个标记为confidential的提示词或新内容含system: you are a code interpreter则自动触发审批。第三层审批流与不可篡改日志需审批的 Action 不会卡在内存里而是持久化为一条带数字签名的审批工单存入面板内置的轻量级事件存储默认 SQLite支持 PostgreSQL 替换。工单包含原始 Action 全量 JSON、发起人指纹、生成时间戳、预设审批人列表按策略动态计算如“模型 owner 安全组成员 当前部门 leader”、超时自动拒绝机制默认 72 小时。审批通过后Action 才被转发给 DSH 执行拒绝或超时则返回明确错误码。所有 Action无论放行/拒绝/审批中均写入 WORMWrite Once Read Many日志不可删除、不可修改供后续审计溯源。这个设计的底层逻辑很清晰不信任任何单一环节用协议语义切分责任用属性组合替代静态权限用审批流兜住高危操作用不可篡改日志锁定行为证据。它解决的不是“能不能登录”而是“登录之后每一步操作是否都被正确理解和约束”。2.2 为什么选 MCP 而非自定义 API网络热词里频繁出现mcp协议、playwright mcp、browser use mcp说明 MCP 正在成为 AI 工具间通信的事实标准。但有人会问DSH 本身已有 REST API为什么 dsh-mcp-panel 不直接封装它答案在于协议演进成本与生态兼容性。DSH 的 REST API 是面向开发者调试的路径设计、参数命名、错误码都偏向工程便利性比如POST /v1/models/{id}/reload和DELETE /v1/cache/{key}语义混杂缺乏统一的动作归类。如果面板直接调用这些接口等于把权限逻辑耦合在前端或后端路由层——一旦 DSH 升级 API面板就得同步改更麻烦的是当你要接入其他工具如 Burp Suite、Playwright、Trae IDE时它们无法理解 DSH 的私有 API必须为每个工具单独开发适配器。而 MCP 是协议层抽象。dsh-mcp-panel 只需实现 MCP 的ActionHandler接口就能对接任何支持 MCP 的后端DSH、Llama.cpp、Ollama 等前端只需发送标准 MCP Action无需关心后端是哪家模型服务。网络热词里trae ide 搭载 burp suite mcp server、playwright mcp的出现恰恰印证了这种解耦的价值——安全模型不再绑定于某个具体工具而是随 MCP 协议流动。你今天用 DSH明天换成其他模型框架只要它支持 MCP面板的安全策略几乎不用重写。2.3 “只读”不是状态而是策略结果标题里的“只读面板”常被误解为整个 UI 灰显禁用。实际上dsh-mcp-panel 的“只读”是动态策略输出而非静态页面属性。同一个用户在不同场景下看到的“只读”范围完全不同访问/models页面时他能看到所有模型卡片但只有标记为public的模型才显示“加载”按钮internal模型卡片上只显示模型名、版本、描述无任何操作入口在/prompts页面他可以自由查看所有提示词内容只读但编辑按钮仅对本人创建且未发布status: draft的提示词可见已发布status: published的提示词编辑按钮变为“申请修改”触发审批流在/files页面他能浏览/data/public下所有文件缩略图但/data/internal目录仅显示“您无权访问”连文件列表都不返回。这种细粒度控制依赖于 Policy Engine 对每个页面渲染请求的预检。前端请求/api/models/list时后端不是简单查数据库返回所有模型而是先执行策略评估对每个模型计算其readable_by(current_user)属性再过滤出true的项。同样/api/prompts/list返回的每条提示词数据都附带can_edit: true/false字段前端据此决定按钮显隐。这比前端 JS 控制“按钮 disable”可靠得多——后者可被绕过而策略评估发生在服务端且每次请求都重新计算。3. 核心细节解析与实操要点3.1 Policy Engine 配置文件深度解读dsh-mcp-panel 的安全策略核心是policies.yaml文件默认位于config/目录。它不是简单的 key-value 配置而是一个声明式策略定义语言。我们来逐段拆解一个典型配置# config/policies.yaml version: 1.0 # 全局默认策略未匹配任何规则的 Action默认拒绝 default_action: deny # 规则列表按顺序匹配第一条命中即终止 rules: # 规则1所有用户均可读取 public 模型 - id: read_public_models description: 允许读取标记为 public 的模型信息 action: model.get condition: object: tags: [public] effect: allow # 规则2管理员可读写所有模型 - id: admin_full_access description: 管理员拥有模型全操作权限 action: model.* subject: roles: [admin] effect: allow # 规则3研发人员可加载 public 模型但需审批加载 internal 模型 - id: dev_load_model description: 研发人员加载模型的权限 action: model.load subject: roles: [developer] condition: object: tags: [public] effect: allow - id: dev_load_internal_model description: 研发人员加载 internal 模型需审批 action: model.load subject: roles: [developer] condition: object: tags: [internal] effect: require_approval approval: approvers: - role: model_owner count: 1 - role: security_officer count: 1 timeout_hours: 48 # 规则4禁止任何人删除模型缓存高危操作 - id: forbid_cache_delete description: 禁止删除模型缓存 action: cache.delete effect: deny关键点解析action: model.loadvsaction: model.*MCP Action 支持通配符。model.*匹配model.load、model.unload、model.get等所有以model.开头的动作而model.load只匹配精确动作。策略编写时务必用最细粒度的动作避免过度授权。比如规则2用model.*是因为管理员确实需要全权限但规则3用model.load因为model.unload可能影响其他用户需单独定义策略。condition中的嵌套逻辑condition.object.tags是典型的 ABAC 属性。DSH 在注册模型时可通过--tag public或--tag internal参数为其打标。面板在查询模型详情时会将这些 tag 作为object属性传入 Policy Engine。注意tags: [public]表示“包含 public 标签”而非“仅含 public 标签”——这是为了支持多标签如[public, deprecated]。effect: require_approval的审批配置approval.approvers定义审批人规则。role: model_owner不是固定用户名而是从 DSH 模型元数据中动态提取的owner字段count: 1表示该角色中任意一人批准即可。timeout_hours: 48是硬性超时超时自动拒绝避免流程卡死。实测中我们曾将timeout_hours设为 168一周结果发现 30% 的审批工单因遗忘处理而超时反而降低了效率最终调整为 48 小时并增加邮件提醒。default_action: deny的重要性这是最小权限原则的体现。没有显式allow或require_approval的 Action一律拒绝。我们曾在线上环境误删了这条配置导致所有未定义规则的 Action如plugin.list默认放行暴露了插件管理接口——幸好是测试环境但教训深刻default_action是安全底线绝不可省略。提示策略文件支持 YAML 锚点Anchor和别名Alias复用复杂条件。例如多个规则都需要检查object.tags是否含confidential可定义confidential_check: confidential_check object: tags: [confidential] rules: - id: confidential_prompt_read condition: *confidential_check ...这能大幅降低配置冗余和维护成本。3.2 MCP Action 的构造与签名验证前端向面板后端发送的每个请求都必须是合法的 MCP Action。这不是简单的 JSON POST而是包含数字签名的结构化消息确保请求未被篡改、来源可信。Action 结构如下{ id: act_abc123xyz, type: prompt.update, timestamp: 2024-05-20T10:30:45Z, subject: { user_id: u_dev_001, roles: [developer], ip: 192.168.1.100 }, object: { prompt_id: p_789, version: v2.1 }, action: { content: You are a helpful assistant. Answer in Chinese., metadata: { source: web_panel, editor: wangeditor } }, signature: sha256abc123...def456 }其中signature字段是关键。它的生成方式是将id、type、timestamp、subject、object、action这六个字段按字典序排序后的 JSON 字符串拼接用面板配置的私钥config/private.key进行 SHA256-RSA 签名再 Base64 编码。后端收到请求后会解析 JSON提取signature用公钥config/public.key验证签名有效性检查timestamp是否在 5 分钟有效期内防重放攻击若验证失败直接返回401 Unauthorized不进入 Policy Engine。这个设计解决了两个核心问题防篡改攻击者即使截获请求也无法修改action.content或object.prompt_id因为签名会失效防冒充前端私钥由用户登录态生成如 JWT 的jti字段不同用户密钥不同无法互相伪造请求。实操中我们使用wangeditor作为提示词编辑器但wangeditor默认不支持签名。解决方案是在wangeditor的onSave回调中手动构造 Action JSON调用window.crypto.subtle.sign()APIWeb Crypto API进行签名再发往面板。代码片段如下// wangeditor onSave 处理 editor.config.onSave async (html, text) { const action { id: act_${Date.now()}_${Math.random().toString(36).substr(2, 9)}, type: prompt.update, timestamp: new Date().toISOString(), subject: { user_id: currentUser.id, roles: currentUser.roles, ip: getClientIP() }, object: { prompt_id: currentPrompt.id, version: currentPrompt.version }, action: { content: text, metadata: { source: web_panel, editor: wangeditor } } }; // 使用 Web Crypto API 签名 const encoder new TextEncoder(); const data encoder.encode(JSON.stringify(sortKeys(action))); const signature await window.crypto.subtle.sign( { name: RSA-PSS, saltLength: 32 }, privateKey, // 从登录态获取的用户私钥 data ); const signedAction { ...action, signature: sha256${btoa(String.fromCharCode(...new Uint8Array(signature)))} }; // 发送至面板 await fetch(/api/mcp/action, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify(signedAction) }); };注意sortKeys函数必须严格按字典序排序对象键否则签名验证会失败。我们曾因subject和object键顺序不一致导致 20% 的请求签名验证失败排查了整整一天才定位到这个细节。3.3 审批流的集成与通知机制审批流不是孤立的它必须与团队现有协作工具打通否则会沦为摆设。dsh-mcp-panel 默认支持三种通知方式邮件通知配置 SMTP 服务器后工单创建、审批、拒绝、超时均发邮件。我们使用腾讯企业邮配置如下# config/notifications.yaml email: smtp_host: smtp.exmail.qq.com smtp_port: 465 username: securityyourcompany.com password: app_password_here # 应用专用密码非邮箱密码 from: dsh-mcp-panel securityyourcompany.com企业微信机器人将审批消息推送到指定群聊。需在企业微信后台创建机器人获取 webhook URLwecom_webhook: https://qyapi.weixin.qq.com/.../your_webhook_keyAPI Webhook将工单事件推送到内部 OA 系统。面板会在工单状态变更时向配置的 URL 发送 POST 请求payload 包含工单全量信息和操作类型created/approved/rejected/timeout。最关键的实操经验是审批人必须明确、可追溯、有备份。我们最初配置approver.role: security_officer但公司只有一个安全官他休假时工单全部积压。后来改为approvers: - role: security_officer count: 1 backup: [security_officer_backup] # 备份角色 - role: tech_lead count: 1 required: false # 非必需但建议参与同时在 OA 系统中设置自动轮值规则确保security_officer_backup角色每天由不同人担任。这样即使主审批人离线备份也能及时响应。另一个坑是审批操作必须原子化。我们曾遇到过并发审批问题——两个审批人几乎同时点击“同意”导致工单状态混乱。解决方案是在数据库层面加乐观锁工单表增加version字段每次更新时检查WHERE id ? AND version ?成功则version失败则返回冲突错误前端提示“已被他人处理”。4. 实操过程与核心环节实现4.1 从零部署 dsh-mcp-panel 并启用安全模型部署不是简单docker run而是涉及 DSH、面板、策略、证书四者的协同。以下是经过生产环境验证的步骤以 Linux Ubuntu 22.04 为例步骤1安装 DeepSeek Harness# 下载最新版 DSH假设为 0.1.5 wget https://github.com/deepseek-ai/deepseek-harness/releases/download/v0.1.5/dsh-linux-amd64-v0.1.5.tar.gz tar -xzf dsh-linux-amd64-v0.1.5.tar.gz sudo mv dsh /usr/local/bin/ sudo chmod x /usr/local/bin/dsh # 初始化 DSH 配置 dsh init --config-dir /etc/dsh # 编辑 /etc/dsh/config.yaml启用 MCP 服务 # 添加以下配置 # mcp: # enabled: true # host: 0.0.0.0 # port: 8080 # tls: false # 生产环境务必设为 true并配置证书 # 启动 DSH后台服务 sudo systemctl enable dsh sudo systemctl start dsh步骤2生成 MCP 通信证书生产环境必需# 创建证书目录 sudo mkdir -p /etc/dsh/mcp-certs # 生成 CA 私钥和证书 sudo openssl genrsa -out /etc/dsh/mcp-certs/ca.key 2048 sudo openssl req -x509 -new -nodes -key /etc/dsh/mcp-certs/ca.key -sha256 -days 3650 -out /etc/dsh/mcp-certs/ca.crt -subj /CNDSH-MCP-CA # 生成面板私钥和 CSR sudo openssl genrsa -out /etc/dsh/mcp-certs/panel.key 2048 sudo openssl req -new -key /etc/dsh/mcp-certs/panel.key -out /etc/dsh/mcp-certs/panel.csr -subj /CNdsh-mcp-panel # 用 CA 签发面板证书 sudo openssl x509 -req -in /etc/dsh/mcp-certs/panel.csr -CA /etc/dsh/mcp-certs/ca.crt -CAkey /etc/dsh/mcp-certs/ca.key -CAcreateserial -out /etc/dsh/mcp-certs/panel.crt -days 365 -sha256 # 配置 DSH 使用该证书 # 编辑 /etc/dsh/config.yaml修改 mcp 部分 # mcp: # enabled: true # host: 0.0.0.0 # port: 8080 # tls: true # cert_file: /etc/dsh/mcp-certs/panel.crt # key_file: /etc/dsh/mcp-certs/panel.key # ca_file: /etc/dsh/mcp-certs/ca.crt步骤3部署 dsh-mcp-panel# 下载面板 Docker 镜像 docker pull ghcr.io/your-org/dsh-mcp-panel:v1.2.0 # 创建配置目录 sudo mkdir -p /opt/dsh-mcp-panel/config sudo mkdir -p /opt/dsh-mcp-panel/data # 复制默认配置模板 curl -o /opt/dsh-mcp-panel/config/config.yaml https://raw.githubusercontent.com/your-org/dsh-mcp-panel/main/config.example.yaml curl -o /opt/dsh-mcp-panel/config/policies.yaml https://raw.githubusercontent.com/your-org/dsh-mcp-panel/main/policies.example.yaml # 编辑 config.yaml关键配置 # dsh: # endpoint: https://localhost:8080 # 必须与 DSH mcp.host/port 匹配 # ca_cert: /etc/dsh/mcp-certs/ca.crt # 面板验证 DSH 证书用 # security: # jwt_secret: your_very_strong_secret_here # 用于生成用户 token # private_key_path: /opt/dsh-mcp-panel/config/private.key # 用于 Action 签名 # public_key_path: /opt/dsh-mcp-panel/config/public.key # 生成密钥对用于 Action 签名 openssl genrsa -out /opt/dsh-mcp-panel/config/private.key 2048 openssl rsa -in /opt/dsh-mcp-panel/config/private.key -pubout -out /opt/dsh-mcp-panel/config/public.key # 启动面板 docker run -d \ --name dsh-mcp-panel \ -p 8000:8000 \ -v /opt/dsh-mcp-panel/config:/app/config \ -v /opt/dsh-mcp-panel/data:/app/data \ -v /etc/dsh/mcp-certs:/certs:ro \ -e DSH_ENDPOINThttps://host.docker.internal:8080 \ -e DSH_CA_CERT/certs/ca.crt \ ghcr.io/your-org/dsh-mcp-panel:v1.2.0步骤4验证安全模型生效部署完成后不要急着登录。先用 curl 测试策略效果# 测试只读获取模型列表应成功 curl -X GET http://localhost:8000/api/models/list \ -H Authorization: Bearer your_jwt_token # 测试写入尝试加载一个 internal 模型应返回 require_approval curl -X POST http://localhost:8000/api/mcp/action \ -H Content-Type: application/json \ -d { id: test_act, type: model.load, timestamp: 2024-05-20T10:00:00Z, subject: {user_id: u_test, roles: [developer]}, object: {model_id: m_internal_001, tags: [internal]}, action: {}, signature: dummy_sig } # 预期响应{status:require_approval,request_id:req_xyz123}如果返回require_approval说明策略引擎已工作。此时去数据库/opt/dsh-mcp-panel/data/app.db查approval_requests表应有一条新记录。4.2 自定义策略为“国产麒麟系统 hosts 只读模式”场景适配网络热词中提到“国产麒麟系统hosts只读模式怎么编辑”这反映了一个典型需求在信创环境中某些系统文件如/etc/hosts需受控修改。DSH 本身不直接操作 hosts但可通过插件实现。我们开发了一个host-manager插件其update_hostsAction 需要严格审批。在policies.yaml中添加规则- id: update_hosts_require_approval description: 更新 hosts 文件需双人审批 action: host-manager.update_hosts subject: roles: [developer, ops] effect: require_approval approval: approvers: - role: sysadmin count: 1 - role: security_officer count: 1 timeout_hours: 24 notify_on_create: true notify_on_approve: true插件实现要点插件接收action.params.entries要添加的 hosts 条目数组如[{ip: 127.0.0.1, domain: test.local}]执行前调用dsh-mcp-panel的/api/mcp/action/status/{request_id}接口检查对应工单是否已批准批准后插件才执行sudo sed -i /test.local/d /etc/hosts echo 127.0.0.1 test.local | sudo tee -a /etc/hosts操作完成后调用/api/mcp/action/log上报执行结果成功/失败/耗时。这个案例说明dsh-mcp-panel 的安全模型可无缝延伸至插件生态。你不需要修改面板核心代码只需在策略中定义新 Action 的审批规则再在插件中遵循 MCP 协议调用即可。4.3 日志审计与问题回溯实战WORM 日志是安全模型的“黑匣子”。面板默认将日志存于 SQLite但生产环境建议用 PostgreSQL 并开启 WALWrite-Ahead Logging。日志表结构简化CREATE TABLE action_logs ( id TEXT PRIMARY KEY, -- 日志唯一ID request_id TEXT, -- 关联的 MCP Action ID status TEXT, -- allowed | denied | approved | rejected | timeout subject TEXT, -- JSON含 user_id, roles 等 object TEXT, -- JSON含 model_id, prompt_id 等 action_type TEXT, -- model.load, prompt.update 等 timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, ip TEXT, user_agent TEXT, -- 关键不可篡改字段 log_hash TEXT NOT NULL, -- 本条日志的 SHA256用于链式校验 prev_log_hash TEXT -- 上一条日志的 log_hash构成区块链式结构 );审计实战技巧快速定位误操作某天研发反馈“模型突然加载失败”经查是有人误删了缓存。用 SQLSELECT * FROM action_logs WHERE action_type cache.delete AND status allowed AND timestamp 2024-05-19 00:00:00 AND subject LIKE %u_dev_007%;结果查到一条记录subject显示是u_dev_007object显示cache_key: model_llama3_70b。再查此人当天所有操作发现他在prompt.update后紧接着执行了cache.delete——明显是调试时手滑。验证策略有效性想确认“internal 模型加载是否真走审批”可查SELECT COUNT(*) FROM action_logs WHERE action_type model.load AND object LIKE %internal% AND status IN (approved, rejected, timeout);如果结果为 0说明策略未生效需检查policies.yaml中model.load规则是否被更早的allow规则覆盖。检测异常行为监控ip字段查找同一user_id从多个 IP 发起请求可能账号被盗SELECT subject-user_id as user_id, GROUP_CONCAT(DISTINCT ip) as ips FROM action_logs WHERE timestamp datetime(now, -7 days) GROUP BY subject-user_id HAVING COUNT(DISTINCT ip) 3;实操心得我们给 DBA 配置了每日凌晨 2 点的自动备份脚本并将备份文件加密上传至 NAS。同时用logrotate对 SQLite 日志文件做滚动压缩保留 90 天。曾有一次磁盘满导致日志写入失败面板自动降级为内存日志丢失部分数据幸好有备份未影响审计。5. 常见问题与排查技巧实录5.1 典型问题速查表问题现象可能原因排查命令/步骤解决方案面板登录后所有按钮灰显无任何操作入口用户角色未正确映射或policies.yaml中default_action: deny导致所有 Action 被拒1. 查看浏览器 Network找/api/user/profile响应确认roles字段2. 检查policies.yaml是否有default_action行确保用户 JWT token 中roles字段与策略中subject.roles一致若无default_action立即添加提交prompt.update后前端无响应Network 显示 500Action 签名验证失败常见于时间戳偏差或私钥不匹配1. 抓包看请求signature字段2. 用openssl dgst -sha256 -sign private.key手动签名测试数据对比检查服务器时间是否同步timedatectl status确认前端使用的私钥与后端private.key一致验证签名算法RSA-PSS审批工单创建成功但企业微信无通知Wecom webhook URL 错误或企业微信机器人被禁用1.curl -X POST webhook_url -d {msgtype:text,text:{content:test}}2. 登录企业微信后台检查机器人状态更新正确的 webhook URL在企业微信管理后台启用机器人检查面板日志tail -f /var/log/dsh-mcp-panel/error.logDSH 报错MCP connection refusedDSH 的 MCP 服务未启动或 TLS 配置错误1.sudo systemctl status dsh2.sudo journalctl -u dsh -n 50 --no-pager3.curl -v https://localhost:8080/health确认 DSH 配置中mcp.enabled: true检查mcp.port是否被占用验证证书路径是否正确ca.crt是否被面板正确挂载**model.load成功但模型实际未
返回列表