Schlagwort: ADT

  • Vom offenen Scheunentor zum abgesicherten MCP-Server: KI-gestützte ABAP-Entwicklung mit ARC-1

    KI-Assistenten wie Claude können inzwischen richtig gut ABAP. Was ihnen fehlt, ist der Zugang zum System: lesen, suchen, aktivieren, am besten direkt über die ADT-Schnittstelle, die auch Eclipse benutzt. Die Brücke dafür heißt MCP (Model Context Protocol, ein offener Standard, über den KI-Clients mit Werkzeugen sprechen). Solche Brücken gibt es als Open Source. Die Frage ist nicht, ob das geht. Die Frage ist, wie kontrolliert.

    Genau daran bin ich beim ersten Anlauf fast gescheitert. Hier die ganze Geschichte, inklusive der Stellen, an denen ich mir an die Stirn gefasst habe.

    Runde 1: Es funktioniert. Und genau das ist das Problem.

    Der Plan: ein zentraler MCP-Server auf einer frischen Debian-Kiste, damit nicht jeder Entwickler lokal sein eigenes Setup pflegt. Installiert war der erste Kandidat schnell, ein Node-basierter ADT-MCP-Server, per npm auf den Server, HTTP-Modus an, Port gebunden, Verbindung zum SAP-Entwicklungssystem stand.

    Dann der Moment, in dem ich auf den laufenden Endpoint geschaut habe: keinerlei Client-Authentifizierung. Nicht falsch konfiguriert, sondern schlicht nicht vorgesehen, das Werkzeug ist als lokales Entwicklertool gebaut. Im LAN bedeutete das: Jeder, der die URL kennt, arbeitet mit vollen Entwicklerrechten auf dem SAP-System. Eine Tür ohne Schloss.

    Der erste Reparaturversuch klang clever: Die SAP-Credentials aus der Server-Konfiguration streichen und vom Client pro Request mitgeben. Dabei bin ich prompt in eine Denkfalle getappt: Umgebungsvariablen aus der Client-Konfiguration erreichen einen Remote-Server nie, die wirken nur bei lokal gestarteten Prozessen. Der einzige Kanal wären HTTP-Header gewesen. Und damit lägen die SAP-Passwörter wieder auf jedem Laptop und wandern bei jedem Request übers Netz. Genau davon wollte ich weg. Verworfen.

    Runde 2: ARC-1, oder: Sicherheit als Werkseinstellung

    Die Lösung kam mit ARC-1, einem Open-Source-MCP-Server für SAP-Systeme, der von vornherein für den Firmeneinsatz gebaut ist. Drei Eigenschaften haben mich überzeugt:

    Erstens verweigert er im HTTP-Modus schlicht den Start, wenn keine Authentifizierung konfiguriert ist. Zweitens ist ab Werk alles auf nur lesen gestellt, jede weitere Fähigkeit (schreiben, Tabellen ansehen, Transporte) ist ein einzelnes, bewusstes Opt-in. Drittens wird jeder Tool-Aufruf mit Personenzuordnung protokolliert. Kostenpunkt: 0 Euro Lizenz, läuft als Docker-Container.

    Das Architekturmodell dahinter ist der eigentliche Aha-Moment: zwei getrennte Anmeldungen. Hop 1 (Client zu ARC-1) läuft über persönliche API-Keys mit Rollenprofil, mein Key darf entwickeln, der meiner Kollegin erst mal nur lesen. Hop 2 (ARC-1 zu SAP) läuft über einen technischen SAP-User, dessen Passwort nur auf dem Server liegt. Kompromittierter Laptop? Ein Key wird gesperrt, das SAP-Passwort bleibt unberührt. Effektiv gilt: Server-Regeln UND Key-Profil UND SAP-Berechtigung müssen alle drei ja sagen.

    Die Compose-Datei dazu passt auf einen Bildschirm:

    services:
      arc1:
        image: ghcr.io/arc-mcp/arc-1
        restart: unless-stopped
        ports:
          - "127.0.0.1:3000:8080"
        environment:
          SAP_TRANSPORT: http-streamable
          SAP_URL: https://srv-sap01:44300
          SAP_CLIENT: "100"
          SAP_USER: <TECH_USER>
          SAP_PASSWORD: <PASSWORT>
          SAP_INSECURE: "true"
          ARC1_API_KEYS: "<KEY_1>:developer,<KEY_2>:viewer"

    Der Abend der kleinen Fehler

    Klingt glatt? War es nicht. Drei Stolperer in einer Stunde, alle lehrreich.

    Stolperer eins: curl http://localhost:3000/health antwortete mit Connection reset. Der Container lief, die Logs waren makellos, SAP-Preflight grün. Des Rätsels Lösung stand in der Ausgabe von docker ps: Das Port-Mapping zeigte auf 3000->8000 statt 3000->8080. Eine vertippte Ziffer, und die Requests liefen ins Leere. Der Debug-Trick, den ich mir gemerkt habe: docker compose config zeigt, was Compose wirklich geparst hat, nicht was man zu editieren glaubt. In meinem Fall bearbeitete ich nämlich zwischenzeitlich die falsche Datei, denn Compose bevorzugt compose.yaml vor docker-compose.yml, wenn beide herumliegen.

    Stolperer zwei: Claude Desktop unter Windows. Die Brücke mcp-remote (nötig, weil Desktop remote nur über einen lokalen Stellvertreterprozess spricht) hat gleich zwei Windows-Eigenheiten. npx lässt sich nicht direkt starten, es braucht die cmd /c-Klammer. Und Leerzeichen in Header-Argumenten werden beim Durchreichen zerlegt, der Authorization-Header kam kaputt an. Der Workaround: Header ohne Leerzeichen schreiben und den Wert über eine Umgebungsvariable einschleusen.

    "arc1": {
      "command": "cmd",
      "args": [
        "/c", "npx", "-y", "mcp-remote",
        "https://192.0.2.10/mcp",
        "--header", "Authorization:${AUTH_HEADER}"
      ],
      "env": {
        "AUTH_HEADER": "Bearer <API_KEY>",
        "NODE_EXTRA_CA_CERTS": "C:\\certs\\ca-root.crt"
      }
    }

    Stolperer drei war fast schon lustig: Nach dem Umbau auf HTTPS meldete der Server einen 404 mit dem freundlichsten Fehlertext des Tages: „Not found. Use /mcp for MCP protocol.“ Beim Umschreiben der URL war schlicht der Pfad /mcp verloren gegangen. Manchmal sagt einem das System wortwörtlich, was fehlt. Man muss es nur lesen.

    Nix mit Klartext: TLS mit Caddy in drei Zeilen

    Bearer-Keys im Klartext durchs LAN? Nein. Als TLS-Terminierung kam Caddy davor, weil der Reverse Proxy dort inklusive eigener Zertifizierungsstelle drei Zeilen braucht:

    https://192.0.2.10 {
        tls internal
        reverse_proxy 127.0.0.1:3000
    }

    Der Klartext-Port wanderte gleichzeitig auf Loopback (127.0.0.1:3000:8080 im Compose), aus dem Netz ist nur noch Port 443 erreichbar. Zwei Fallen auf der Zielgeraden: Die Root-CA von Caddy liegt in einem versteckten Verzeichnis (.local, ein normales ls zeigt nichts, und sie entsteht überhaupt erst nach dem ersten TLS-Handshake). Und auf dem Windows-Client hilft der Import in den Windows-Zertifikatsspeicher exakt gar nichts, weil Node ihn ignoriert. Node will NODE_EXTRA_CA_CERTS mit dem Pfad zur Datei. Wer die Datei dann noch per PowerShell-Umleitung kopiert, bekommt UTF-16 und einen kryptischen OpenSSL-Fehler obendrauf. scp nehmen, fertig.

    Learnings

    • „Funktioniert“ und „ist sicher“ sind zwei Baustellen. Ein MCP-Endpoint ohne Client-Auth ist im LAN ein offenes Scheunentor mit SAP-Entwicklerrechten dahinter.
    • Zwei Auth-Hops sind der Schlüssel: persönliche Keys zum Gateway, technischer User zum SAP. Credentials gehören auf den Server, nicht auf Laptops.
    • docker compose config vor jedem Neustart. Es zeigt die geparste Wahrheit und entlarvt vertippte Ports und doppelte Compose-Dateien in Sekunden.
    • Node ignoriert den Windows-Zertifikatsspeicher. Interne CAs brauchen NODE_EXTRA_CA_CERTS, alles andere ist verschwendete Lebenszeit.
    • Fehlermeldungen wörtlich lesen. Der beste Hinweis des Tages stand im 404-Text des Servers selbst.

    Nächster Ausbauschritt, wenn das Setup wächst: pro Person eine eigene Server-Instanz mit eigenem SAP-User, dann stimmt auch das SAP-eigene Audit-Log auf Personenebene. Aber das ist eine Geschichte für einen eigenen Beitrag.