Skip to main content
Glama
ChinhHN-DEV

SAP MCP-RFC Bridge

by ChinhHN-DEV

MCP-RFC bridge for SAP ABAP (RFC-only / SAProuter / ECC R3)

An MCP server that lets an MCP client (e.g. Claude Code) work with SAP ABAP objects over RFC instead of ADT/HTTP. Because it speaks RFC + SAProuter, it reaches systems that expose no HTTP/ADT endpoint — including classic ECC / R/3.

Inspired by the SAP Community blog "Using Claude for SAP ABAP development on RFC-only / SAProuter systems (even ECC R/3)". This is an independent, prototype implementation — not an official SAP or Anthropic product.

Architecture

Claude Code  --stdio/MCP-->  server.py (FastMCP)
                                   |
                             sap/tools.py      (wraps standard SAP FMs)
                                   |
                             sap/connection.py (pyrfc Connection, reconnect)
                                   |
                             sap/config.py     (.env -> conn params, SAProuter)
                                   |
                                 pyrfc  --RFC/SAProuter-->  SAP system

Tools exposed

Tool

Purpose

Needs write?

sap_ping

Test connection, system info

no

sap_read_table

Read a table (RFC_READ_TABLE)

no

sap_read_program

Read ABAP report source

no

sap_read_function_module

Read FM source + interface

no

sap_read_class

Read class/interface source

no

sap_read_method

Read ONE method of a class

no

sap_class_api

Public API only (+ dependency APIs)

no

sap_dead_code

Unused-method scan for a package

no

sap_search_objects

Search TADIR for repository objects

no

sap_ddic_info

Describe table/structure fields

no

sap_list_dumps

Recent ST22 runtime errors

no

sap_list_transports

List transport requests (E070)

no

sap_read_transport

One transport + its object list

no

sap_where_used

Where-used via WBCROSSGT index

no

sap_read_screen

Read Dynpro definition (via Z-FM)

no

sap_read_gui_status

Read GUI status/CUA (via Z-FM)

no

sap_syntax_check

Syntax-check source, no save (Z-FM)

no

sap_read_cds

Read CDS/DDL source (Z-FM)

no

sap_textpool_read

Read program text elements (Z-FM)

no

sap_run_unit_tests

Run ABAP Unit for a class (Z-FM)

no

sap_run_atc

Run ATC check (Z-FM stub)

no

sap_adt_dispatch

Raw ZMCP_ADT_DISPATCH call

read: no / write: yes

sap_activate

Activate inactive objects (Z-FM)

yes

sap_textpool_write

Write program text elements (Z-FM)

yes

sap_write_program

Create/update program (INACTIVE)

yes

sap_run_rfc

Call an arbitrary RFC-enabled FM

yes

Custom dispatcher ZMCP_ADT_DISPATCH

The Z-FM tools above route through a custom RFC-enabled FM ZMCP_ADT_DISPATCH (function group ZMCP_ADT_UTILS) installed on the SAP system — the escape hatch for features no standard RFC FM exposes. It runs inside SAP, so it can call non-remote workbench APIs (SYNTAX-CHECK, RS_WORKING_OBJECTS_ACTIVATE, READ/INSERT TEXTPOOL, DDDDLSRC, ABAP Unit, ATC) and return JSON.

Install the two FMs from abap/ on any SAP system you want to drive (see abap/README.md for the interfaces and step-by-step setup). Action → tool map:

Action

Tool

Underlying ABAP

SYNTAX_CHECK

sap_syntax_check

SYNTAX-CHECK FOR

READ_DDLS

sap_read_cds

SELECT … FROM DDDDLSRC

RUN_UNIT_TESTS

sap_run_unit_tests

CL_AUCV_TEST_RUNNER_STANDARD

ATC_CHECK

sap_run_atc

CL_SATC_API_FACTORY (stub — fill in)

ACTIVATE

sap_activate

RS_WORKING_OBJECTS_ACTIVATE

DYNPRO_* / CUA_*

sap_read_screen / sap_read_gui_status

RPY_DYNPRO_* / RS_CUA_INTERNAL_*

RUN_UNIT_TESTS and ATC_CHECK use release-sensitive class APIs — verify/adjust the ABAP in SE24 for your system (ATC_CHECK ships as an explicit stub). Every write action goes through the same SAP_ALLOW_WRITE guard.

Text elements use a separate dedicated FM, ZMCP_ADT_TEXTPOOL (same function group), driven by sap_textpool_read / sap_textpool_write. Flag it Remote-Enabled in SE37 to use it. sap_textpool_write defaults to WRITE_INACTIVE (staged; published on program activation), matching the "nothing goes live until activate" model; pass active=true to write directly.

Write tools are disabled unless SAP_ALLOW_WRITE=true.

Sensitive-table policy: sap_read_table refuses tables holding credentials/PII (USR02, PA0*, SECSTORE*, …). Override the pattern list via SAP_TABLE_BLOCKLIST (comma-separated, * wildcards) in .env.

Package whitelist for writes: set SAP_ALLOWED_PACKAGES (e.g. $TMP,ZPK_SANDBOX*) to restrict sap_write_program to specific packages. Unset = no package restriction (only SAP_ALLOW_WRITE applies).

FM deny list: sap_run_rfc refuses high-risk function modules (OS command execution, arbitrary ABAP, mass delete, raw SQL, user admin, file transfer, kernel admin) even with SAP_ALLOW_WRITE=true. Override the pattern list via SAP_FM_DENYLIST (comma-separated, * wildcards).

Project layout

MCP_SAP_PRIVATE/
  bootstrap.bat              copy to a new machine: clones repo + runs setup
  setup.ps1 / setup.bat      installer + MCP registration
  README.md
  mcp/                       the MCP server (everything it needs to run)
    server.py                MCP server entrypoint (FastMCP, stdio)
    test_connection.py       standalone connectivity check
    requirements.txt
    .env / .env.example      base/shared settings (real .env is git-ignored)
    profiles/                one <name>.env per SAP system (multi-system)
      ds4.env.example        per-system profile template
    sap/                     Python package (the bridge)
      config.py              .env -> pyrfc params, SAProuter, SDK discovery
      connection.py          pyrfc wrapper, reconnect, DLL registration
      tools.py               FM wrappers behind each MCP tool
    vendor/                  third-party / licensed binaries
      nwrfcsdk/              SAP NW RFC SDK (bundled, auto-detected)
      pyrfc-3.3.1-*.whl      prebuilt pyrfc wheel (offline install)
  abap/                      ABAP to install on the SAP system (reusable)
    README.md                install guide + FM interfaces
    zmcp_adt_dispatch.abap   ZMCP_ADT_DISPATCH (screens, syntax, activate, …)
    zmcp_adt_textpool.abap   ZMCP_ADT_TEXTPOOL (text elements)

Deploy via git (clone-and-go)

This repo is meant for a private git remote: the SAP NW RFC SDK (mcp/vendor/nwrfcsdk) and the pyrfc wheel are committed, so a fresh clone runs without any SAP-portal download. Secrets are not committed — .env and mcp/profiles/*.env are git-ignored; each machine fills them in locally.

First push (once, from this folder)

git init
git add .
git commit -m "SAP MCP-RFC bridge"
git remote add origin https://github.com/ChinhHN-DEV/MCP_SAP_PRIVATE.git
git push -u origin main

The commit includes the ~60 MB SDK. Keep the remote private — the SDK is licensed and must not be public.

On a new machine (one command)

Edit the REPO= line in bootstrap.bat, copy just that one file to the new machine, and run it (or bootstrap.bat <git-url>). It clones the repo and runs setup.ps1. Afterwards, create your connection config:

# single system:
copy mcp\.env.example mcp\.env            # then edit
# or multi-system:
copy mcp\profiles\ds4.env.example mcp\profiles\ds4.env   # then edit, re-run setup.ps1

Quick install on a new machine

Copy the whole folder over, then from inside it run one of:

# Windows (PowerShell)
powershell -ExecutionPolicy Bypass -File .\setup.ps1

…or just double-click setup.bat.

setup.ps1 finds Python, installs python-dotenv + mcp, installs the matching pyrfc wheel (from vendor/, or downloads the right one), verifies the bundled SDK, creates .env from the template, and registers the sap-rfc MCP server with Claude Code using this folder's current absolute path — so it works no matter where the folder was moved to. Afterwards just edit .env and run python mcp\test_connection.py. The manual steps below are the same thing by hand.

Multiple SAP systems

Run one MCP server per system, each selected by a profile file. Claude Code then sees separate, namespaced tool sets (mcp__sap-ds4__…, mcp__sap-qa4__…) and picks the right system by server name.

  1. Put per-system logon in mcp/profiles/<name>.env (copy mcp/profiles/ds4.env.example):

    profiles/ds4.env      # DEV, SAP_ALLOW_WRITE=true
    profiles/qa4.env      # QA,  read-only
    profiles/prd.env      # PROD, read-only

    Shared policy (SAP_TABLE_BLOCKLIST, SAP_FM_DENYLIST, …) stays in the base .env; each profile overrides the base and holds that system's credentials + SAP_ALLOW_WRITE.

  2. Run setup.ps1 — it registers one server sap-<name> per profile file (falls back to a single sap-rfc from .env when no profiles exist).

  3. Test a specific system:

    python mcp\test_connection.py --profile qa4

Profile selection precedence: --env-file <path> > --profile <name> > SAP_PROFILE env var > base .env. sap_ping reports which profile answered. Keep DEV writable and QA/PROD read-only (SAP_ALLOW_WRITE=false) so the deny guards differ per system automatically.

Setup (manual)

1. SAP NW RFC SDK (prerequisite for pyrfc)

pyrfc wraps the SAP NetWeaver RFC SDK (licensed; from the SAP Support Portal). This repo bundles the Windows SDK at mcp/vendor/nwrfcsdk, auto-detected and registered at runtime (via os.add_dll_directory). No PATH edits needed. To use a different SDK location, set SAPNWRFC_HOME — it takes precedence over the bundled copy.

OS runtime prerequisite for the SDK (SAP Note 2573790)

The NW RFC SDK DLL needs the Microsoft Visual C++ 2015-2022 Redistributable x64 (vcruntime140.dll) present — without it, import pyrfc fails with a cryptic load error. setup.ps1 warns and links the installer if it is missing. Patch level of an installed SDK: findstr Patch sapnwrfc.dll.

2. Install Python dependencies

pyrfc has no PyPI wheel for recent Python, so a matching prebuilt wheel is vendored in mcp/vendor/:

python -m pip install python-dotenv mcp
python -m pip install mcp/vendor/pyrfc-3.3.1-cp312-cp312-win_amd64.whl

The wheel is cp312 / win_amd64 (Python 3.12, Windows 64-bit) from the SAP-archive/PyRFC GitHub releases. For a different Python version, fetch the matching wheel from there.

3. Configure the connection

Copy-Item mcp\.env.example mcp\.env
# then edit .env

SAProuter example — either put the full route in SAP_ASHOST:

SAP_ASHOST=/H/saprouter.example.com/S/3299/H/sapappserver.internal
SAP_SYSNR=00

…or keep a plain host and set the router prefix separately:

SAP_ASHOST=sapappserver.internal
SAP_SYSNR=00
SAP_SAPROUTER=/H/saprouter.example.com/S/3299

4. Test connectivity (no MCP needed)

python mcp\test_connection.py

5. Register the server with Claude Code

claude mcp add sap-rfc -- python "c:\Users\Administrator\Desktop\MCP_SAP_PRIVATE\mcp\server.py"

Or add to your MCP client config:

{
  "mcpServers": {
    "sap-rfc": {
      "command": "python",
      "args": ["c:\\Users\\Administrator\\Desktop\\MCP_SAP_PRIVATE\\mcp\\server.py"]
    }
  }
}

Safety

  • Read-only by default. Keep SAP_ALLOW_WRITE=false unless you intend to modify objects, and only enable writes against a DEV system.

  • Writes are saved INACTIVE — nothing goes live until you activate it in SAP.

  • Use an RFC user with the minimum authorizations required.

  • .env holds credentials — it is git-ignored; never commit it.

Verified on

Read tools (sap_ping, sap_read_table, sap_read_program, sap_read_function_module, sap_read_class, sap_search_objects) verified end-to-end against an S/4HANA system (SAP_BASIS 758) reached through a SAProuter. Class source uses the remote-enabled SIW_RFC_READ_CLIF_SOURCE.

Caveats / limits over pure RFC

  • Only remote-enabled function modules are callable over RFC. Many workbench FMs (e.g. the SEO_* class APIs, the ABAP SYNTAX-CHECK) are not RFC- enabled, so some ADT-style features simply aren't reachable this way.

  • CDS/DDL source read is not available over pure RFC on the tested system — there is no remote-enabled FM that returns DDL source text. Use ADT for that.

  • Object activation and syntax check are likewise not wired up: no clean remote-enabled FM was found on the tested release. Writes therefore stay INACTIVE; activate in SAP GUI/ADT.

  • RFC_READ_TABLE cannot select rows wider than 512 bytes or long/deep fields; long WHERE clauses are auto-wrapped to the 72-char OPTIONS line limit.

  • FM availability/interfaces can still vary by release — validate on your target.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ChinhHN-DEV/MCP_SAP_PRIVATE'

If you have feedback or need assistance with the MCP directory API, please join our Discord server