abapsmith
An MCP server that lets an LLM develop in SAP ABAP on a live system over ADT (/sap/bc/adt/*).
Capabilities
| Area | What the server does |
|---|
| Read | Source, outline, single method, line windows, raw properties, version history, diff. DDIC rendered as pseudo-DDL. Every response carries an etag. |
| Search | Object-name patterns and where-used. |
| Classes & interfaces | Create, read, update, delete, activate. |
| Programs & function groups | Programs, function groups, function modules: create, read, update, delete, activate. Includes and transformations: read. |
| DDIC | Domains, data elements, structures, table types, tables: create, read, update, delete, activate. Message classes: create, read, update, delete. Lock objects: read, update, activate. |
| CDS | DDL sources and metadata extensions: create, read, update, delete, activate. |
| RAP & services | Behavior definitions, behavior pool classes, service definitions, service bindings: create, read, update, activate. OData contract read (V2 and V4), metadata only. |
| BOPF | Business objects, nodes, associations, actions, determinations, validations, queries: create, read, delete. Dangling-reference check. End-to-end run through a generated bridge. |
| Enhancements | Enhancement spots, BAdI definitions and implementations, filters, source-code plug-ins. |
| Debugger | Arm breakpoints, trigger a run, step, read the call stack, inspect any variable in scope down to one field or table row. |
| ABAP Unit | Run existing tests. Four distinct outcomes — "nothing ran" is never reported as a pass. |
| ATC | Run ABAP Test Cockpit static analysis, return the findings. No IDE needed. |
| Quick fixes | List and apply ADT position-driven quick fixes as a gated, journalled write. Deterministic proposals only. |
| Transports | List, show, check, users, create, add user, set owner, delete. Release is separately gated and dry-run unless confirmed. |
| Run | Classes via IF_OO_ADT_CLASSRUN, and classic reports through a generated bridge, with list output and selection-screen parameters captured. |
| Activate | Check-only or activate, single object or batched. |
| Dumps | Read ST22 runtime errors. Variable contents are opt-in. |
| Data preview | Rows from one DDIC table or view. Opt-in, denylisted, refused on a productive system. |
| Classic dynpro | Read a screen's fields, flow logic and GUI status; drive a transaction by batch input (opt-in, admin only). |
| Undo | Local write journal: list, show, and undo a mutation, restoring the exact prior source. Drift is detected and refused. |
Per-object-type detail, and the evidence behind every claim above:
doc/CAPABILITIES/README.md.
Every response is capped and truncation is line-wise, marked, and names the call that fetches
the rest.
Requirements
- Node >= 20
- An ABAP system with ADT enabled (
/sap/bc/adt/* reachable over HTTP)
- A user with
S_DEVELOP. A dedicated technical user is recommended.
Install
Claude Code
This repository is a plugin marketplace, so there is nothing to clone and nothing to build:
/plugin marketplace add Freight-Art/abapsmith
/plugin install abapsmith@abapsmith
That installs the MCP server together with the task-shaped skills in skills/, which carry the
wire lore an agent needs before it calls a tool. The server runs from bundle/ — a committed,
dependency-free build, because plugin installation performs no build step.
To stay on a particular release, or to step back to one after an update, add the marketplace at
its tag instead of at main; every release is a vX.Y.Z tag with a CHANGELOG section of the same
name:
/plugin marketplace add Freight-Art/abapsmith#v0.3.1
/plugin install abapsmith@abapsmith
/plugin update follows whatever the marketplace points at, so a marketplace added at a tag stays
on that tag until you add it again at another one.
The plugin deliberately declares no env block, so configure the connection the way the next
section describes: a .env in the directory you start Claude Code from, or exported shell
variables. Both reach the server. Wire it into an MCP
client is then only for other clients.
Any other MCP client
Not published to a registry — build from a clone.
git clone https://github.com/Freight-Art/abapsmith.git
cd abapsmith
npm install
npm run build
npm run build emits dist/index.js, which is the server entry point.
Configure
Five variables connect to a system. Put them in a .env in the directory the server runs from
— it is loaded automatically — or in your MCP client's env block. Copy .env.example for the
annotated version.
ABAP_URL=https://abap.example.com:44300
ABAP_USER=DEVELOPER
ABAP_PASSWORD=your-password
ABAP_CLIENT=001
ABAP_SID=A4H
ABAP_MODE=read # read (default) | edit | admin
ABAP_PASSWORD is one of five mutually exclusive credential methods — the others are a session
cookie, an X.509 client certificate, a static bearer token, and OAuth 2.0 client credentials; see
doc/CONFIGURATION/connection.md for all five.
ABAP_MODE is the single permission knob. read is an absolute ceiling that no other variable
lifts. edit allows write, activate and run. admin adds transport release, transport and
cascade delete, and SAP-original enhancement targets. Three capabilities sit outside the ladder
and stay off in every mode, admin included, until named explicitly:
ABAP_ALLOW_DATA_PREVIEW, ABAP_ALLOW_DUMP_VARIABLES, ABAP_ALLOW_UI_PRESS.
The server speaks stdio by default — that's what the plugin install above and the mcpServers
block below both use. ABAP_MCP_TRANSPORT=http runs the same binary as a Streamable HTTP service
instead (ABAP_MCP_HTTP_HOST/_PORT/_PATH), so it can run next to the SAP system and serve
several MCP sessions over the network rather than one process per local conversation. A
non-loopback bind with no ABAP_MCP_HTTP_TOKEN set is refused at startup. See
doc/CONFIGURATION/transport.md for the variables and
doc/SAFETY/remote-transport.md for what the bearer token does
and does not guarantee once this is reachable over a network.
Every other variable — allowlists, pool sizing, journal retention, timeouts, debugger identity —
is in doc/CONFIGURATION/README.md.
Concurrent calls and ABAP_SESSION_WAIT_MS. Calls to one server share a small pool of ABAP
sessions (ABAP_MAX_SESSIONS, default 5 = ABAP_READ_CONCURRENCY 2 + ABAP_WRITE_CONCURRENCY 2
- 1 reserved for the debugger). A call that finds every slot of its lane busy queues, up to
ABAP_SESSION_WAIT_MS (default 10000) of queueing headroom plus the longest request timeout
(ABAP_TIMEOUT_MS, ABAP_RUN_TIMEOUT_MS, ABAP_ACTIVATE_TIMEOUT_MS, ...), so a call queued behind
one long abap_ui press, run or activation is not refused before that holder can finish. If it
still times out, the result is SESSION_BUSY with retryable: true and details naming the
holder, how long it has held the slot, its expected remaining time and a suggested retryAfterMs;
nothing was sent to SAP, so retrying unchanged is safe. abap_ui press already runs on the write
lane, so read-only calls (abap_read, abap_data_preview) are not queued behind it. More lane
slots (ABAP_READ_CONCURRENCY, ABAP_WRITE_CONCURRENCY, within ABAP_MAX_SESSIONS) reduce queueing;
raising ABAP_SESSION_WAIT_MS only lengthens how long a caller waits.
Wire it into an MCP client
For clients other than Claude Code, which the plugin install above already wires up:
{
"mcpServers": {
"abap": {
"command": "node",
"args": ["/absolute/path/to/abapsmith/dist/index.js"],
"env": {
"ABAP_URL": "https://abap.example.com:44300",
"ABAP_USER": "DEVELOPER",
"ABAP_CLIENT": "001",
"ABAP_SID": "A4H",
"ABAP_MODE": "read"
}
}
}
}
ABAP_PASSWORD — and, in whichever other credential method is in play, ABAP_TOKEN,
ABAP_OAUTH_CLIENT_SECRET, ABAP_SERVICE_KEY, and ABAP_CLIENT_KEY_PASSPHRASE — are deliberately
absent from that block: keep them in the .env the client's working directory supplies, so a
secret never lands in a JSON file that is easy to commit or sync alongside the rest of an editor
config. Start on ABAP_MODE=read and opt into edit once you intend to write.
Documentation
| |
|---|
| doc/CAPABILITIES/README.md | Every object type, framework and capability, with the evidence behind each claim |
| doc/TOOLS/README.md | Full per-tool parameter reference |
| doc/FLUID-API/README.md | The fluid API: one package, one manifest format, one wire protocol for the tools that install ABAP to run |
| doc/CONFIGURATION/README.md | Every environment variable, its default, and its failure mode |
| doc/SAFETY/README.md | The gate, the modes, and the boundaries that are not security controls |
| doc/JOURNAL/README.md | Journal format, undo semantics, drift detection, retention |
| doc/CONCURRENCY/README.md | Session pool, lanes, object gate |
| doc/LIMITATIONS/README.md | What is unproven, unimplemented, or structurally impossible here |
| doc/DESIGN-NOTES/README.md | Decisions that are load-bearing and not obvious from the code |
| doc/TESTING/README.md | Suite layout, fixtures, and how the live tests are gated |
| CONTRIBUTING.md | Build, test, and the bar for a change |
| SECURITY.md | Reporting a vulnerability |
| CHANGELOG.md | What changed, release by release |
License
MIT — see LICENSE. Third-party attribution: THIRD-PARTY-NOTICES.md.
Thanks
Big thanks to two projects whose ideas shaped this one: