abapsmith
# 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](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](#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.
```bash
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.
```bash
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](doc/CONFIGURATION/connection.md#authentication) 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](doc/CONFIGURATION/transport.md) for the variables and
[doc/SAFETY/remote-transport.md](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](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:
```jsonc
{
"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](doc/CAPABILITIES/README.md) | Every object type, framework and capability, with the evidence behind each claim |
| [doc/TOOLS/README.md](doc/TOOLS/README.md) | Full per-tool parameter reference |
| [doc/FLUID-API/README.md](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](doc/CONFIGURATION/README.md) | Every environment variable, its default, and its failure mode |
| [doc/SAFETY/README.md](doc/SAFETY/README.md) | The gate, the modes, and the boundaries that are not security controls |
| [doc/JOURNAL/README.md](doc/JOURNAL/README.md) | Journal format, undo semantics, drift detection, retention |
| [doc/CONCURRENCY/README.md](doc/CONCURRENCY/README.md) | Session pool, lanes, object gate |
| [doc/LIMITATIONS/README.md](doc/LIMITATIONS/README.md) | What is unproven, unimplemented, or structurally impossible here |
| [doc/DESIGN-NOTES/README.md](doc/DESIGN-NOTES/README.md) | Decisions that are load-bearing and not obvious from the code |
| [doc/TESTING/README.md](doc/TESTING/README.md) | Suite layout, fixtures, and how the live tests are gated |
| [CONTRIBUTING.md](CONTRIBUTING.md) | Build, test, and the bar for a change |
| [SECURITY.md](SECURITY.md) | Reporting a vulnerability |
| [CHANGELOG.md](CHANGELOG.md) | What changed, release by release |
## License
MIT — see [LICENSE](LICENSE). Third-party attribution: [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md).
## Thanks
Big thanks to two projects whose ideas shaped this one:
- [Vibing Steampunk](https://github.com/oisee/vibing-steampunk) — also the source of the ADT
debugger protocol knowledge behind `src/debug/`, credited in
[THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md).
- [mcp-abap-adt](https://github.com/fr0ster/mcp-abap-adt)
TDQS
Scored across 29 tools
Most tools target distinct resource-action pairs (search, read, write, debug, transport, BOPF, IMG, RAP) and descriptions are detailed enough to disambiguate. A few pairs like abap_read vs abap_search or abap_bopf vs abap_bopf_edit could cause hesitation, but the descriptions clarify their boundaries.
All tools share a consistent snake_case style with the abap_ prefix, which is good. However, the naming mixes nouns (abap_transport, abap_journal), verbs (abap_read, abap_write), and compounds (abap_transport_release, abap_debug_vars), so there is no uniform verb_noun pattern.
29 tools is on the heavy side, but the apparent scope is broad—ABAP development spans search, read/write, transports, BOPF, IMG, RAP, debugging, and testing. The count is justified by the domain, though many tools are locked on this server, adding surface area without live functionality.
The set covers the core ABAP lifecycle—search, read, write/activate, test, debug, and transport—plus specialized areas like BOPF, RAP, FPM, and IMG. Minor gaps exist (e.g., no dedicated object comparison tool), but common workflows are well supported and abap_write covers delete operations.