abap-adt-mcp
Allows AI agents to read, check, write, activate, and transport ABAP code directly on SAP ABAP systems via the ABAP ADT REST API, covering the full development lifecycle without requiring SAP GUI.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@abap-adt-mcpsearch for ZCL* objects"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ABAP ADT MCP Server 设计文档
基于 ABAP ADT(ABAP Development Tools)REST API 构建的 Model Context Protocol (MCP) 服务器。 让 AI Agent(Claude Desktop / Cline / VS Code Copilot Agent / 任意 MCP 客户端)无需 SAP GUI 即可 读取、检查、编写、激活、传输 ABAP 代码,覆盖完整开发生命周期。
1. 设计定位与决策
社区已有成熟实现,本项目的定位不是重复造轮子,而是采用"AI 友好"的高层工具设计:
现有项目 | 定位 | 本项目的取舍 |
| 对 | ✅ 复用其底层库 |
| 偏向只读的高层工具(GetProgram/GetClass…) | ✅ 借鉴其"高层工具"思路 |
| AI 友好工作流、安全优先、审计日志 | ✅ 主要设计蓝本:把 lock 编排、错误翻译、只读/白名单封装进工具内部 |
结论:底层通信直接建立在业界验证的 abap-adt-api(v3.1.2)之上,
避免自己重写脆弱的 ADT REST 协议(CSRF、XML 解析、对象元数据)。
在其之上构建一层安全优先、面向 Agent 的高层工具,使 Agent 通过工具名即可理解能力,且不会留下悬空锁、不会误改 SAP 标准对象。
Related MCP server: vibing-steampunk
2. 架构分层
┌─────────────────────────────────────────────────────────────┐
│ MCP Client (Claude / Cline / VS Code Agent / FLUJO) │
└───────────────────────────┬─────────────────────────────────┘
│ JSON-RPC over stdio
┌───────────────────────────▼─────────────────────────────────┐
│ MCP Server (this project, TypeScript) │
│ │
│ ├─ tools/read.ts 只读/检查工具 (11) │
│ ├─ tools/write.ts 写入编排工具 (4) — 仅非只读模式注册 │
│ ├─ tools/ddic.ts DDIC 创建工具 (2) — 域 / 数据元素 │
│ ├─ tools/table.ts DDIC 创建工具 (1) — 透明表 │
│ ├─ tools/package.ts DDIC 创建工具 (1) — 包 DEVC/K │
│ ├─ tools/textelements.ts 文本元素读写 (1读+1写) │
│ ├─ tools/functions.ts 函数模块读写 (2读+3写, SE37) │
│ ├─ tools/edit.ts surgical edit 工具 (1) — token 优化 │
│ ├─ tools/decisions.ts 统一 包/请求 决策(澄清 vs 直接绑定) │
│ ├─ resources/ 可浏览资源 (system info / package) │
│ ├─ adt/security.ts 安全层:只读、Z*/Y* 白名单、审计日志 │
│ ├─ adt/errors.ts 错误翻译(可行动的错误信息) │
│ └─ adt/client.ts 连接生命周期 + 每个 ADT 操作的薄封装 │
└───────────────────────────┬─────────────────────────────────┘
│ HTTPS + CSRF (abap-adt-api)
┌───────────────────────────▼─────────────────────────────────┐
│ SAP ABAP System (SICF: /sap/bc/adt 已激活, 用户具 S_DEVELOP) │
└─────────────────────────────────────────────────────────────┘关键原则(对应 MCP Builder 准则)
描述性工具名 —
adt_write_source而非tool1;Agent 靠名字选工具。Zod 类型化参数 — 每个输入都校验,可选参数有默认值。
结构化输出 — 数据返回 JSON,源码类内容返回带行号的文本。
优雅失败 — 所有工具经
safe()包裹,错误转为isError文本,服务器永不崩溃。无状态工具 — 每次调用独立;SAP 会话由单例
ADTClient维护。安全优先 — 见第 4 节。
3. 工具清单(24 个:11 只读 + 13 写入)
只读 / 检查(始终注册,含只读模式)
工具 | 说明 | 关键参数 |
| 连通性 + 会话/角色信息诊断 | — |
| 按名称模式搜索对象(支持 |
|
| 列出包(DEVCLASS)内对象 |
|
| 读取源码,支持行范围切片、行号前缀、截断保护; |
|
| 对象结构大纲;类返回每个 include 的 sourceUri + 方法/属性清单(方法级定位) |
|
| 语法检查(不锁、不写) |
|
| 列出用户传输请求 |
|
| 读 DDIC 表 / CDS 视图数据(WHERE + 行数限制) |
|
| 读程序文本元素(文本符号 / 选择文本 / 列表标题三类),支持语言覆盖 |
|
| 读函数模块(SE37):完整源码 + 解析出的参数接口(IMPORTING/EXPORTING/CHANGING/TABLES/EXCEPTIONS)。不传 |
|
| 列函数组的函数模块/包含程序:返回每个模块名、URI、描述,便于调用/读取前先发现组里有什么 |
|
写入(仅非只读模式注册)
工具 | 说明 | 关键参数 |
| AI 安全编辑编排:冲突检查 → 语法检查 → 锁 → 写 → 解锁(finally) → 可选激活 |
|
| 激活对象(含未激活部分) |
|
| 创建对象壳(无源码),返回 URI 供后续写入 |
|
| 传输请求:create / release / list |
|
| 创建开发包(DEVC/K):包必须嵌套在真实父包下并继承其父包的软件组件+传输层,故必传 |
|
| 创建 DDIC 域(DOMA):骨架 → 锁 → PUT 技术属性(类型/长度/小数) → 解锁 → 可选激活。 |
|
| 创建 DDIC 数据元素(DTEL):引用已有域,技术类型(CHAR/长度/小数)自动从域派生;骨架 → 锁 → |
|
| 创建 DDIC 透明表(TABL):ABAP 字典 DDL 源( |
|
| 写程序文本元素:锁 textelements 资源 → PUT 三类(symbols/selections/headings) → 解锁 → 激活文本池。symbols 用 |
|
| surgical edit(token 优化):Agent 只发 |
|
| 创建函数组(FUGR):在包(默认 |
|
| 创建函数模块(FUGR/FF):在已存在函数组中建模块、写源码、可选激活。源码接受经典 |
|
| 编辑已有函数模块源码(lock → write → unlock → 可选激活)。接受经典或归一化源码,自动归一化。只读模式禁用,名需匹配 Z*/Y* 前缀。首次创建请用 |
|
资源(Resources)
adt://system/info— 连接与角色信息adt://packages/{pkg}— 包内容清单(JSON)
4. 安全模型(最重要)
ABAP 系统里误改 SAP 标准对象或留下悬空锁是真实风险。本设计内建四道防线:
只读模式:
ABAP_MCP_READONLY=true时,13 个写入工具根本不注册(Agent 看不到),其余工具拒绝变更。生产系统强制只读:
ABAP_MCP_SYSTEM_ROLE=prod时,无论READONLY如何,一律只读。Z/Y 前缀白名单**:
assertPrefixAllowed()校验对象名,默认仅允许Z,Y前缀,杜绝误改 SAP 交付对象。审计日志:每次写入追加 JSON 行到
ABAP_MCP_AUDIT_LOG,含时间、工具、对象、传输号、状态。
adt_write_source 的锁编排保证 try/finally 释放锁;即使写入失败也不会留下悬空锁。
4.1 统一「包 / 请求」决策流(所有写入工具共用)
每个写入工具在创建对象前,都要先决定目标开发包与传输请求。逻辑统一由 tools/decisions.ts 的 resolvePackageInput() / resolveTransportInput() 实现,规则如下:
包(package)决策
调用方显式给了
package→ 直接绑定到该包(已大写上送)。调用方没给
package→ 工具返回一条结构化澄清(needsClarification:true、topic:"package"),列出两个动作让 Agent 转问用户:create_package— 调用adt_create_package新建一个真实包(需指定superPackage父包);该选项额外携带requiredInputs:[name, superPackage, description],提示 Agent 必须先从用户处确认这三项必填信息再调建包工具。keep_local— 落到本地包$TMP(无需传输)。
传输请求(transport)决策(同样逻辑)
调用方显式给了
transport→ 直接绑定。包是
$TMP→ 本地对象,不需要传输(resolveTransportInput返回空串,后续调用不传corrNr)。包是非
$TMP且没给transport→ 返回结构化澄清(topic:"transport"、action:create_transport),由 Agent 经adt_manage_transport(create) 建请求后回填。
设计要点:工具绝不静默默认到
$TMP或自动建包——缺参数时一律返回needsClarification,把选择权交还给用户,避免 Agent 在用户不知情的情况下把对象塞进本地包或误建包。澄清对象结构为{ needsClarification, topic, message, options:[{action,label,description,requiredInputs?}], missingFields?, tool, object }:
topic:"package"/"transport"的澄清:options列出可行动作,Agent 转述给用户、回收选择后重新调用同一工具并补上package/transport。
topic:"package_creation"的澄清(由adt_create_package自身返回):当name/superPackage/description任一缺失时返回,missingFields列出缺哪些包必填项,Agent 与用户确认后用完整参数重新调用adt_create_package。这一层保证「创建包前必与用户确认必填信息」,缺项时绝不猜测或崩溃。通用
topic:"missing_inputs"澄清(仅「重型创建」类工具保留):adt_create_function_group(需name/description)、adt_create_domain(需name/description/datatype/length)、adt_create_dataelement(需name/domain/description)、adt_create_table(需name/description/fields)——这类工具自身有多个必填项、且参数结构较复杂,缺项时返回missing_inputs澄清(missingFields列出缺什么 + 中文 label + hint),由decisions.ts的inputClarification()工厂统一生成,缺项检查在 handler 顶部、任何 SAP 调用之前完成。其余 8 个写入工具已还原为 Zod 必填校验(不再返回
missing_inputs澄清):adt_write_source、adt_activate_object、adt_create_object、adt_manage_transport、adt_create_function_module、adt_write_function_module_source、adt_write_textelements、adt_edit_source。它们的必填字段(如objectUri/source/edits/name/action等)在 Zod schema 中声明为必填,缺项时由 MCP SDK 返回标准校验错误,而非结构化澄清。其中adt_manage_transport的action=create需objectUri、action=release需transport仍由 handler 内显式throw校验(create/release 的条件性必填)。
真机验证结论(verify_packages.mjs,VERDICT: PASS):
缺包 → 返回
topic=package澄清;缺传输(非$TMP)→ 返回topic=transport澄清;$TMP路径无需传输。adt_create_package在ZRAP_TEST_192637下建包,自动继承softwareComponent=HOME、transportLayer=ZS4C。adt_create_dataelement/adt_create_domain/adt_create_table在显式transport下创建时,对象均正确绑定到该传输请求(域通过 POST/LOCK/PUT 全程带corrNr实现)。⚠️ 已知 SAP 限制:通过 ADT 创建的包(DEVC/K)因携带 SAP 自动生成的子对象,ADT 删除端点会报「仍然包含开发对象或其它包」而拒绝删除——这是 SAP 行为,非本 server 缺陷;验证脚本对包做尽力删除(不计入功能结论),残留测试包可在 SE21/SE80 手动清理。
5. 错误处理哲学
底层错误(ADT 业务异常 / 网络 / TLS / 锁冲突)被 translateError() 翻译成可让 Agent 自我纠正的中文信息,例如:
证书错误 → 提示设置
SAP_SSL_REJECT_UNAUTHORIZED=false401/403 → 提示检查账号/客户端/是否被锁
锁冲突 → 提示去 SM12 释放或重试
语法错误 → 在
adt_write_source中写前拦截并返回行号,不真正写入
6. 安装与配置
前置条件
Node.js ≥ 20(本项目用 22 验证)
一个启用了 ADT 的 SAP ABAP 系统(
SICF中/sap/bc/adt已激活,用户具S_DEVELOP)
步骤
git clone <this-repo> abap-adt-mcp && cd abap-adt-mcp
npm install
cp .env.example .env # 填入 SAP_URL / SAP_USER / SAP_PASSWORD / SAP_CLIENT
npm run build # 产出 dist/配置文件名:服务器按以下优先级加载(后者不覆盖前者已设的值):
MCP 客户端
env块中直接传入的变量(最高优先级)项目根目录的
.env项目根目录的
MCP.env(本项目的约定文件名,便于与客户端配置共存)所以把配置放在项目根的
MCP.env即可被自动加载,无需改名。
.env / MCP.env 关键项:
SAP_URL=https://s4h.example.com:44300
SAP_USER=DEVELOPER
SAP_PASSWORD=*****
SAP_CLIENT=100
SAP_SSL_REJECT_UNAUTHORIZED=true # 自签名证书开发环境设为 false
ABAP_MCP_SYSTEM_ROLE=dev # prod 会强制只读
ABAP_MCP_READONLY=false
ABAP_MCP_ALLOWED_PREFIXES=Z,Y
ABAP_MCP_AUDIT_LOG=./abap-mcp-audit.log接入 MCP 客户端(任选其一)
a) 任意客户端(npx,无需构建)
{
"mcpServers": {
"abap-adt-mcp": {
"command": "npx",
"args": ["-y", "abap-adt-mcp"],
"env": {
"SAP_URL": "https://...:44300",
"SAP_USER": "DEVELOPER",
"SAP_PASSWORD": "*****",
"SAP_CLIENT": "100"
}
}
}
}b) 本地构建后(stdio)
{
"mcpServers": {
"abap-adt-mcp": {
"command": "node",
"args": ["/绝对路径/abap-adt-mcp/dist/index.js"],
"env": { "SAP_URL": "...", "SAP_USER": "...", "SAP_PASSWORD": "...", "SAP_CLIENT": "100" }
}
}
}调试可用:
npm run inspect启动官方 MCP Inspector。
7. 端到端使用示例
你: 读取 ZCL_INVOICE 的源码并加一个方法,然后激活。
Agent 内部流程:
1. adt_search_objects query="ZCL_INVOICE" → 拿到 objectUri
2. adt_read_source objectUri=... → 当前源码
3. adt_syntax_check source=<新源码> → 预校验(写前拦截错误)
4. adt_write_source objectUri=... source=<新> activate=true
内部: 解析传输 → 语法检查 → lock → setObjectSource → unlock(finally) → activate
5. 返回 { written:true, transport:"NPLK900123", activated:true, success:true }8. AI Token 优化
三类策略降低 Agent 与 SAP 交互时的 token 开销(对标 VSP 的方法级手术 + 上下文压缩):
8.1 Surgical edit(写入侧,adt_edit_source)
Agent 只发 {oldString, newString} 改动片段,不发整个对象源码。工具内部读当前源码 → 逐个替换(要求 oldString 唯一匹配,否则报错并提示加上下文消歧)→ 走 lock/write/unlock/activate 编排。对 2000 行类改一个 5 行方法,请求载荷省 90%+。
8.2 方法级读取定位(读取侧,adt_get_object_structure 增强)
对类返回每个 include(definitions/implementations/main/testclasses)的 sourceUri + 方法/属性清单(name + visibility)。Agent 拿到 include sourceUri 后用 adt_read_source 只读单个 include(如只读实现部分),配合行范围切片定位到具体方法,避免读整个类。
8.3 源码压缩 prologue(读取侧,adt_read_source 的 attachContext)
attachContext=true 时,解析源码中 TYPE/LIKE 引用的 DDIC 对象名(排除 ABAP 内置类型),逐个查 domain/data element 端点取一行摘要(NAME DATATYPE(LENGTH)),附加为 prologue。上限 12 个对象,避免过多调用。Agent 一次读源码即可获得所有引用类型的概要,省去逐个查 DDIC 的往返。
9. 扩展点
ATC 质量门禁:调用
abap-adt-api的 ATC 接口,在adt_write_source中加一道run_atc_check。单元测试:
runUnitTest(url)接入adt_activate_object之后的 CI 流。BTP OAuth2 + PKCE:
abap-adt-api支持传入BearerFetcher,可替换账号密码登录(参考@abapify/adt-cli的 service-key 流程)。Streamable HTTP:用 FLUJO 或
mcp-proxy把 stdio 服务暴露为 HTTP,供远程 Agent 调用。Git/abapGit:
abap-adt-api已支持gitRepos / stageRepo / pushRepo,可加adt_git_*工具。
10. 目录结构
abap-adt-mcp/
├─ package.json
├─ tsconfig.json
├─ .env.example
├─ README.md
└─ src/
├─ index.ts # 入口:建 McpServer、注册、连接 stdio
├─ config.ts # 环境变量 + 安全默认值
├─ adt/
│ ├─ client.ts # ADTClient 单例 + 每操作封装
│ ├─ errors.ts # 错误翻译
│ └─ security.ts # 只读/白名单/审计
├─ tools/
│ ├─ index.ts # 聚合注册(按只读模式决定写入工具)
│ ├─ read.ts # 11 个只读工具(含 attachContext prologue + 方法级定位增强)
│ ├─ write.ts # 4 个写入工具(含 lock 编排)
│ ├─ ddic.ts # 2 个 DDIC 创建工具(域 / 数据元素)
│ ├─ table.ts # 1 个 DDIC 创建工具(透明表)
│ ├─ package.ts # 1 个 DDIC 创建工具(包 DEVC/K,含父包属性继承)
│ ├─ textelements.ts # 文本元素读写(adt_read_textelements + adt_write_textelements)
│ ├─ edit.ts # surgical edit 工具(adt_edit_source, token 优化)
│ ├─ decisions.ts # 统一 包/请求 决策(resolvePackageInput / resolveTransportInput + 澄清结构)
│ ├─ util.ts # safe() / textResult / jsonResult 公共工具
│ └─ util.ts # 结果格式化 + safe() 包裹
└─ resources/
└─ index.ts # system info / package 资源10. 验证状态
✅
npm run build通过(TypeScript 严格模式,零错误)✅ stdio 冒烟测试通过:MCP
initialize→tools/list返回 24 个工具(11 只读 + 13 写入);adt_ping在未配置 SAP 时返回isError而非崩溃✅ 真实 S/4HANA 联调:
adt_create_dataelement创建引用YTEST_192637的数据元素成功并激活(datatype=CHAR, length=11);存在性守卫与坏域守卫均优雅报错✅ 真实 S/4HANA 联调(函数模块):
verify_functions.mjs全绿(VERDICT: PASS)——读BAPI_USER_GET_DETAIL(44 参数)、列ZAIRFC_TOOLS(5 模块)、建组ZFMCPV2_192637并激活、建模块ZFMCPV2_FM(经典含"*注释块源码被自动归一化并激活)、读回解析出IV_NAME/EV_GREETING、编辑加CHANGING CV_COUNTER并激活、清理删除成功。关键结论:ADT 拒绝经典FUNCTION z_fm.尾点形式与"*Local Interface 注释块,本 server 的normalizeFmSource()已将其转换/重写为 ADT 接受的function name+ 小写接口块 + 独立.+endfunction.形式✅ 真实 S/4HANA 联调(统一包/请求决策流):
verify_packages.mjs功能全绿(FUNCTIONAL VERDICT: PASS)——24 工具齐全且含adt_create_package;缺包→返回topic=package澄清、缺传输(非$TMP)→返回topic=transport澄清、$TMP路径无需传输;adt_create_package缺必填项时返回topic=package_creation澄清并列出missingFields(name/superPackage/description),创建包前必与用户确认必填信息;adt_create_package在ZRAP_TEST_192637下建包继承HOME/ZS4C;adt_create_dataelement/adt_create_domain/adt_create_table在显式transport下均正确绑定该请求。清理阶段子对象可正常删除,包本身因 SAP「自动子对象」限制无法经 ADT 删除(已知限制,不计入功能结论)
11. 部署到其他电脑(便携分发)
本服务器源码可移植:config.ts 用 fileURLToPath(import.meta.url) 解析项目根绝对路径读取凭证,不依赖启动时的 cwd,因此放到任意目录、任意电脑都能自定位。跨机器只需处理三件事:依赖、路径、凭证。
一键打包脚本 deploy.bat(推荐,零手敲命令)
仓库根目录已提供 deploy.bat,双击或命令行运行即可自动完成「重建 dist → 打包为 abap-adt-mcp-dist.zip」,且自动排除凭证与日志(MCP.env / .env / *.log / *.err / *.mjs),保留 node_modules/ + dist/,对方免装免构建。
deploy.bat :: 在本机项目根目录运行;产物 abap-adt-mcp-dist.zip 自动生成实现要点:用 %~dp0 自定位项目根(不硬编码路径),robocopy /XF 排除敏感文件后 Compress-Archive 压缩,兼容老版本 PowerShell(不依赖 -Exclude 参数)。对方拿到 zip 后从下方「方式 A 第 2 步」继续即可。
方式 A:零安装便携包(推荐给同事,最直接)
打包:在本机把整个项目目录压缩,排除
MCP.env和*.log(含真实密码,切勿外传)。已带的node_modules/(≈54M) 和dist/让对方免安装、免构建。# Git Bash / PowerShell zip -r abap-adt-mcp.zip abap-adt-mcp -x "abap-adt-mcp/MCP.env" -x "*.log"对方解压到任意目录,例如
D:/tools/abap-adt-mcp。填凭证:复制
.env.example为MCP.env,填入对方自己的 SAP 账号:cp .env.example MCP.env # 编辑 MCP.env,填 SAP_URL/SAP_USER/SAP_PASSWORD/SAP_CLIENT加 MCP 配置:在对方机器的
~/.workbuddy/mcp.json(或其他客户端配置)加:{ "mcpServers": { "abap-adt-mcp": { "command": "node", "args": ["D:/tools/abap-adt-mcp/dist/index.js"], "cwd": "D:/tools/abap-adt-mcp", "env": { "ABAP_MCP_READONLY": "false" } } } }command用node(要求对方node在 PATH,Node ≥ 20);若想彻底免装 node,把node.exe也放进包、command指向./node.exe。必须把路径改成对方机器上的实际位置(本项目
mcp.json里硬编码的绝对路径在别的电脑不存在)。凭证不必写进
env——服务器会自动读项目根下的MCP.env。
启用:在 WorkBuddy 连接器管理页右上角「自定义连接器」点新 server 的 Trust。
方式 B:源码分发(目标机自行安装,包体最小)
对方拿到 src/ + package.json + .env.example,然后:
cd abap-adt-mcp
npm install # 拉取依赖
npm run build # 产出 dist/
cp .env.example MCP.env # 填凭证之后同方式 A 第 4–5 步配置并 Trust。
其他 MCP 客户端
配置结构相同,只是文件位置不同:
Claude Desktop:
%APPDATA%/Claude/claude_desktop_config.jsonCursor / VS Code:对应
mcp.jsonnpx 一行版(无需本地构建,但每次拉包):
{ "mcpServers": { "abap-adt-mcp": { "command": "npx", "args": ["-y", "abap-adt-mcp"], "env": { "SAP_URL":"...", "SAP_USER":"...", "SAP_PASSWORD":"...", "SAP_CLIENT":"100" } } } }
安全提醒
永远不要分发
MCP.env:它含明文 SAP 密码。用.env.example作模板,让每台机器填自己的凭证。生产系统把
ABAP_MCP_SYSTEM_ROLE=prod(强制只读)或ABAP_MCP_READONLY=true,写工具会被隐藏且拒绝变更。
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/abap0917/abap-adt-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server