Skip to main content
Glama

SAP-MCP

MCP-Server für SAP on-premise über ADT: ein Prozess, der sowohl den MCP-Endpoint als auch die Web-Administration ausführt, mehrere SAP-Systeme gleichzeitig verbinden kann, mit Debugger und Laufzeit-Diagnosewerkzeugen. Die Tool-Namen folgen der PascalCase-Konvention von vibing-steampunk, ergänzt um ein Multi-System-Modell und eine Verwaltungsseite.

Es müssen keine ABAP-Objekte auf dem SAP installiert werden – die einzige Ausnahme ist RunReport, und der Server installiert es selbst (siehe Abschnitt Gruppe D).

Installation

Windowsinstall.bat doppelklicken oder im Terminal ausführen:

install.bat

Es prüft Python 3.10+, erstellt .venv, installiert Abhängigkeiten und erstellt systems.json aus der Vorlagendatei. Danach systems.json öffnen, URL / Benutzer / Passwort des echten SAP-Systems eintragen und run.bat ausführen.

Andere Plattformen:

python -m venv .venv && . .venv/bin/activate
pip install -e .
cp systems.example.json systems.json   # sửa URL, user, password
python -m sap_mcp

systems.json enthält Passwörter und steht bereits in .gitignore – nicht einchecken.

Server starten

Windowsrun.bat doppelklicken, oder:

run.bat              :: cổng 8765, chế độ focused (50 tool)
run.bat 8766         :: đổi cổng
run.bat 8766 expert  :: đổi cổng + bật đủ 66 tool

run.bat setzt die Konsole automatisch auf UTF-8 (Logs enthalten Vietnamesisch, eine cp1252-Konsole würde Python zum Absturz bringen), erstellt systems.json automatisch aus der Vorlage, falls sie fehlt, und meldet klar, welche PID den Port belegt, statt uvicorn einen rohen Socket-Fehler werfen zu lassen.

http://127.0.0.1:8765 öffnen, um Systeme hinzuzufügen/zu bearbeiten/zu testen. Der MCP-Endpoint liegt unter /mcp.

Mit MCP-Client verbinden

mcp.example.json als .mcp.json in das Projektverzeichnis kopieren oder den Abschnitt mcpServers in die vorhandene Client-Konfigurationsdatei einfügen:

{
  "mcpServers": {
    "sap-mcp": {
      "type": "http",
      "url": "http://127.0.0.1:8765/mcp"
    }
  }
}

Den Port anpassen, falls Sie run.bat mit einem anderen Port ausführen. Der Server muss laufen, bevor der Client sich verbindet – dies ist ein streamable-http-Transport, der Client startet den Prozess nicht selbst wie bei stdio.

Systemkonfiguration (systems.json)

Feld

Standard

Bedeutung

url

https://host:port des SAP-Systems

client

100

sap-client

language

EN

sap-language

username / password

Basic-Auth

verify_ssl

true

Auf false setzen für selbstsignierte Zertifikate

ca_bundle

Pfad zu eigenem CA (ersetzt verify_ssl)

timeout

30

HTTP-Obergrenze normal, Sekunden

allow_write

false

Nur damit ist Schreiben möglich

write_packages

["Z*","Y*","$TMP"]

Pakete, in denen geschrieben werden darf

write_objects

Zusätzliche Einschränkung nach Objektnamen

require_transport

true

Transportierbare Pakete benötigen zwingend einen TR

allow_debug

false

Nur damit ist Gruppe D nutzbar (Debugger + Code ausführen)

debug_timeout

1800

Wie lange an einem Breakpoint gestoppt werden darf, Sekunden

debug_listen_seconds

300

Standard-Wartezeit für DebuggerListen, Sekunden

Objekte im Standard-SAP-Namespace werden immer abgelehnt, das lässt sich nicht konfigurieren.

debug_timeout ist nicht nur eine Zahl zum Wohlfühlen. Code, der an einem Breakpoint stoppt, hält die HTTP-Anfrage fest, die ihn ausgeführt hat, also schneidet das normale timeout (30s) mitten beim Betrachten von Variablen ab: Der Hintergrund-Thread stirbt und das Report-Ergebnis geht verloren, DebuggerDetach liefert The read operation timed out statt Daten. Diese Obergrenze wird nur beim Debuggen angehoben (mit Listener oder während am Debuggee gestoppt ist) – sie für jeden Lauf anzuheben würde bedeuten, dass ein hängender Report einen SAP-Workprocess eine halbe Stunde belegt, ohne dass jemand hinsieht.

Umgebungsvariablen

Variable

Standard

Bedeutung

SAP_MCP_SYSTEMS

./systems.json

Pfad zur Konfigurationsdatei

SAP_MCP_PORT

8765

HTTP-Port

SAP_MCP_MODE

focused

focused (50 Tools) oder expert (66 Tools)

SAP_MCP_DISABLED_GROUPS

Funktionsbereiche deaktivieren, z. B. C oder C,D

Gruppencodes: C Transportaufträge, D Debugger, P Laufzeitdiagnose (Dumps, Traces) – siehe Abschnitt Tools unten. Kern-Tools gehören keiner Gruppe an und sind immer aktiviert. Beide zu deaktivieren (SAP_MCP_DISABLED_GROUPS=D,P) reduziert focused/expert auf 30/45 Tools.

Tools

Verwaltung ListSystems GetConnectionInfo GetSystemInfo

Lesen GetSource GetObjectStructure GetClassInfo GetPackage GetFunctionGroup SyntaxCheck · expert: GetProgram GetClass GetInterface GetInclude GetFunction GetClassInclude

GetSource liest einen Ausschnitt statt des gesamten Objekts: around="SELECT" holt das Fenster um das erste Vorkommen außerhalb von Kommentaren, oder from_line/to_line holt genau den Zeilenbereich. Jeder Ausschnitt beginnt mit einer Kommentarzeile, die angibt, dass es sich um einen Ausschnitt handelt – nur die vollständige Version darf an UpdateSource übergeben werden; das Überschreiben mit einem Fenster löscht den Rest. GetPackage hat eine Obergrenze max_objects und meldet, wenn gekürzt wurde.

Suchen SearchObject GrepObjects GrepPackages · expert: GrepObject GrepPackage

Daten RunQuery GetTableContents

RunQuery führt Open-SQL-SELECT aus und liefert die Ergebnistabelle; GetTableContents baut die SELECT-Anweisung für Sie. allow_write ist nicht nötig, weil SAP selbst Schreibbefehle an diesem Endpoint ablehnt:

DELETE FROM t001 …  → 400 Invalid query string. Only SELECT statement is allowed.

Die Grenze für das LESEN sind die Rechte des SAP-Benutzers in systems.json – jede Tabelle, die dieser Benutzer lesen kann, kann auch der Agent lesen, einschließlich Personaltabellen. Konfigurieren Sie keinen Allzweck-Benutzer.

Quellcode-Navigation FindDefinition FindReferences

FindDefinition(system, 'CLAS', 'ZCL_X', symbol='cl_salv_bs_runtime_info') – der Server sucht das Symbol selbst im Quellcode (Kommentare werden übersprungen) und löst es dort auf, liefert Typ, Name und Komponentenliste. navigation/target wird nicht verwendet, obwohl der Name passender klingt: Es liefert genau die eingegebene URI zurück, wenn nichts aufgelöst werden kann – also einen falschen Erfolg. Der nutzbare Weg ist abapsource/codecompletion/elementinfo, und er verlangt den gesamten Quellcode im Body.

FindReferences liefert where-used. SAP gibt einen Baum zurück, der drei Knotentypen mischt; nur Einträge mit gradeDirect sind echte Verwendungsstellen. gradeComponent sind Komponenten des gerade untersuchten Objekts selbst – zählt man sie mit, hat eine Klasse, die niemand aufruft, plötzlich 6 Verwendungsstellen.

Schreiben WriteSource EditSource Activate ActivatePackage CreatePackage GetInactiveObjects LockObject UnlockObject · expert: CreateObject UpdateSource DeleteObject

Zusammenführen CompareSource CloneObject PrettyPrint ImportFromFile ExportToFile

Gruppe C ListTransports · expert: GetTransport CreateTransport ReleaseTransport DeleteTransport

Gruppe D – Debugger SetBreakpoint DeleteBreakpoint DebuggerListen DebuggerPoll DebuggerStopListener DebuggerAttach DebuggerDetach DebuggerGetStack DebuggerGetVariables DebuggerStep RunClass RunReport RunUnitTests

Erfordert allow_debug: true. Ablauf:

  1. SetBreakpoint – die Zeile muss eine ausführbare Anweisung sein, keine Deklaration. Zeilen zählen ist nicht nötig: statement="SELECT" lässt den Server selbst suchen (er überspringt Kommentare, fällt also nicht auf eine nicht ausführbare Zeile) und meldet die Zeilennummer zurück.

  2. DebuggerListen – kehrt sofort zurück, der Listener läuft im Hintergrund

  3. RunClass / RunReport / RunUnitTests – Code ausführen

  4. Wenn der Breakpoint auslöst, kehrt Schritt 3 sofort mit An Breakpoint gestoppt … zurück (nicht mit Daten). DebuggerPoll meldet den Status jederzeit.

  5. DebuggerAttachDebuggerGetStack / DebuggerGetVariables / DebuggerStep

  6. DebuggerDetach – Debuggee freigeben; der Code läuft zu Ende und das Ergebnis von Schritt 3 wird hier zurückgegeben (oder bei DebuggerPoll, wenn es lange läuft)

Wenn kein Breakpoint auslöst, liefert Schritt 3 direkt das Ergebnis wie ein normales Tool.

Warum die drei Code-Ausführungs-Tools im Hintergrund laufen. Wenn Code an einem Breakpoint stoppt, hält SAP die HTTP-Anfrage fest, die ihn ausführt – der Aufruf kehrt erst zurück, nachdem der Debuggee freigegeben wurde. Bei synchronem Aufruf würde genau dieses Tool hängen und der Agent könnte nie DebuggerAttach aufrufen, um es freizugeben: Selbstblockade. Diese drei Tools laufen daher auf einer eigenen Session in einem Hintergrund-Thread und antworten sofort, sobald der Listener den Debuggee erfasst.

Jedes System verwendet beim Debuggen drei getrennte HTTP-Sessions: eine für Listener + Debug-Session (stateful, wird dutzende Sekunden festgehalten), eine zum Ausführen von Code (kann bis zur Freigabe des Debuggee blockiert sein), eine zum Setzen/Entfernen von Breakpoints. Ohne Trennung blockieren sie sich gegenseitig: Code auf der Listener-Session auszuführen passt nur in die Lücke zwischen zwei Long-Poll- Schleifen – genau dann, wenn SAP keinen Listener registriert hat, also nie ein Breakpoint auslöst.

Debug-Report mit Selection-Screen. Externe Breakpoints erfassen keine Dialog-Session – F8 in SE38 drücken, und der Debugger sieht nichts (auf einem echten System gemessen). Verwenden Sie RunReport statt RunClass in Schritt 3: Es führt den Report in einer externen Session aus, sodass der Breakpoint auslöst.

RunReport unterdrückt die ALV-Anzeige und holt trotzdem die Daten (cl_salv_bs_runtime_info), sodass ein Report, der mit ALV endet, nicht mittendrin dumpt. Akzeptiert sowohl PARAMETERS als auch SELECT-OPTIONS (Parameternamen, die mit S_ beginnen) und Varianten.

RunReport schreibt in SAP, benötigt also sowohl allow_write als auch allow_debug, nicht nur allow_debug wie die übrigen Debugger-Tools. Der Server installiert zwei Objekte selbst in $TMP, Sie müssen nichts tun:

  • ZCL_MCP_RUNNER – Vermittlungsklasse, generisch und wird nie verändert. Sie führt SUBMIT (mv_report) WITH SELECTION-TABLE mt_sel aus, d. h. Reportname und der gesamte Selection-Screen sind Laufzeitdaten.

  • ZMCP_RUNNER_ARGS – Programm, das nur aus einer Kommentarzeile besteht und vor jedem Lauf neu geschrieben wird. Die Klasse liest es zur Laufzeit mit READ REPORT.

*@MCP TOKEN 24b8bff8dfb8477b
*@MCP REPORT ZPG_DEMO
*@MCP MAX 100
*@MCP SEL S_BUKRS S I BT
*@MCP LOW 1000
*@MCP HIGH 2000

Warum trotzdem geschrieben werden muss: IF_OO_ADT_CLASSRUN~MAIN( out ) akzeptiert keine Parameter – keine Query-Parameter, kein Body. Der Quellcode eines Objekts ist der einzige Parameterkanal, den ADT REST öffnet.

Die wichtigste Konsequenz ist Sicherheit: Nichts vom Agenten Geliefertes wird mehr zu ABAP-Code. Die frühere Version bettete Filterwerte in ABAP-Literale ein, sodass ein durchgerutschtes Anführungszeichen beliebige Befehle in das SAP-System einschleusen konnte – diese Stelle musste escaped werden, um sicher zu sein. Jetzt liegen die Werte in einer Kommentarzeile und erreichen SAP über die Tabelle RSPARAMS, es gibt also keine Syntax mehr, die man brechen könnte. Nur Zeilenumbruchzeichen sind verboten (sie erzeugen eine Pseudo-Parameterzeile), und Werte über 45 Zeichen werden abgelehnt, weil RSPARAMS-LOW ein CHAR45 ist – SAP würde stillschweigend kürzen, also falsch filtern, ohne dass es jemand merkt.

Jeder Lauf trägt ein Token; die Klasse gibt dieses Token zurück und der Server gleicht ab. Wenn das Schreiben der Parameter fehlschlägt und trotzdem weiterlaufen würde, liefe der Report mit alten Parametern und das Ergebnis würde dem neuen Aufruf zugeordnet – das Token verhindert genau diese Art von stillem Fehler.

Im Vergleich zu vibing-steampunk (das Plugin ZADT_VSP erforderlich: 1 Interface, 3 Klassen, WebSocket- Handler) benötigt RunReport weniger und erfordert keine manuelle SAPC- und SICF-Konfiguration:

vsp (ZADT_VSP)

SAP-MCP (RunReport)

Zu installierende ABAP-Objekte

4

2

SAPC- und SICF-Konfiguration

erfordert Basis-Admin

nein

Server installiert selbst

nein

ja

Klasse wird pro Lauf verändert

nein

nein

SELECT-OPTIONS

nein (hardcodiert kind='P')

ja

Schreiben in SAP pro Lauf

nein

ja (eine Kommentardatei)

Die letzte Zeile ist der Preis dafür, dass kein Admin etwas installieren muss: vsp überträgt Parameter über WebSocket und berührt das System nicht, RunReport überträgt über den Quellcode, weil ADT REST keinen anderen Kanal öffnet. Dafür ist das geschriebene Objekt eine Datei, die nur aus Kommentaren besteht – sie hat keine Syntax, die kaputtgehen könnte, und die Klasse mit der Logik bleibt unverändert.

Gruppe P – Laufzeitdiagnose ListDumps GetDump StartTrace ListTraces GetTrace DeleteTrace GetSQLTraceState · expert: DeleteTraceRequest

Short dump (ST22). ListDumps filtert nach user/error/program/since, GetDump gibt summary (was passiert ist, Fehleranalyse, Absturzstelle, Call-Stack), source (Quellcode an der Absturzstelle), full oder meta zurück.

Leistungsmessung (SAT/ATRA). StartTrace('ZPG_X', 'report') → Code ausführen → ListTracesGetTrace. GetTrace gibt standardmäßig ein Zeitprofil nach Aufrufen zurück, absteigend sortiert; view='db' liefert Datenbankzugriffe nach Tabelle — Anzahl der Zugriffe, Anzahl der Buffer-Treffer, Zeit. RunReport(..., trace=True) vereinfacht die gesamte Kette: Es setzt selbst eine Messanfrage auf, die genau auf diesen Report begrenzt ist.

   NET µs      %  GROSS µs   LẦN  GỌI TỪ                     VIỆC
     3800   51.2      3800     1  CL_HTTP_SERVER_NET=======C DB: Exec Static
      368    5.0      4185     1  SAPLHTTP_RUNTIME           Call M. …SEND_RESPONSE

Drei Dinge, die auf NW 758 gemessen wurden, entgegen den Annahmen von vibing-steampunk — jedes davon würde das Tool stillschweigend beschädigen, wenn man danach handeln würde:

vsp macht

auf NW 758 gemessen

Accept des Feed-Dumps

application/atom+xml

406 — muss …;type=feed sein

Dump-Filter

sendet $filter FQL

SAP ignoriert es, liefert die ungekürzte Liste

ST05 trace/directory

als Trace-Feed lesen

liefert eine Fiori-URL, keine Datensätze

Daher filtert ListDumps auf der MCP-Serverseite, und die SQL-Abfragen stammen aus dbAccesses des ABAP-Traces, nicht aus ST05. GetSQLTraceState bleibt nützlich, um einen vergessenen, noch aktiven Trace zu erkennen — er verlangsamt das gesamte System, ohne dass man es von außen sieht.

StartTrace erfordert zwingend einen Objektnamen. Eine unbegrenzte Trace-Anfrage erfasst sofort genau den HTTP-Aufruf, der sie gerade erzeugt hat: Das Messergebnis besteht dann nur aus ICFSERVICE/HTTP_HEADER_REG — gemessen wird die ADT-Engine, nicht dein Code — und sieht dennoch wie eine echte Zahlentabelle aus. Mit Begrenzung trifft das Messergebnis genau auf den anschließenden Lauf (T001, DDFTX, VARID…).

StartTrace, DeleteTrace, DeleteTraceRequest benötigen allow_debug: Sie verändern das Verhalten des Systems, und eine vergessene Anfrage misst heimlich einen späteren Lauf. Die drei Lese-Tools (ListDumps, GetDump, GetSQLTraceState) benötigen nichts dergleichen.

Status

Die Kern-Toolgruppe, die Gruppe D (Debugger, einschließlich RunReport) und die Gruppe P (Dump + Trace) sind fertig — 50 Tools im Fokusmodus / 66 im Expertenmodus, getestet auf NetWeaver 758. Der Bereich DDIC/i18n, abapGit und ABAP-Helfer ist noch nicht erledigt.

Bekannte Einschränkungen

1. ImportFromFile / ExportToFile beschränken den Pfad nicht. Diese beiden Tools akzeptieren jeden Pfad, den das Modell angibt. import_from_file prüft nur os.path.isfile, export_to_file prüft nur os.path.isdir — keine Allowlist, keine Einschränkung auf ein Workspace-Verzeichnis, keine Sperre für .. oder absolute Pfade. Ein Agent — selbst ein Agent, der durch Inhalte beeinflusst wird, die er aus SAP liest — kann daher jede Datei lesen, die der Serverprozess lesen kann, und sie nach SAP übertragen, oder SAP-Quellcode in jeden beschreibbaren Pfad schreiben. Die derzeitige Risikominderung: Führe den Server nur auf einer Maschine aus, die du kontrollierst, unter einem Konto, das außer den Dateien, die der Agent sehen soll, keine Zugriffsrechte hat.

2. Die REST-Admin-Routen haben keine Authentifizierung. / und /api/systems* sind nur durch das Binden an 127.0.0.1 geschützt. Alles, was den Loopback auf diesem Port erreicht, kann Systemkonfigurationen auflisten, hinzufügen, ändern, löschen und Verbindungstests auslösen. Öffne diesen Port nicht über den lokalen Rechner hinaus und betreibe ihn nicht auf einem gemeinsam genutzten Host.

3. Der Debugger liest alle Variablen im Speicher. DebuggerGetVariables liefert die echten Werte am Haltepunkt, einschließlich sensibler Daten, die gerade in Variablen liegen — Passwörter, Schlüssel, personenbezogene Daten. Das ist die Natur des Debuggens, kein Fehler. Zusätzlich führt RunClass beliebigen ABAP-Code aus. Deshalb ist allow_debug standardmäßig deaktiviert und sollte nur auf Entwicklungssystemen aktiviert werden.

4. RunReport verwendet eine gemeinsame Parameterdatei. ZMCP_RUNNER_ARGS in $TMP wird vor jedem Lauf überschrieben. Innerhalb eines Servers sind die Läufe bereits in einer Warteschlange (ein Ausführungskanal pro System), aber zwei Server oder zwei Personen, die dasselbe System nutzen, überschreiben weiterhin gegenseitig ihre Parameter. Ein Token in der Ausgabe erkennt das und macht daraus einen Fehler, statt falsche Daten zurückzuliefern. vibing-steampunk umgeht das vollständig mit einem eigenen APC-WebSocket pro Sitzung — im Gegenzug muss SICF manuell konfiguriert werden.

Architektur

transport/ (HTTP, Auth, CSRF) → adt/ (Objekttyp, Datenlieferung) → tools/ (Format + MCP-Registrierung). Die Tabelle adt/uri.py ist die einzige Quelle für den Aufbau von URIs. Gruppe D verwendet zusätzlich drei AdtSession pro System (transport/debug_pool.py, nach Kanälen aufgeteilt), weil der Listener im Hintergrund läuft, die Debug-Sitzung ihren Zustand über mehrere Aufrufe hinweg halten muss und laufender Code an einem Breakpoint blockiert werden kann — keine dieser Sitzungen kann aus dem gemeinsamen SessionPool entliehen werden.

Tools laufen im Worker-Thread, nicht auf der Event-Loop. FastMCP ruft synchrone Funktionen direkt auf der Event-Loop auf; würde man das so lassen, blockiert ein einzelner SAP-Aufruf den gesamten Server: Der Agent kann DebuggerPoll nicht aufrufen, während RunReport wartet, verschiedene Systeme blockieren sich gegenseitig und die Web-Admin-Oberfläche friert ein. tools/_registry.py umhüllt jedes Tool vor der Registrierung mit anyio.to_thread.run_sync. Die Serialisierung pro System bleibt bestehen und ist weiterhin beabsichtigt — sie liegt im SessionPool, denn SAP-Lock-Handles gelten nur auf einer Verbindung pro System.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Hosted Amazon Seller and Vendor MCP server for Claude, ChatGPT, Cursor, Codex, Gemini, Copilot.

  • Official Microsoft MCP Server to query Microsoft Entra data using natural language

  • GibsonAI MCP server: manage your databases with natural language

View all MCP Connectors

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/NhatPD-VNEXT/SAP-MCP'

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