Skip to main content
Glama
Tjarliman

sap-mcp

by Tjarliman
README.md
# sap-mcp

MCP server for SAP S/4HANA via the ADT API. Runs locally over stdio.

## Setup on a new machine

**Prerequisites** (install these first):

- **Node.js >= 20.12** (needs `process.loadEnvFile`; also provides `npm`) — required
- **Claude Code** — required to use the server (only the registration step needs it)
- **Network/VPN reachability** to your SAP hosts (e.g. `fiori-dev...`) — required
- **git** — optional; only used for `git clone`. No git? See below.
  (To install on Windows: `winget install --id Git.Git -e`, then **reopen your
  terminal**. macOS: `brew install git`. Verify with `git --version`.)

Then:

```bash
git clone https://github.com/Tjarliman/sap-mcp.git
cd sap-mcp
npm install
cp .env.example .env      # PowerShell/CMD: copy .env.example .env
```

> **No git?** Instead of `git clone`, download the repo from GitHub: green
> **Code** button -> **Download ZIP**, unzip it, then `cd` into the folder and
> continue from `npm install`. (git is only nicer later, for pulling updates
> with `git pull` instead of re-downloading.)

Now **edit `.env`** and fill in the real `HOST`/`CLIENT` for each system plus
**your own** SAP `USER`/`PASS`. The real hostnames are intentionally not in this
repo — get them from whoever maintains it. Then verify and register:

```bash
node test.mjs             # PASS = install OK  (does NOT check credentials)
node test.mjs --live      # PASS = credentials + SAP reachable  <-- the real proof

# Register with Claude Code (use the ABSOLUTE path to server.js on this machine):
claude mcp add sap-adt --scope user -- node C:\Users\<name>\sap-mcp\server.js
```

Start a **fresh Claude Code session** afterwards for the server to load.

> `node test.mjs` reports PASS even before you edit `.env` — it only checks that
> the server boots and loads profiles. `node test.mjs --live` is what actually
> confirms your credentials and SAP connectivity.

## Updating an existing install

If you already have sap-mcp set up, pull the latest and **restart Claude Code**:

```bash
cd sap-mcp
git pull            # no git? re-download the ZIP over your folder (keep your .env)
npm install         # only needed if dependencies changed; harmless to run anyway
node test.mjs       # confirm it still boots
```

You do **not** need to re-run `claude mcp add` — the registration persists. Your
`.env` is never touched by an update (it's gitignored), so your credentials and
profiles carry over.

> **Important — quit and restart Claude Code after updating.** New tools are only
> discovered when a Claude Code session **starts**. If an update adds a tool
> (like `create_program` below), a reconnect or `/mcp` refresh is **not** enough:
> fully quit Claude Code and open a fresh session. (Behaviour-only changes to
> existing tools just need the server to respawn, which a new session also does.)

To confirm the update loaded, start a fresh session and ask Claude to run
`list_servers`, or check that the new tool is available.

### What's new (2026-07)

This release roughly doubles the toolset (25 → 45). **These are new tools, so you
must fully quit and restart Claude Code after updating** (see the note above).

- **Source editors for the objects that were create-only.** You could previously
  create a class but never edit one — that's fixed:
  `update_class` / `patch_class`, `update_bdef` / `patch_bdef`,
  `update_srvd` / `patch_srvd`, `update_cds` / `patch_cds`,
  `update_function_module`. Each locks → writes → unlocks and can activate;
  the `patch_*` variants do a surgical exact-string replace and refuse to write
  when the target text matches zero or more than one time.
- **`syntax_check`** — run ADT's syntax/consistency check on an object *without*
  activating it. Read-only and safe on any profile, including production. Use it
  after writing source and before `activate_object`; pass `version:"inactive"`
  to check source you have saved but not yet activated.
- **New object types**: `create_structure` / `update_structure` /
  `patch_structure` (DDIC structures), `create_interface` / `update_interface` /
  `patch_interface`, `create_ddlx` / `update_ddlx` / `patch_ddlx` (CDS metadata
  extensions — the UI annotations a Fiori Elements app needs),
  `create_domain`, `create_data_element`,
  `create_function_group`, `create_function_module`.
- **`where_used`** — the ADT where-used list: find everything that depends on an
  object before you change or delete it. Read-only; results are capped and the
  true total is always reported (a common table can have tens of thousands).
- **`run_atc`** — run an ATC (ABAP Test Cockpit) static-analysis check on an
  object and report the findings. Read-only. Picks up the system's configured
  check variant automatically. Use `syntax_check` for fast error checking and
  `run_atc` before releasing a transport.
- **`list_transports`** — find your open transport requests, so you can pass a
  real request number to the create/update tools.
- **Fix:** `get_object_info` now sends `Accept: */*`, so DDIC metadata (domains,
  data elements, tables) is readable instead of failing with HTTP 406.
- **`update_table` / `patch_table`** — modify an EXISTING DDIC table's source:
  `update_table` overwrites the whole definition, `patch_table` does a surgical
  exact-string replace (add/change a field). Both lock → write → unlock and
  optionally activate; blocked on production. Mirrors the
  `update_program_source` / `patch_program_source` pair. **New tools — restart
  Claude Code after updating** (see above).
- **`create_program`** — create a brand-new classic ABAP report (executable
  program, `PROG/P`) and activate it in one call. Previously the server could
  only *edit* an existing program; now it can create one from scratch. Refuses
  to run on production profiles. **This is a new tool, so you must restart
  Claude Code after updating** (see above).
- **Data-driven profiles** — profiles are now discovered from your `.env`: every
  `SAP_<KEY>_HOST` you define becomes a switchable profile named `<KEY>`, with no
  code change needed to add a system. Profile switching is case-insensitive.
- **Production write-block widened** — writes are now blocked on both `ABLP`
  (production) and `ABLQ` (QAS). Read access still works on every profile.

## Testing your install

The `node test.mjs` / `node test.mjs --live` steps above are the self-check
(`npm test` runs the structural one). The bundled harness talks to the server
over stdio — no Claude Code needed.

Once registered, you can also verify through Claude Code — ask it to run
`list_servers`, or a `query_table` with `SELECT MANDT, MTEXT FROM T000`.

## Credentials

Each person uses their **own named SAP user** per system. All connection
details and credentials live in `.env` (gitignored); `server.js` contains no
real hostnames. Never commit or share `.env` — sharing a service account breaks
the SE24/transport audit trail and usually violates license terms.

Fill in `HOST`, `CLIENT`, `USER` and `PASS` for each profile in `.env`. Every
`SAP_<KEY>_HOST` you define becomes a switchable profile named `<KEY>` — the
list below is illustrative, not fixed, so add or rename systems freely:

| Profile  | Role                     |
|----------|--------------------------|
| `ABLD`   | Development              |
| `dev120` | Development (client 120) |
| `snet`   | QA/Test                  |
| `ABLQ`   | QAS (read-only)          |
| `ABLP`   | Production               |
| `snet2`  | S/4HANA on-prem          |

### Protecting a system from writes

Add a `READONLY` (or `PROD`) flag next to any profile in `.env` and every write
on it — create, edit, activate — is refused. Reads keep working:

```bash
SAP_PRD2_HOST="https://sap-prd2.example.com:44300"
SAP_PRD2_CLIENT="100"
SAP_PRD2_USER=""
SAP_PRD2_PASS=""
SAP_PRD2_READONLY=true      # or SAP_PRD2_PROD=true
```

Accepted values: `true` / `1` / `yes` / `y` / `X`. **Do this for every
production system you add** — no code change needed. Add
`SAP_PRD2_LABEL="Production"` to control how the profile is described by
`list_servers`.

> The flag protects a **profile**, not a system. If two profiles point at the
> same host *and* client, flag both — otherwise writes still reach that client
> through the unflagged one.

`ABLP` and `ABLQ` are *also* blocked by a built-in list in `server.js`, so they
stay protected even if the flag is missing. The two sources are **additive**: a
missing flag can never unblock a system that was protected before.

Run `list_servers` to confirm — protected profiles are shown as `[read-only]`.
A blocked write reports which rule stopped it.

## Disclaimer

This software is provided **"as is", without warranty of any kind**, express or
implied. You use it entirely **at your own risk**.

- **No liability.** The author accepts no responsibility for any damage, data
  loss, downtime, security incident, or other harm — to your computer, your SAP
  systems, or your data — arising from the use, misuse, or inability to use this
  software.
- **Your access, your responsibility.** You supply your own SAP credentials in
  `.env`. Keep that file private, use your own named user, and connect only to
  systems you are authorized to access.
- **Production risk remains.** Writes to the `ABLP` (production) profile are
  blocked, but the tool can still *read* from any system you configure. Use it
  at your own discretion.
- **Compliance is on you.** Ensure your use complies with your organization's
  policies and your SAP license terms before connecting.
- **Not affiliated with SAP.** SAP and S/4HANA are trademarks of SAP SE. This
  is an independent, unofficial tool and is not endorsed by or affiliated with
  SAP SE.

## License

[MIT](LICENSE). The license text includes the binding "as is" / no-warranty /
no-liability terms; the Disclaimer above restates them in plain language.