Keploy
End-to-end API testing — generate and run tests from OpenAPI, curl, Postman, or real user traffic.
KEkeploy/keploy19k36 new stars in the last 7 days
Give Claude live access to SAP ABAP via ADT: read, search, check, test, and edit objects.
MCP server giving Claude (and any MCP-compatible client) live access to SAP systems via ADT.
Read source, search the repository, run syntax checks, run unit tests, run ATC, diff the same object across landscapes, edit and activate ABAP — all from a chat window or an autonomous agent. No add-on installation on the SAP stack required.
SAP development is full of repetitive read-the-source / check-the-callers / diff-the-system work. AI assistants are great at exactly that kind of task — but only if they can reach the system. ADT (ABAP Development Tools) is the HTTP API that Eclipse uses; it ships with every modern NetWeaver and S/4 system. This server speaks ADT on behalf of the agent so the agent can do real work against your real systems, with the same auth and scoping you'd give a developer in Eclipse.
50+ high-level tools wrapped around the most common ADT endpoints, plus a generic escape hatch for anything else, plus 5 user-invokable Clean Core prompts that turn the tool surface into outcome-shaped slash commands (see Clean Core prompts below).
| Category | Tools |
|---|---|
| Connection | adt_list_systems, adt_ping, adt_system_info |
| Source CRUD | adt_get_source, adt_set_source |
| Quality | adt_syntax_check, adt_pretty_print, adt_run_unit_tests, adt_run_atc, adt_run_atc_package, adt_run_atc_transport |
| Lifecycle | adt_create_object, adt_delete_object, adt_activate, adt_lock, adt_unlock, adt_list_inactive_objects |
| Versions | adt_list_versions, adt_compare_versions |
| Discovery | adt_browse_package, adt_list_packages, adt_search_objects, adt_grep_source, adt_where_used |
| CDS | adt_cds_data_preview, adt_cds_dependencies, adt_list_released_apis |
| Cross-system | adt_compare_source, adt_transport_diff |
| Transports | adt_list_transports, adt_get_transport, adt_create_transport, adt_release_transport, adt_transport_queue |
| Runtime errors | adt_list_dumps, adt_get_dump |
| Debugger | adt_debug_set_breakpoint, adt_debug_delete_breakpoint, adt_debug_listen, adt_debug_stack, adt_debug_variables, adt_debug_step, adt_debug_goto_stack, adt_debug_set_variable, adt_debug_set_watchpoint, adt_debug_delete_watchpoint, adt_debug_stop |
| Data | adt_read_table, adt_value_help |
| Generation | adt_rap_scaffold |
| Experimental¹ | adt_get_note, adt_check_note_status, adt_implement_note, adt_list_locks, adt_schedule_job, adt_read_spool |
| Escape hatch | adt_request |
¹ Experimental tools target ADT endpoints (SNOTE, SM12 enqueues, SM36/SP01)
that classic NetWeaver does not expose; on such systems they return
available:false with a fall-back hint rather than failing. They work where the
backing service exists (typically S/4HANA).
Multi-system aware. One config, many SAP systems (DEV / QAS / PRD or
landscape-wide); switch with the system argument or compare across two with
adt_compare_source / adt_transport_diff.
Safe by default. A readOnly flag (global or per-system) blocks every
write method. Read-only POST queries (search, where-used, package tree)
remain allowed so agents can still discover.
Robust. Per-request timeout. CSRF token negotiation with auto-retry on 403. Self-signed cert opt-out. Optional debug tracing to stderr.
Structured errors. ADT's <exc:exception> envelopes are parsed into
{ type, message, namespace } so failed calls don't dump XML into the agent's
context window.
Previously published as
claude-for-abap— that package still works but is deprecated; new installs should usesap-adt-mcp.
# global
npm install -g sap-adt-mcp
# or run without installing
npx sap-adt-mcp
Requires Node.js 22.19+ (undici v8, used as the HTTP client, requires this minimum).
Create your config:
mkdir -p ~/.sap-adt-mcp
cp config.example.json ~/.sap-adt-mcp/config.json
$EDITOR ~/.sap-adt-mcp/config.json
The server searches in this order:
$SAP_ADT_MCP_CONFIG (absolute path)~/.sap-adt-mcp/config.json./config.json (cwd at server start){
"defaultSystem": "DEV",
"readOnly": false,
"systems": {
"DEV": {
"host": "https://sap-dev.example.com:44300",
"client": "100",
"language": "EN",
"user": "DEVELOPER",
"password": "env:SAP_DEV_PASSWORD",
"rejectUnauthorized": false
},
"QAS": {
"host": "https://sap-qas.example.com:44300",
"client": "200",
"user": "DEVELOPER",
"password": "env:SAP_QAS_PASSWORD"
},
"PRD": {
"host": "https://sap-prd.example.com:44300",
"client": "300",
"user": "READONLY",
"password": "env:SAP_PRD_PASSWORD",
"readOnly": true
}
}
}
| Field | Meaning |
|---|---|
host | Base URL including scheme + ICM HTTPS port (e.g. https://...:44300). |
client | SAP client (sets sap-client query param). |
language | Optional logon language (sets sap-language). |
user | RFC user. |
password | Either a literal string or env:VAR_NAME to read from environment. |
rejectUnauthorized | Set false to skip TLS validation for self-signed certs. Default true. |
readOnly | Block POST / PUT / DELETE / PATCH for this system (read-only POST queries still work). |
timeoutMs | Override default 30 s request timeout. |
readOnly: true (top-level or per-system) refuses any unsafe HTTP method.
Whitelisted read-only POST endpoints (nodestructure, search,
usagereferences, parsers, checkruns) remain available so agents can
still discover and analyze without being able to modify.
Recommended: set readOnly: true for QAS and PRD profiles. Keep DEV writable.
Many internal SAP systems use self-signed certs. "rejectUnauthorized": false
disables TLS validation for that profile only. Don't set this on PRD.
Every write the server performs against SAP (POST/PUT/DELETE/PATCH — locks, source updates, activations, transport operations) is appended to a local JSONL file, including which MCP tool triggered it and, for blocked attempts in read-only mode, the violation itself. Reads and read-only queries are not logged. Nothing leaves your machine — this is your local answer to "what exactly did the AI change?".
Default location: ~/.sap-adt-mcp/audit.log. One JSON object per line:
{"ts":"2026-06-11T12:00:00.000Z","tool":"adt_set_source","host":"https://...","sapUser":"DEVELOPER","method":"PUT","path":"/sap/bc/adt/programs/programs/ztest/source/main","status":200,"ok":true,"transport":"E4DK900123"}
Configure or disable:
{ "audit": { "enabled": false, "path": "/var/log/sap-adt-mcp/audit.log" } }
…or set SAP_ADT_MCP_AUDIT=0 (also accepts false/no/off).
Agents repeat the same discovery calls while they reason. Results of the
read-only tools adt_search_objects, adt_browse_package, adt_list_packages,
adt_where_used, adt_system_info and adt_value_help are cached in memory
for 60 seconds per system and argument set. Any write this server performs
drops the whole cache, so you never read back a stale result of your own change;
changes made elsewhere (SAP GUI, Eclipse) can be up to one TTL old. A cached
result carries _meta["sap-adt-mcp/cache"] = { hit: true, ageMs }.
{ "cache": { "ttlMs": 120000 } }
"ttlMs": 0 (or SAP_ADT_MCP_CACHE_TTL_MS=0) turns it off.
The server sends small, redacted reports to the maintainer so defects get found and fixed. This is on by default and the server prints a notice saying so on startup. There are three channels:
adt_report_issue tool.What is sent: the sap-adt-mcp version, Node version, OS, the tool name, and the
error/finding with a fingerprint for de-duplication, plus an anonymous install
id (random bytes, cached at ~/.sap-adt-mcp/install-id) that lets repeat
reports from the same install be grouped for triage — it identifies neither you
nor your system. Before anything leaves your machine it is scrubbed of
hostnames, users, passwords, tokens, IPs, and emails; tool arguments and
free-text fields are redacted the same way. Reports
go to a relay the maintainer owns, which files/de-dups a GitHub issue — the
relay holds the GitHub credentials, never this package.
Turn it all off:
{ "reporting": { "enabled": false } }
…or set SAP_ADT_MCP_REPORT=0 (also accepts false/no/off). Finer control:
| Key | Default | Effect |
|---|---|---|
reporting.enabled | true | Master switch for all three channels. |
reporting.adtErrors | true | Channel 2 (auto-report flagged ADT errors). |
reporting.allowManual | true | Channel 3 (the adt_report_issue tool). |
reporting.includeArgs | true | Include redacted tool args / repro args. Note: object names can appear here. |
reporting.endpoint | relay URL | Point at your own relay (see worker/). |
claude mcp add sap-adt -- npx sap-adt-mcp
Pass secrets through the registration:
claude mcp add sap-adt \
--env SAP_DEV_PASSWORD=... \
--env SAP_PRD_PASSWORD=... \
-- npx sap-adt-mcp
Edit claude_desktop_config.json (Settings → Developer → Edit Config):
{
"mcpServers": {
"sap-adt": {
"command": "npx",
"args": ["-y", "sap-adt-mcp"],
"env": {
"SAP_DEV_PASSWORD": "..."
}
}
}
}
Quit and restart Claude Desktop fully (system tray → Quit) for the change to apply.
npx sap-adt-mcp --validate-config
Loads the config and pings every system; exits non-zero if any are unreachable or rejecting credentials. Run this first when troubleshooting.
| Tool | Purpose | Notes |
|---|---|---|
adt_get_source | Fetch ABAP source by object name + type. | Returns plain text. For classes, pick the include via include: main (default), definitions, implementations, macros, testclasses. Function modules require group. For large objects, pass outputFile to write the source straight to disk (response omits inline source). |
adt_set_source | Replace source. Orchestrates lock → PUT → unlock. | Supply the new source inline via source, or via sourceFile (a local path the MCP reads itself) for large objects that exceed the per-call I/O cap. Optional transport assigns the change to a TR (corrNr); optional lockHandle reuses an externally-acquired lock. Refused under readOnly: true. |
adt_create_object | Create a new ABAP object in a package. | Supported types: program, class, interface, include, functiongroup, function, cds, accesscontrol, metadataext, behaviordef, messageclass. After creation, set the source body with adt_set_source and activate. Refused under readOnly: true. |
adt_delete_object | Delete an object. | Acquires lock and DELETEs. Refused under readOnly: true. |
adt_activate | Activate one or more objects. | Pass objects: [{ name, type, group? }]. |
adt_pretty_print | Run the SAP-side ABAP formatter. | Stateless — pass source, get formatted source back. |
adt_lock / adt_unlock | Acquire / release a lock for multi-step edits. | For one-shot edits, prefer adt_set_source (manages the lock for you). Use these when you need to keep an object locked across multiple writes within a single agent turn. |
| Tool | Purpose | Notes |
|---|---|---|
adt_syntax_check | ADT syntax check on an object. | Returns <chkrun:reports> XML; the agent reads severity + line numbers. |
adt_run_unit_tests | ABAP Unit run. | Pass test container objects (typically classes). |
adt_run_atc | ABAP Test Cockpit run. | API surface varies across NW releases — see Caveats. |
| Tool | Purpose | Notes |
|---|---|---|
adt_browse_package | One level of package contents. | Returns counts by type. Past 500 objects only the first 500 entries come back (truncated: true); full: true returns all. |
adt_list_packages | Recursive walk from a root. | Has prefix (only descend into matching subpackages) and maxPackages safety cap (default 200). Always returns totals by type; when the tree holds more than 500 objects the per-package entries are left out (counts stay) unless full: true. |
adt_search_objects | Quick-search by name pattern. | * wildcard. Returns parsed { name, type, description, packageName, uri } records. |
adt_where_used | Where-used list. | Same parsed record shape. Capped at maxResults (default 200); the response carries the backend's own numberOfResults plus truncated when the list was cut. |
| Tool | Purpose | Notes |
|---|---|---|
adt_compare_source | Diff one object between two systems. | Returns unified diff + { added, removed } stats. |
adt_transport_diff | Diff every object in a TR between two systems. | Caps at maxObjects (default 50). |
| Tool | Purpose | Notes |
|---|---|---|
adt_list_dumps | List ST22 short dumps. | Optional filters: user, host, from/to (YYYYMMDD), maxResults (default 20). Atom feed is parsed into structured entries with runtimeError, program, user, updated, and release-specific rba:*/dump:* fields surfaced as a map. Trims client-side because some releases ignore the server-side cap. |
adt_get_dump | Fetch a single dump by id. | Two-step fetch: metadata XML (runtime error, program, links) followed by the formatted dump text from the dump:link relation="contents" sub-resource. Returns a chapters map (shortText, whatHappened, errorAnalysis, howToCorrect, whereTerminated, sourceCodeExtract, …). Pass chapters: [...] to limit, full: true to include the raw text. |
External ABAP debugger over ADT's /sap/bc/adt/debugger/* API. Set a breakpoint,
wait for a session to hit it, then inspect the stack/variables, step through, and
(guarded) change values. Requires debug authorization on the backend; minimum
NW 7.31 SP04 + Kernel 7.21 (fine on S/4).
| Tool | Purpose | Notes |
|---|---|---|
adt_debug_set_breakpoint | Set an external breakpoint. | Give uri, or object+type(+include)+line. Optional condition. Returns the breakpoint id. |
adt_debug_delete_breakpoint | Remove a breakpoint by id. | |
adt_debug_listen | Bounded wait for a debuggee to hit a breakpoint. | Returns { caught: true, debuggee, … } and auto-attaches, or { caught: false } on timeout (default 30 s, capped 55 s) — just call again. One listener per process. |
adt_debug_stack | Call stack of the attached debuggee. | |
adt_debug_variables | Read variable values. | names: ['sy-subrc','lv_total']; omit for the scope roots. |
adt_debug_step | Advance execution. WRITE. | kind: into / over / return / continue / runToLine / jumpToLine (need uri) / terminate. A continue that lets the run finish answers status: "debuggeeEnded" — that is success. |
adt_debug_goto_stack | Move the active stack frame. WRITE. | stackUri (from the stack) or 0-based position. |
adt_debug_set_variable | Set a variable's value. WRITE. | name + value. Changes live session state. |
adt_debug_set_watchpoint / adt_debug_delete_watchpoint | Break when a variable changes. WRITE. | Best-effort — the watchpoint contract has no reference impl; check raw on a live run. |
adt_debug_stop | End the session: resume the debuggee, then delete the listener + all breakpoints it set. | Call when done so nothing dangles and no request stays suspended. release: false skips the resume. |
Typical flow:
1. adt_debug_set_breakpoint { object: "ZREPORT", type: "program", line: 42 } → id
2. adt_debug_listen {} → ARM IT FIRST, then trigger the run
3. (trigger: a Fiori/OData call, an ADT classrun, an RFC, a job)
4. listen returns caught:true → already attached (or caught:false → call again)
5. adt_debug_stack {} → where execution paused
6. adt_debug_variables { names: ["sy-subrc", "lv_total"] }
7. adt_debug_step { kind: "over" } → advance; or set_variable / continue
8. adt_debug_stop {} → resume the debuggee + cleanup
What an external breakpoint traps: HTTP/ICF (Fiori, OData, ADT), RFC and
background sessions — not your own SAP GUI dialog session. Running the report
from SE38 with F8 traps nothing and opens no debugger, which reads like a broken
feature but isn't. To debug dialog-only code, run it inside an ICF session with a
throwaway IF_OO_ADT_CLASSRUN wrapper and trigger
POST /sap/bc/adt/oo/classrun/<class>:
METHOD if_oo_adt_classrun~main.
DATA lt_list TYPE TABLE OF abaplist.
" There is no screen in an ICF session, so list output must go to memory.
SUBMIT zoy_dbg_target EXPORTING LIST TO MEMORY AND RETURN.
ENDMETHOD.
SUBMIT opens a fresh program context, so you debug the target report on its own.
Timing: arm adt_debug_listen before triggering the run — for a fast
request (Fiori/OData) arming it after clicking is already too late. A trapped
debuggee then waits only ~15–20 s for the attach before resuming on its own, so
listen attaches immediately with no round trip in between. A caught: false
can therefore mean three things: the run hasn't happened yet, the listener was
armed too late, or that line never executes in this flow — keep a known-good
control breakpoint to tell a wrong breakpoint apart from a setup problem.
Read-only mode: inspection (breakpoints, listen, stack, variables) is allowed;
the WRITE tools above (step, goto-stack, set-variable, watchpoints) are refused
under readOnly: true. Debugging another user's session (requestUser) is off
by default; enable it per system with "debug": { "allowRequestUser": true }
(needs backend debug authorization).
| Tool | Purpose | Notes |
|---|---|---|
adt_read_table | Run an OpenSQL SELECT via the ADT Data Preview API. | SE16-style table reads. SELECT-only — INSERT/UPDATE/DELETE rejected client-side; the SAP endpoint enforces server-side too. maxRows capped at 5000 (default 100). Requires NetWeaver 7.55+ / S/4HANA. |
adt_system_info | Which system is this? | Product (S/4HANA version, ECC or plain NetWeaver), SAP_BASIS release + SP level, and whether ABAP Cloud is available (SAP_BASIS ≥ 7.57), read from table CVERS. includeComponents: true lists every installed component. Same Data Preview baseline as adt_read_table. |
adt_value_help | F4-style value help for a domain, data element or table + field. | Domain fixed values with texts (DD07L/DD07T), else the check / value table joined with its text table in the requested language (language: ISO EN/TR or SAP key; defaults to the profile language). includeCheckTable reads the check table even when fixed values exist. Search helps are not evaluated. Same Data Preview baseline as adt_read_table. |
| Tool | Purpose | Notes |
|---|---|---|
adt_list_transports | List TRs by user / status. | Default user = config user; default status = modifiable. |
adt_get_transport | TR header + objects. | |
adt_create_transport | Create a new TR. | Refused under readOnly: true. Endpoint shape varies — see Caveats. |
adt_release_transport | Release a TR. | Refused under readOnly: true. |
adt_transport_queue | Where is a TR right now? | Reads E070 (status, owner, target) and TPALOG (tp steps + return codes) on every system in systems (e.g. ["DEV","QAS","PRD"]) and reports per target: exported, in-import-queue, imported, imported-with-errors, import-aborted. A task resolves to its request. One unreachable system is reported, not fatal. The TMS buffer file is not reachable over ADT, so in-import-queue comes from the logged forward step. |
adt_request — direct ADT REST call. Use this when a niche endpoint isn't
covered by a high-level tool. Handles auth / CSRF / cookies / sap-client
automatically.
Friendly aliases (any of either column work):
| Alias | TADIR code |
|---|---|
| program / report | PROG |
| include | INCL |
| class | CLAS |
| interface | INTF |
| function / fm | FUGR/FF (requires group) |
| functiongroup | FUGR |
| table / structure | TABL |
| dataelement | DTEL |
| domain | DOMA |
| cds / ddls | DDLS |
| accesscontrol / dcls | DCLS |
| metadataext / ddlx | DDLX |
| behaviordef / bdef | BDEF |
| messageclass / msag | MSAG |
The raw tools are building blocks; skills/ ships ready-made
workflows for Claude Code that orchestrate them. Each SKILL.md lists its own
prerequisites (minimum NetWeaver release, required authorizations, read-only
compatibility).
| Skill | What it does | Read-only OK? | Min. system |
|---|---|---|---|
transport-release-gate | Pre-release quality gate over a TR: inactive objects, locks, syntax, ATC, unit tests → go/no-go report. Release stays a human decision. | Mostly (unit tests + release need write) | NW 7.50+, ATC configured |
dump-triage | ST22 triage: group dumps into families, deep-read top offenders, root cause + fix per family. | Yes — safe on PRD | NW 7.50+ (dumps feed) |
legacy-code-doc | Reverse-document legacy Z code: structure, DB touchpoints, callers, risks, S/4 migration notes. | Yes — safe on PRD | NW 7.4x+ (data samples 7.55+) |
abap-clean-core | SAP Clean Core framework knowledge: levels, decision framework, governance. | Yes (knowledge-only) | none |
To use one, copy its folder into your project's .claude/skills/ (or
~/.claude/skills/ for all projects):
cp -r node_modules/sap-adt-mcp/skills/dump-triage .claude/skills/
# or from a clone: cp -r sap-adt-mcp/skills/dump-triage .claude/skills/
Claude Code picks them up automatically; they trigger when the conversation matches (e.g. "is E4DK900123 safe to release?" → transport-release-gate).
The server ships an opt-in Clean Core layer for SAP S/4HANA work. There are two pieces, and they are deliberately separate:
src/prompts.js) — the operational surface. The
user invokes them as slash commands. Each one pairs a slice of the
Clean Core framework with the relevant adt_* tools so the model can
act on a real system, not just lecture about levels.skills/abap-clean-core/)
— the framework's full text: Stay Clean / Get Clean playbook, A/B/C/D
level deep-dive, Cloudification Repository state semantics, ABAP Cloud
allowed/forbidden lists, the SAP Application Extension Methodology
(3 phases), governance practices, KPI calculations, ATC exemption
process. Read once, link to it from PRs, hand to a new team member.
The prompts above quote what they need; the reference is everything
else.In Claude Code (assuming you registered the server as sap-adt), the
exact commands are:
| Command | Arguments | What it does |
|---|---|---|
/mcp__sap-adt__clean_core_grade | object (req), type (req), system | Grade one object A/B/C/D. Pulls source + ATC, classifies, cites reasons, sketches the Level A refactor if Level C/D. |
/mcp__sap-adt__clean_core_review | package (req), system, maxObjects (default 50) | Walk a package and compute Clean Core Share %, Tech Debt Score, top Level D offenders. |
/mcp__sap-adt__clean_core_refactor | object, type, system (all optional) | Enter refactor mode. Loads BAPI-wrapper / MARA→released-CDS / modification→BAdI patterns. With object it pre-seeds; without, waits for direction. |
/mcp__sap-adt__clean_core_create | requirement, package, system (all optional) | Enter creation mode at Level A by default — ABAP Cloud syntax, released CDS views, RAP, business object interfaces. Drives the create_object → set_source → syntax_check → activate pipeline. |
/mcp__sap-adt__clean_core_design | use_case (optional) | Architecture mode — fit-to-standard, 3-phase methodology, on-stack vs side-by-side, hybrid. No code writes. Produces a target-solution memo. |
The slash-command name structure is determined by the MCP client: the
mcp__<server-alias>__ prefix is added automatically based on the alias
you used when registering the server. If you registered the server with
a different alias (e.g. claude mcp add cc -- npx sap-adt-mcp), the
prefix changes accordingly (/mcp__cc__clean_core_grade).
In Claude Desktop, prompts appear in the slash-command picker — same naming.
Atomic prompts (grade, review) take all their arguments inline and
return a structured analysis:
You: /mcp__sap-adt__clean_core_grade object:ZCL_PRICING type:class system:DEV
Agent: → adt_get_source { ... }
→ adt_run_atc { ... }
Verdict: Level C. Two SELECTs from MARA without using the released
I_Product view; one CALL FUNCTION to internal FM RV_PRICE_PRINT.
Refactor sketch: replace SELECT with `from I_Product`; encapsulate
the RV_PRICE_PRINT call in a Z-class so the dependency is localised.
Mode-loading prompts (refactor, create, design) optionally take a
seed; without one, they wait for the user's natural-language follow-up:
You: /mcp__sap-adt__clean_core_create
Agent: I'm in Clean Core CREATE mode (Level A by default). What do you
want to build, on which package and system?
You: A small Fiori list-report of overdue invoices, package ZFIN_REPORTS,
system DEV.
Agent: Plan: a CDS view projecting I_OperationalAcctgDocItemCube for items
with NetDueDate < today; a behavior definition; a service binding
exposing it to Fiori Elements list-report. Three objects. Confirm?
Or with a seed argument so the request is one-shot:
You: /mcp__sap-adt__clean_core_create requirement:"Fiori list-report of
overdue invoices" package:ZFIN_REPORTS system:DEV
skills/abap-clean-core/ is the canonical
source for everything the prompts quote and more. If you're setting up
Clean Core governance for a real program — KPI baselines, ATC exemption
discipline, maturity assessment, on-stack vs side-by-side trade-offs at
the architecture level — that's where the depth lives.
The directory is structured as one entry point (SKILL.md) plus four
deep-dive files in references/:
references/levels-detailed.md — Cloudification Repository state
values, released local vs released remote APIs, reclassification
dynamics, per-anti-pattern remediationreferences/decision-framework.md — fit-to-standard, the SAP
Application Extension Methodology in detail, on-stack vs side-by-side
triggers, hybrid patterns, worked scenariosreferences/governance.md — Stay Clean / Get Clean playbook, the four
KPIs and how to compute them, ATC exemption process, maturity
assessment, multi-year roadmapreferences/abap-cloud-rules.md — full allowed/forbidden lists, RAP /
CDS / business object interfaces / Custom Fields, prebuilt services,
classic-to-cloud migration patternsYou can install the reference as an actual auto-loading Claude skill by
copying or symlinking skills/abap-clean-core/ into your
~/.claude/skills/ — but that's an explicit choice. The default
behavior of this repo is opt-in, prompt-only.
See examples/ for end-to-end agent workflows: project discovery,
class audit, cross-system release verification, where-used-driven refactor,
test triage.
Quick taste:
You: "Compare class ZCL_PRICING between DEV and PRD on the live systems."
Agent: → adt_compare_source { systemA: "DEV", systemB: "PRD",
object: "ZCL_PRICING", type: "class" }
Returns: { identical: false, stats: { added: 14, removed: 9 },
diff: "..." }
Then narrates the meaningful changes.
MCP client (Claude Desktop / Claude Code / custom)
│ stdio (JSON-RPC)
▼
┌──────────────────────────────────┐
│ src/server.js │ CLI + MCP dispatch (thin)
│ ├─ src/tools/*.js │ one module per category:
│ │ │ connection, source, quality,
│ │ │ lifecycle, discovery,
│ │ │ cross-system, transports,
│ │ │ runtime, data, request
│ ├─ src/object-uris.js │ type alias → ADT URI map
│ ├─ src/node-structure.js │ package tree XML parser
│ ├─ src/object-references.js │ <objectReference> parser
│ ├─ src/dump-feed.js │ runtime-dumps Atom parser
│ ├─ src/data-preview.js │ Data Preview XML parser + SELECT guard
│ ├─ src/diff.js │ unified diff (LCS)
│ ├─ src/adt-error.js │ <exc:exception> parser
│ ├─ src/lock.js │ ADT lock acquire / release
│ └─ src/adt-client.js │ HTTP client: auth / CSRF / cookies / timeout
└──────────────────────────────────┘
│ HTTPS
▼
SAP system (ADT REST: /sap/bc/adt/...)
Two runtime dependencies: @modelcontextprotocol/sdk (the MCP wire protocol)
and undici (HTTP with custom TLS dispatcher). Everything else is stdlib.
For most edits, adt_set_source is enough — it acquires the lock, writes,
and releases. For workflows that touch the same object multiple times within
a single turn (e.g. apply N method-level patches, then activate), use the
sticky-lock pattern:
1. adt_lock { object: "ZCL_X", type: "class" } → returns lockHandle
2. adt_set_source { object: "ZCL_X", type: "class", (repeat as needed)
source: "...", lockHandle: "<handle>" }
3. adt_activate { objects: [{ name: "ZCL_X", type: "class" }] }
4. adt_unlock { object: "ZCL_X", type: "class",
lockHandle: "<handle>" }
The lockHandle parameter on adt_set_source skips internal lock/unlock
when present.
A multi-thousand-line class or program can exceed the per-call I/O cap, so its source cannot be passed inline. Keep the content on disk instead — it never enters the agent context:
1. adt_get_source { object: "ZCL_BIG", type: "class",
outputFile: "/tmp/zcl_big.abap" } → writes the file, no inline source
2. (edit /tmp/zcl_big.abap locally)
3. adt_set_source { object: "ZCL_BIG", type: "class",
sourceFile: "/tmp/zcl_big.abap",
transport: "E4DK900123" } → MCP reads the file and PUTs it
Note: assigning to a transport works headless, but TR creation
(adt_create_transport) routes through a GUI dialog on some systems and can
fail with a 500 — pass an existing TR id instead.
adt_request with the right path / content type for
your release.adtcore:masterLanguage, etc.) — open an issue if your system rejects
the create payload, and include the response body.adt_create_object — these need a richer DDIC-specific payload that we
haven't generalised. Use adt_request for now."failed" in Claude Desktop's MCP server list. Run sap-adt-mcp --validate-config from a terminal. If that prints OK, the server is fine and
the issue is in your claude_desktop_config.json (wrong path or env).
403 with x-csrf-token: required. Should self-heal — the client refetches
the token and retries. If it persists, you likely have an SSO / front-end
auth in front of ADT that breaks Basic auth; check your ICM and SAP web
dispatcher rules.
Read-only mode refuses an obviously-read endpoint. It's probably a POST
endpoint not in the whitelist. Open a PR or issue with the path; we'll add
it. Or temporarily flip the system to readOnly: false.
SAP_ADT_MCP_DEBUG=1 traces every request and response (status, latency,
URL, request headers minus Authorization) to stderr. The MCP client shows
stderr in its server log, so check there.
See CONTRIBUTING.md — bug reports, new tool coverage, NetWeaver compatibility notes, docs, examples all welcome.
MIT — see LICENSE.
End-to-end API testing — generate and run tests from OpenAPI, curl, Postman, or real user traffic.
KEkeploy/keploy19k36 new stars in the last 7 days
MCP server for iOS and Android Mobile Development, Automation and Testing
MOmobile-next/mobile-mcp9k329 new stars in the last 7 days
MCP server for mobile app automation: verify, control, and debug iOS, Android, TV, and desktop apps
CAcallstack/agent-device5k84 new stars in the last 7 days
Open-source MCP server for LinkedIn. Give Claude and any MCP-compatible AI agent access to profiles, companies, jobs, and messages.
STstickerdaniel/linkedin-mcp-server3.8k75 new stars in the last 7 days
The ripgrep of AI context: a zero-dependency C++23 CLI + MCP server for coding agents. Find what you want without reading the repo, then check you built what you meant — blast radius, tests-to-run, quality deltas. Signatures at 74.7% fewer bytes than bodies; every guess labelled, every loss published. Paddle out with a map.
REredhat-et/ripwire2.4k33 new stars in the last 7 days
An MCP client for Neovim that seamlessly integrates MCP servers into your editing workflow with an intuitive interface for managing, testing, and using MCP servers with your favorite chat plugins.
RAravitemer/mcphub.nvim1.8k2 new stars in the last 7 days