Chuyển đến nội dung chính

dsh-abap-mcp

Đã xác minh

@xiaobanli/dsh-abap-mcp · v0.5.0 · MIT · Giao diện web

DeepSeek Harness plugin: connect SAP ABAP ADT over MCP with a read-only-by-default permission model, configured from the Settings page. · DSH 插件:通过 MCP 连接 SAP ABAP ADT,默认只读 + 7 类写权限开关,设置页卡片配置。

Cài đặt

dsh plugin add @xiaobanli/dsh-abap-mcp

Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.

Mã nguồn

Phát hành lên npm mà không có repository công khai. Hãy kiểm tra nội dung package trước khi cài.

Thẻ

Readme

dsh-abap-mcp

⚠️ 实验阶段 · EXPERIMENTAL

本插件仍处于实验阶段(Experimental),仅供开发 / 测试(Dev / Test)环境使用。

  • 请勿直接连接生产系统。 即便默认只读,只读工具也能读取生产系统的源码与业务数据。
  • 请使用 最小权限(least-privilege)的 SAP 账号 连接。
  • 写权限开关(sourceWrite / transports / refactor / exec / git / debug / serviceBinding)默认全部关闭,仅在开发系统上按需、谨慎开启。
  • 密码保存在 DSH 凭据库($DSH_HOME/.credentials.yaml,引用名 SAP_PASSWORD),不写入配置文档,注意凭证安全。

使用本插件即表示你已知悉上述风险,并自行承担后果。

DeepSeek Harness 插件:通过 MCP 连接 SAP ABAP ADT,在 DSH 里直接查询/阅读 SAP 中的 ABAP 对象,默认严格只读,7 类写权限作为可配置开关。

上游服务器:mario-andreschak/mcp-abap-abap-adt-api 本插件在 server/ 里内置了加了权限层的服务器副本(默认只读 + 开关),并负责连接、注册工具、随设置变更重连。

设置页面

设置页面截图

对话验证

对话验证截图

架构

DSH 设置页卡片(ABAP MCP)
        │  settingsScope.set(...)   ←→  settings/updated
        ▼
Host 插件 lib/index.js
  1. settings.register("abap-mcp", schema)   # 连接配置 + 7 类权限开关 + 状态
  2. spawn `node server/dist/index.js`(StdioClientTransport,env=SAP_* + MCP_ABAP_PERMISSIONS)
  3. MCP Client 连接,把服务器工具注册为 mcp__abap__<tool>
  4. 配置变更 → 去抖重连;连接断开 → 有界退避重试
        ▼
server/dist/index.js(MCP 服务器,权限在这里强制生效)
  - MCP_ABAP_PERMISSIONS 未设置 → 默认只读(约 80 个只读工具)
  - 7 类写权限通过 MCP_ABAP_PERMISSIONS 的 JSON 开关启用
  • 权限单一事实来源在服务器侧:Host 只是把开关值透传给服务器,工具列表与调用都按权限过滤/拒绝。即使有人绕过 DSH 直接连服务器,权限依然生效。
  • 工具命名:mcp__abap__<工具名>(如 mcp__abap__searchObject)。

权限模型(默认 = 严格只读)

权限模型在 server 侧强制(server/src/permissions.ts → dist/permissions.js)。默认只读核心始终开启;7 类写权限默认全关,通过 MCP_ABAP_PERMISSIONS 环境变量按类别开启。未登记的任何工具一律拒绝(deny-by-default),新增的 handler 不会悄悄放开。

只读核心(~80 个工具,始终开启)

子分组 工具 说明
认证 / 会话 login logout dropSession 登录 / 登出 / 清除本地会话缓存
对象发现 objectStructure searchObject findObjectPath objectTypes reentranceTicket 查对象结构 / 搜索 / 定位路径 / 对象类型 / 重入票
类内省 classIncludes classComponents 类的 include 组成 / 组件列表
代码分析(只读) syntaxCheckCode syntaxCheckCdsUrl codeCompletion findDefinition usageReferences syntaxCheckTypes codeCompletionFull codeCompletionElement usageReferenceSnippets fixProposals fixEdits fragmentMappings abapDocumentation 语法检查 / 补全 / 定义跳转 / 引用查询 / 修复建议 / 文档(只读)
源码读取 getObjectSource 读取对象源码
源码检索(grep) grepObjects grepPackages 按正则搜索对象源码:先按名/按包圈定候选,再逐个拉源码做行匹配(只读)
系统信息 getSystemInfo getInstalledComponents SID / 客户端 / NetWeaver-ABAP 版本 / 已安装组件(来自 T000/CVERS,只读)
非活动对象 inactiveObjects 列出未激活对象
注册 / 校验 objectRegistrationInfo validateNewObject 对象注册信息 / 新建对象参数校验(只读)
传输读取 transportInfo hasTransportConfig transportConfigurations getTransportConfiguration userTransports transportsByConfig systemUsers transportReference 传输请求信息 / 用户传输 / 配置 / 系统用户(只读)
仓库浏览 nodeContents mainPrograms 对象树浏览 / include 主程序
特性 / 发现 featureDetails collectionFeatureDetails findCollectionByUrl loadTypes adtDiscovery adtCoreDiscovery adtCompatibiliyGraph ADT 能力发现 / 特性查询
单测结果读取 unitTestEvaluation unitTestOccurrenceMarkers 评估单测结果 / 标记位置(只读)
格式化设置读取 prettyPrinterSetting 读取格式化设置(不修改)
Git 读取 gitRepos gitExternalRepoInfo checkRepo remoteRepoInfo 仓库列表 / 远程信息 / 检查(只读)
DDIC 读取 annotationDefinitions ddicElement ddicRepositoryAccess packageSearchHelp 注解 / DDIC 元素 / 包搜索(只读)
服务绑定详情 bindingDetails 服务绑定详情(只读)
数据读取 tableContents runQuery 表数据 / SQL 查询(只读)
Feeds / Dumps feeds dumps 动态对象列表 / 短转储(dump)列表
改名分析 renameEvaluate renamePreview 改名评估 / 预览(只执行不落盘)
ATC 读取 atcCustomizing atcCheckVariant atcWorklists atcUsers isProposalMessage atcContactUri ATC 检查配置 / 变式 / 工作清单 / 用户 / 联系人(只读)
追踪读取 tracesList tracesListRequests tracesHitList tracesDbAccess tracesStatements 追踪列表 / 请求 / 命中 / DB 访问 / 语句(只读)
修订 / 健康 revisions healthcheck 对象修订历史 / 连接健康检查

7 类写权限(默认全关)

开关 子分类 工具 说明
sourceWrite 源码写入 setObjectSource deleteObject activateObjects activateByName createObject createTestInclude lock unLock 写源码 / 删对象 / 激活 / 建对象 / 建测试 include / 锁定与解锁
transports 传输请求 createTransport setTransportsConfig createTransportsConfig transportDelete transportRelease transportSetOwner transportAddUser 创建 / 配置 / 删除 / 释放 / 换负责人 / 加用户
refactor 重构 renameExecute extractMethodEvaluate extractMethodPreview extractMethodExecute prettyPrinter setPrettyPrinterSetting 改名执行 / 抽取方法(评估/预览/执行)/ 格式化(读写)
exec 运行类 runClass unitTestRun 运行 ABAP 类 / 运行单元测试
ATC 写操作 createAtcRun atcExemptProposal atcRequestExemption atcChangeContact 发起 ATC 检查 / 豁免建议 / 请求豁免 / 改联系人
追踪配置 tracesSetParameters tracesCreateConfiguration tracesDeleteConfiguration tracesDelete 设追踪参数 / 建配置 / 删配置 / 删记录
git Git 写操作 gitCreateRepo gitPullRepo gitUnlinkRepo stageRepo pushRepo switchRepoBranch 创建仓库 / 拉取 / 解除链接 / 暂存 / 推送 / 切分支
debug 调试 debuggerListeners debuggerListen debuggerDeleteListener debuggerSetBreakpoints debuggerDeleteBreakpoints debuggerAttach debuggerSaveSettings debuggerStackTrace debuggerVariables debuggerChildVariables debuggerStep debuggerGoToStack debuggerSetVariableValue 监听 / 断点 / 附加 / 单步 / 栈 / 变量读写
serviceBinding 服务绑定 publishServiceBinding unPublishServiceBinding 发布 / 取消发布 OData 服务绑定

说明:只读核心里的「ATC 读取」「追踪读取」「Git 读取」「传输读取」只能读;对应分类里的写工具(发起检查、改配置、推代码、发服务等)才需要开权限。改名前仅预览(renameEvaluate/renamePreview)是只读的,真正执行(renameExecute)才要 refactor。

权限人工确认(防止 AI 自行开启权限)

开启任意权限开关时,插件要求人工确认:设置页卡片在勾选时会生成一个一次性确认凭据(confirm-<时间戳>-<随机串>)写入配置,Host 侧仅在凭据新鲜(60 秒内)且格式正确时才允许以对应模式连接,否则强制回退只读并在状态里提示「需在设置卡片人工确认」。该机制覆盖全部 7 类权限开关(sourceWrite / transports / refactor / exec / git / debug / serviceBinding),一视同仁。

  • 只能通过设置页卡片开启权限。通过 settings API / 直接改 settings.yaml / 对话中让模型改 permissions 的方式开启,都会因缺少有效凭据而被拒绝。
  • 凭据有 60 秒时效,重启后自动过期,需重新在卡片操作。
  • 关闭全部权限(回到全关)无需确认,始终允许。

写操作逐次人工确认(每次写入都弹审批,可开关)

除了「开启权限」这一层确认,每次真正的写操作执行前还有一层逐次人工确认(设置页卡片上的 writeConfirm 开关,默认开启):

  • 模型调用任意写工具(即 server/src/permissions.ts 里 CATEGORY_TOOLS 列出的工具,如 setObjectSource / deleteObject / activateObjects / createTransport / renameExecute / pushRepo / debuggerSetBreakpoints 等)时,DSH 会弹出原生审批卡,展示:
    • 工具名(如 mcp__abap__setObjectSource)
    • 将写入的对象/参数摘要(目标对象名、URL、传输号)
    • 源码类写操作(setObjectSource / createObject / createTestInclude)会先做真实的「旧 → 新」行级 diff:审批卡内联显示每处改动的 -/+ 行(含行号、改动计数 +N/-M),新建对象则显示完整源码行数
    • 一次「允许一次 / 拒绝」的选择
  • 「序号 + 点击展开」工具卡:写工具执行时,对话流里的工具卡会渲染「写前预览」——每处改动一个序号按钮,点击即展开该处 -/+ 差异;改动再多也不省略,按需加载。审批按钮仍在原生审批卡上,本卡只负责让用户看清「到底会改成什么」。
  • 只有用户点击**「允许一次」**,该次写操作才会真正向 SAP 执行;拒绝 / 取消 / 无审批通道时一律不写入(fail-closed)。
  • 该机制复用 DSH 原生审批通道(ctx.approval,与文件写入、命令执行的越权审批同款),自带审计日志,无需额外 UI。
  • 只读工具不经过此确认,不受影响。
  • 关闭 writeConfirm 后:写工具在对应权限已开启时直接执行、不弹审批(不推荐,仅当对写操作有充分信任时使用)。
  • 开关状态会反映在 abap_mcp_status.writeConfirm;该字段不参与重连判定。

安全加固:runQuery 仅允许只读 SQL

runQuery 虽然列在只读核心,但它走 ADT Data Preview 的 freestyle SQL 端点——部分后端允许 DML。为避免它成为「无权限、无写确认」的隐藏写通道,服务器侧已做确定性白名单:只放行以 SELECT / WITH / EXPLAIN / DESCRIBE 开头的单条语句,且不允许分号拼接多语句;命中 UPDATE / INSERT / DELETE / DROP 等一律拒绝,绝不把语句发给后端。

安装

从 npm(正式包)

dsh plugin add @xiaobanli/dsh-abap-mcp

本地目录(开发/联调)

在 profile 的 package.json 增加依赖并执行 pnpm install:

{
  "dependencies": {
    "@xiaobanli/dsh-abap-mcp": "link:<你的本地插件目录绝对路径>/dsh-abap-mcp"
  },
  "dsh": { "profile": { "bundles": [ "...", "dsh-abap-mcp" ] } }
}

重启 DSH 后,设置页左侧会出现「ABAP MCP」卡片。

配置(设置页卡片)

前置准备(连接前请确认)

  1. SAP 侧需在事务码 SICF 中开启 ADT 服务节点:插件通过 ABAP Development Tools (ADT) 的 HTTP(S) 服务访问 SAP,若相关 ADT 服务节点未激活,连接会失败。一般在 SICF 里激活 default_host/sap/bc/adt 及其子节点即可(具体节点随系统版本略有差异)。
  2. SAP 地址格式:大多数为 http://地址:端口 或 https://地址:端口(部分高版本/网关配置为 http://地址:端口/sap/bc/adt 的完整路径)。请根据实际系统确认协议与端口,例如 http://10.0.0.1:8000 或 https://sap.example.com:44300。
字段 说明
启用连接 总开关;关闭时不连接、不注册任何工具
SAP 地址 如 http://地址:端口 / https://地址:端口(需先开启 ADT 服务)
用户名 / 密码 连接凭证
客户端 / 语言 如 000 / EN
7 类写权限开关 勾选即启用对应写能力

推荐操作流程

  1. 在卡片填好 SAP 地址 / 用户名 / 密码(密码写入 DSH 凭据库,卡片只写不读)。
  2. 先点「测试连接」:显示成功(工具数约 80)即说明配置与网络都没问题。
  3. 再打开「启用连接」开关(总开关)。
  4. 稍等几秒,再查看连接状态(卡片状态块,或在对话里问模型 abap_mcp_status)。
    • 状态变为「已连接 / read-only / N 个工具」即成功。
    • 若仍显示失败,把 abap_mcp_status 返回的 error 字段贴出来排查。

配置保存后 Host 会按当前配置重连;也可以直接问模型 abap_mcp_status 查看连接状态。

「测试连接」按钮:先把当前表单落盘,再用当前配置做一次真实的 spawn→连接→工具枚举→断开, 结果(成功/失败、耗时、工具数)显示在按钮旁;不改变「启用连接」开关状态。

  • 未填写 SAP 地址 / 用户名 / 密码时,按钮直接提示「请先填写配置」,不会空跑一次测试。
  • 测试进行中按钮显示「测试中…」;60 秒无结果自动判超时并提示。
  • 测试结果(status.lastTest)会持续显示在按钮旁,不会被重连状态刷新抹掉。
  • 测试是一次性动作:不会触发持久连接或自动重连,测试失败也不会进入退避重试; 仅当配置变更(启用开关/连接字段/权限)时才触发持久连接与有界重连(最多 5 次后放弃)。
  • 若「测试连接」成功且当前已启用,插件会顺带建立持久连接,卡片状态立即变为已连接; 测试失败则保持原状(不重试、不重连)。

构建服务器(修改 server/ 后)

cd server
npm install --ignore-scripts   # 依赖均为纯 JS,无需生命周期脚本
node node_modules/typescript/bin/tsc -p tsconfig.json   # 产出 dist/

故障排查(Troubleshooting)

「测试连接」一直显示「测试中…」,或点了没反应

  • 多半是设置写入没落盘成功。确认 SAP 地址 / 用户名 / 密码都已填写;插件会把设置写回本地 settings.yaml。
  • 若反复卡住,检查 DSH 日志里是否有 SettingsConflictError(设置 revision 冲突导致写入被丢弃)——重启 DSH 后再试一次。

连接报 McpError: Connection closed

  • 桌面版宿主跑在 Electron 里,子进程需要以 Node 模式启动(插件已自动设置 ELECTRON_RUN_AS_NODE=1)。
  • 若仍出现,确认 server/dist/index.js 存在(未修改 server/ 源码则无需重新构建);直接 node server/dist/index.js 能在终端待命说明服务器本身正常。

启用了某写权限开关,但对应工具没出现

  • 权限的真正生效点在服务器侧:开关保存后插件会重连并重新枚举工具(工具数应增加,如 75 → 83)。
  • 权限只读工具数不变时,检查 abap_mcp_status 的 mode 是否已变成 read-only + <类别>;若仍是 read-only,说明开关没保存成功。

改完 server/ 源码后工具行为没变化

  • 需要重新构建:cd server && npm install --ignore-scripts && node node_modules/typescript/bin/tsc -p tsconfig.json,然后重启 DSH 让插件用上新的 dist/。

运行期 ABAP 报 STRING_OFFSET_TOO_LARGE 等错误

  • 这类错误来自 SAP 侧被读取/执行的 ABAP 程序本身,与插件无关。用 mcp__abap__dumps 查看短转储详情,或在 SE38 里修正对应程序。

安全说明

  • 只读 ≠ 无害:只读工具仍可能读取生产系统里的源码与业务数据。强烈建议连开发/测试系统,使用最小权限账号(权限开关只是 DSH 侧的护栏,不替代 SAP 侧的授权)。
  • 服务器会在启动时打印权限模式与"建议仅用于开发/测试系统"的提示(这是建议 + 提示,不强制)。
  • 密码保存在 DSH 凭据库($DSH_HOME/.credentials.yaml,credentials 服务,引用名 SAP_PASSWORD),设置卡片只写不读;首次启动会把历史 settings.yaml 里的明文密码自动迁移进凭据库并清空旧字段。若启动环境已设置 SAP_PASSWORD,以环境变量为准且凭据条目只读(与 DEEPSEEK_API_KEY 同款行为)。连接配置(url / user / client / language / 权限开关)仍写在 settings.yaml。
  • 服务器子进程只继承 SDK 白名单环境变量 + 本插件显式注入的 SAP_* 与 MCP_ABAP_PERMISSIONS,不泄漏宿主其余环境变量。

License

MIT。服务器部分版权归原作者 mario-andreschak(MIT),本插件在其基础上加入权限层。