# SAP MCP Bridge Five SAP / UI5 / Fiori Model Context Protocol servers, packaged in a single container and routed through an internal **nginx reverse proxy** so the app exposes only **one external port** (Runtipi / Traefik friendly). ## Bundled MCP servers | Path prefix | MCP server | Use case | | -------------- | ----------------------------------------- | ------------------------------------------ | | `/cap/mcp` | `@iflow-mcp/cap-js-mcp-server` | SAP CAP (Cloud Application Programming) | | `/abap/mcp` | `@iflow-mcp/mcp-abap-adt` | SAP ABAP via ADT (S/4HANA Cloud, on-prem) | | `/odata/mcp` | `@iflow-mcp/btp-sap-odata-to-mcp-server` | SAP OData via BTP Destination service | | `/ui5/mcp` | `@ui5/mcp-server` | SAPUI5 framework guidance + linting | | `/fiori/mcp` | `@sap-ux/fiori-mcp-server` | SAP Fiori tools / app generation | Each stdio MCP server is wrapped by `supergateway` and speaks **Streamable HTTP** on its own internal port (9001–9005). An internal nginx (port 8080 — the only EXPOSEd port) routes external requests by URL path. Long timeouts and disabled buffering make MCP streaming responses work correctly. ## Health endpoints - `/healthz` — aggregate (probes the CAP gateway) - `/cap/healthz`, `/abap/healthz`, `/odata/healthz`, `/ui5/healthz`, `/fiori/healthz` ## Using from Claude Code Once the app is installed (and either exposed via a domain or reachable on the LAN), wire the servers you want into your MCP client. With the Claude Code CLI: ```bash claude mcp add --transport http sap-cap https://sap-mcp.example.com/cap/mcp claude mcp add --transport http sap-abap https://sap-mcp.example.com/abap/mcp claude mcp add --transport http sap-odata https://sap-mcp.example.com/odata/mcp claude mcp add --transport http ui5 https://sap-mcp.example.com/ui5/mcp claude mcp add --transport http fiori https://sap-mcp.example.com/fiori/mcp ``` …or by adding the equivalent block to your project's `.mcp.json` / `~/.claude.json`: ```json { "mcpServers": { "sap-cap": { "type": "http", "url": "https://sap-mcp.example.com/cap/mcp" }, "sap-abap": { "type": "http", "url": "https://sap-mcp.example.com/abap/mcp" }, "sap-odata": { "type": "http", "url": "https://sap-mcp.example.com/odata/mcp" }, "ui5": { "type": "http", "url": "https://sap-mcp.example.com/ui5/mcp" }, "fiori": { "type": "http", "url": "https://sap-mcp.example.com/fiori/mcp" } } } ``` ## ⚠️ Security warning — read before exposing externally This app intentionally enables **wildcard CORS** (`Access-Control-Allow-Origin: *`) inside the supergateway wrappers, because MCP clients may call the endpoint from a variety of origins. Combined with `exposable: true` and **no built-in authentication**, this means: if you expose the app on a public URL via Traefik or a Cloudflare Tunnel, *anyone who knows the URL* can drive your configured SAP credentials. Recommended deployments: - **Local LAN only**: leave `exposable: false` (default) and reach it via `http://:` from inside the LAN. - **Exposed to the internet**: put it behind a Traefik **ForwardAuth** middleware (e.g. Authentik / Authelia), a Cloudflare Access policy, or basic-auth in nginx-proxy-manager — i.e. authenticate at the proxy, not the app. Do NOT expose this publicly without an auth layer in front of it. ## Configuration All credential form fields are **optional**. Empty values are fine — servers that don't have their required env vars simply won't be usable, but the others (and the container as a whole) will still run. - **`sap-abap-adt` needs:** `SAP_URL`, `SAP_USERNAME`, `SAP_PASSWORD`, `SAP_CLIENT` - **`sap-odata` needs:** `SAP_DESTINATION_NAME`, `DESTINATION_SERVICE_URL`, `DESTINATION_CLIENT_ID`, `DESTINATION_CLIENT_SECRET`, `DESTINATION_AUTH_URL` - **`sap-cap`, `ui5-mcp-server`, `fiori-mcp-server`** require no credentials — they read your **project workspace** at request time. ## Workspace mount The container's `/workspace` is bound to: ``` /etc/runtipi/user-config/runtipi/sap-mcp-bridge/workspace ``` This lives under `user-config/`, which **survives Runtipi restarts and `app update`**. Drop your CAP / UI5 / Fiori projects in there for the `cap`, `ui5`, and `fiori` MCP servers to operate on. The entrypoint chowns this directory to the in-container `mcp` user (UID 10001) on every start, so a freshly auto-created mount works. If you want `/workspace` to point at a different host path, create `/etc/runtipi/user-config/runtipi/sap-mcp-bridge/docker-compose.yml` with an overlay, e.g.: ```yaml services: sap-mcp-bridge: volumes: - /your/other/path:/workspace ``` ## Image Custom image: `git.alexzaw.dev/alexz/sap-mcp-bridge:latest` — built from the sources in `build/` (Dockerfile + entrypoint.sh + nginx.conf). See `build/README.md` for the build & push procedure.