Setup in three steps.
You need Node.js 22.12 or newer, access to the SAP system (on S/4HANA Cloud the developer business role your user already has for Eclipse ADT; on-prem the /sap/bc/adt service active in SICF), and a Chromium browser for browser SSO. The full version, with Windows paths and the host logs, is in the README.
Describe your SAP systems
One file, ~/.abap-adt-mcp/systems.json, one entry per system. The key is the name you will use in chats. This complete S/4HANA Cloud entry with browser SSO starts read-only; drop the policy line when you are ready to write, and the model can then create, edit and activate within your SAP authorizations.
{
"DEV": {
"url": "https://myXXXXXX.s4hana.cloud.sap",
"client": "080",
"authType": "sso",
"default": true,
"policy": { "readOnly": true }
}
}Register the server in your host
Claude Code is one line. Claude Desktop takes the JSON under Settings, Developer, Edit Config, then a restart. The same map works in Cursor and Cline; VS Code names it servers.
claude mcp add abap-adt-mcp \
-e SAP_SYSTEMS_FILE=$HOME/.abap-adt-mcp/systems.json \
-- npx -y abap-adt-mcp{
"mcpServers": {
"abap-adt-mcp": {
"command": "npx",
"args": ["-y", "abap-adt-mcp"],
"env": {
"SAP_SYSTEMS_FILE": "/Users/me/.abap-adt-mcp/systems.json",
"MCP_TOOLSETS": "focused"
}
}
}
}Say hello
Open a new chat. The model calls listSystems, login (a browser window appears once for SSO), searchObject and getObjectSource. When the source comes back, you are done.
List my SAP systems, log in to DEV and show me the source of class CL_ABAP_CHAR_UTILITIES.
If nothing appears in the host, read its MCP log: spawn npx ENOENT means Node.js is missing; no browser window means no Chromium found (SAP_BROWSER_PATH names one); on-prem, /sap/bc/adt must be active in SICF. The troubleshooting list has the rest.
What to ask the model.
The server is a toolbox the model picks from: ask in plain language and it chooses the sequence. Write tools lock and unlock by themselves, activate=true activates in the same call, and every error is JSON with a kind, a hint and the next tools to try.
| Ask | Tools the model reaches for |
|---|---|
| "Explain what method GET_DATA of ZCL_ORDER_SERVICE does." | searchObject, getMethodSource |
| "Where is table ZTABLE still used, and by which programs?" | whereUsed, sourceTextSearch, grepPackage |
| "Add a null check at the top of GET_DATA, activate and run the unit tests." | resolveTransport, syntaxCheckCode, editObjectSource, unitTestRun, objectDiff |
| "Create class ZCL_HELLO in package ZDEMO that prints Hello World, with a unit test." | validateNewObject, resolveTransport, createObject, setObjectSource, createTestInclude, unitTestRun |
| "Run ATC on package ZFIN and apply every quickfix that is safe." | createAtcRun, atcWorklists, atcQuickfixProposals, atcApplyQuickfix, atcSummary |
| "What changed in transport DEVK900123? Is it safe to release?" | transportDetails, transportUnifiedDiff |
| "Why did the last short dump of user DEVELOPER happen? Propose a fix." | dumps, dumpDetails, getObjectSource |
| "Is ZCL_ORDER_SERVICE ready for ABAP Cloud? Which SAP objects block it?" | apiReleaseState, createAtcRun |
| "Select the ten newest rows of ZTABLE where STATUS = 'X'." | runQuery (once the destination allows data) |
Six ready-made workflows also travel as MCP prompts: create-object, safe-edit, review-transport, fix-atc, clean-core-check, debug-dump. Each names the tools in order and says where it stops and asks.
Guard rails live in the server, not in the host.
A destination's policy block is evaluated in the server before the tool's own SAP call, whatever the host approves. Refusals come back as kind: "policyDenied" naming the gate. A destination without a policy is fully writable within your SAP authorizations and reads no table data until you allow it.
Also: secrets stay in ${env:VAR}, TLS stays on per destination, every call lands in an audit log with tool, destination, outcome and gate, and error messages pass through redaction. Content from SAP is untrusted input; use a host that asks before destructive calls.
| Policy key | Effect |
|---|---|
| readOnly | Only read-only tools run. Every source write, runSnippet, unitTestRun and ATC runs are refused. |
| allowedPackages | Writes only inside these package globs (["Z*", "$*"]); reads are never gated. |
| deniedTables | Globs refused in tableContents, in every FROM/JOIN of runQuery, and scanned in written ABAP. |
| allowDataPreview | Off unless stated. Opens table rows by name. |
| allowFreeSql | Off unless stated. Opens runQuery; implies data preview. |
| deniedTools | Names, globs or toolset:git refused on this destination; the tools stay listed. |
| allowedTransports | Every transport argument must match; creating transports is refused. |
Watch it work on the jobs you actually have.*
A short dump at three in the morning, twenty-seven ATC findings on a Friday, a transport nobody wants to sign off, a class that still needs its test, code that has to survive S/4HANA Cloud. Pick the one that looks like your week.
dumps, dumpDetails, the line, the fix, activated and tested.apiReleaseState grades every SAP object, names the successor, then the rewrite.173 tools, 16 toolsets.
Tool schemas cost context. MCP_TOOLSETS=focused publishes the 114 everyday development tools; all adds the debugger, traces, abapGit, RAP, services, refactoring and discovery. The per-tool reference with parameters and read-only/destructive annotations is docs/TOOLS.md.
- core6 · destinations, health, session
- source16 · read, write, lock, diff
- objects27 · search, navigate, create, activate
- transports18 · transports
- analysis16 · syntax, completion, apiReleaseState, runSnippet
- tests4 · ABAP Unit
- atc14 · runs, quickfixes, exemptions
- data10 · DDIC, tableContents, runQuery
- runtime3 · feeds, dumps
- discovery7 · ADT discovery, feature details
- refactoring8 · rename, extract method, change package
- rap8 · RAP generation
- services4 · business services
- git10 · abapGit
- debugger13 · breakpoints, stack, variables
- traces9 · SQL and runtime traces
● in the focused preset (114 tools). The other 59 come with MCP_TOOLSETS=all.
This server
- Many destinations from one process, stdio or HTTP
- Policies enforced server-side, audit log, redaction
- Reads and searches source, writes source, locks, dumps, data, where-used, debugger, abapGit
- Compositions such as
resolveTransport,editObjectSource,grepPackage,apiReleaseState,runSnippet,objectDiff
SAP's official ADT MCP Server
- Ships with ADT for VS Code and Eclipse under the key
abap-adt - Creates, activates, tests, checks and transports
- Does not read or search source, write source, lock, or show dumps
- Both can be registered side by side: keys and tool names do not collide. docs/ROUTING.md maps the names.
The ADT REST services are the ones Eclipse uses and are not published on the SAP Business Accelerator Hub; SAP's API Policy calls them internal. Whether SAP accepts your use is a question for your SAP contact. docs/API-POLICY.md has the policy section by section and a conservative configuration.
Other ways to install.
Claude Code plugin
The repository is its own plugin marketplace. Two commands register the server and load both skills, pinned to the release they ship with.
/plugin marketplace add williansaez/abap-adt-mcp
/plugin install abap-adt-mcp@abap-adt-mcpContainer
Built from node:22-alpine, runs as the unprivileged node user, published to GHCR on every release. Browser SSO needs a local browser; basic and oauth destinations work inside.
docker run -i --rm \
-v "$PWD/systems.json:/config/systems.json:ro" \
-e SAP_SYSTEMS_FILE=/config/systems.json \
ghcr.io/williansaez/abap-adt-mcp:latestPinned version
npx -y abap-adt-mcp fetches the newest release at every start. For a controlled rollout pin it and verify the provenance attestation trusted publishing attaches.
npx -y abap-adt-mcp@2.7.0
npm audit signaturesFrom source
A systems.json next to the checkout is picked up automatically. Point the host at dist/index.js.
git clone https://github.com/williansaez/abap-adt-mcp.git
cd abap-adt-mcp && npm ci && npm run buildAuthentication modes: sso (S/4HANA Cloud named users, a browser window once), sso2 (headless on-prem through a trusted local ticket provider), basic (on-prem users and Communication Users), oauth (unattended clients). Details in docs/AUTH.md.
One prompt away from your first activation.
Node.js, a systems.json, one line in your host. The first chat can read a class; the guard rails decide what it may write.