SAP-MCP
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
Windows – install.bat doppelklicken oder im Terminal ausführen:
install.batEs 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_mcpsystems.json enthält Passwörter und steht bereits in .gitignore – nicht einchecken.
Server starten
Windows – run.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 toolrun.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 |
| — |
|
|
|
|
|
|
|
| — | Basic-Auth |
|
| Auf |
| — | Pfad zu eigenem CA (ersetzt |
|
| HTTP-Obergrenze normal, Sekunden |
|
| Nur damit ist Schreiben möglich |
|
| Pakete, in denen geschrieben werden darf |
| — | Zusätzliche Einschränkung nach Objektnamen |
|
| Transportierbare Pakete benötigen zwingend einen TR |
|
| Nur damit ist Gruppe D nutzbar (Debugger + Code ausführen) |
|
| Wie lange an einem Breakpoint gestoppt werden darf, Sekunden |
|
| Standard-Wartezeit für |
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 |
|
| Pfad zur Konfigurationsdatei |
|
| HTTP-Port |
|
|
|
| — | Funktionsbereiche deaktivieren, z. B. |
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:
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.DebuggerListen– kehrt sofort zurück, der Listener läuft im HintergrundRunClass/RunReport/RunUnitTests– Code ausführenWenn der Breakpoint auslöst, kehrt Schritt 3 sofort mit
An Breakpoint gestoppt …zurück (nicht mit Daten).DebuggerPollmeldet den Status jederzeit.DebuggerAttach→DebuggerGetStack/DebuggerGetVariables/DebuggerStepDebuggerDetach– Debuggee freigeben; der Code läuft zu Ende und das Ergebnis von Schritt 3 wird hier zurückgegeben (oder beiDebuggerPoll, 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ührtSUBMIT (mv_report) WITH SELECTION-TABLE mt_selaus, 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 mitREAD REPORT.
*@MCP TOKEN 24b8bff8dfb8477b
*@MCP REPORT ZPG_DEMO
*@MCP MAX 100
*@MCP SEL S_BUKRS S I BT
*@MCP LOW 1000
*@MCP HIGH 2000Warum 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 ( | SAP-MCP ( | |
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 | 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 → ListTraces → GetTrace. 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_RESPONSEDrei 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 |
| 406 — muss |
Dump-Filter | sendet | SAP ignoriert es, liefert die ungekürzte Liste |
ST05 | 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.
This server cannot be installed
Maintenance
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
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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