Skip to main content

Shared configuration models for MCP servers that connect to SAP systems

Project description

sap-mcp-config

Go Tests Go Coverage Go Lint Go Reference Go Report Card Python Tests Python Coverage Python Lint Python Formatting Python Versions PyPI

The standard way to manage SAP credentials for MCP servers.


General

If you're building an MCP server that connects to SAP, use this package. It gives you validated, type-safe configuration in both Go and Python with a single shared config file. No more reinventing credential loading, no more inconsistent formats between projects.

Both mcp-server-abap (Go) and sapgui.mcp (Python) use this package.

The default config path (~/.config/sap-mcp/systems.json) follows the XDG Base Directory Specification.

Features

  • One config file, two languages - Go and Python read the same config, guaranteed by shared test fixtures
  • JSON and YAML - use whichever format you prefer (auto-detected by file extension)
  • Validates eagerly - reports all errors at once so users fix everything in one pass
  • Passwords never leak in print/log output - masked in str()/repr()/fmt.Println()/fmt.Sprintf("%+v") (Go: fmt.Formatter; Python: pydantic.SecretStr)
  • Immutable after loading - frozen Pydantic models in Python; in Go, use the returned structs as read-only
  • .env file support - SAP_CONFIG_FILE can be set in a .env file
  • Easy to extend - subclass SAPSystem in Python or embed the struct in Go to add project-specific fields

License

MIT


Users

This section covers everything you need to connect an MCP server to your SAP system. No programming knowledge required.

[!NOTE] Why a separate file for credentials? Most MCP tools put credentials directly in each project's MCP config (env block), which means re-entering them for every tool you install. This package separates SAP credentials into a single shared file (systems.json) so that multiple MCP servers - like sapgui.mcp and mcp-server-abap - can all read the same credentials without duplication.

Configuration File

Create ~/.config/sap-mcp/systems.json (or systems.yaml - format is auto-detected by file extension):

[!NOTE] On Windows, ~ resolves to %USERPROFILE%, so the default path is %USERPROFILE%\.config\sap-mcp\systems.json.

JSON

{
  "default_system": "dev",
  "systems": {
    "dev": {
      "connection_name": "DEV - ERP Development",
      "host": "https://your-sap-system:44300",
      "client": "100",
      "user": "YOUR_USER",
      "password": "YOUR_PASSWORD",
      "language": "DE"
    },
    "prod": {
      "connection_name": "PROD - ERP Production",
      "host": "https://prod-sap:44300",
      "client": "200",
      "user": "PROD_USER",
      "password": "PROD_PASSWORD",
      "language": "EN"
    }
  }
}

YAML

default_system: dev
systems:
  dev:
    connection_name: "DEV - ERP Development"
    host: "https://your-sap-system:44300"
    client: "100"
    user: YOUR_USER
    password: YOUR_PASSWORD
    language: DE
  prod:
    connection_name: "PROD - ERP Production"
    host: "https://prod-sap:44300"
    client: "200"
    user: PROD_USER
    password: PROD_PASSWORD
    language: EN

[!TIP] Override the config file location via the SAP_CONFIG_FILE environment variable:

export SAP_CONFIG_FILE=/path/to/my/config.yaml

This also works from a .env file in the current directory.

Fields

Field Type Required Default Description
connection_name string no "" SAP Logon connection entry name - must match the bold description text shown in the SAP Logon pad, not the System ID (SID). Used by desktop backends (e.g. SAP GUI) to open the correct connection. (See Finding your connection_name below.)
host string yes SAP system base URL (must start with http:// or https://)
client string no "" SAP client/mandant, must be exactly 3 digits (e.g. "100")
user string conditional "" SAP username (omit for OAuth2)
password string conditional "" SAP password (omit for OAuth2)
language string no "EN" Login language: "DE" or "EN"
tls_skip_verify bool no false Skip TLS certificate verification
oauth2_client_id string no "" OAuth2 client ID for token-based auth

Validation rules:

  • At least one system must be defined
  • default_system must reference an existing system key
  • host is required and must start with http:// or https://
  • client, if set, must be exactly 3 digits
  • language, if set, must be "DE" or "EN"
  • Either both user and password must be set, or neither (for OAuth2)

Finding your connection_name in SAP Logon

Open the SAP Logon pad - your systems appear in a table. The connection_name is the text in the Description or Name column (the leftmost column with the bold/display name). It is not the short System ID (SID):

Description or Name - use this as connection_name System ID (SID) Instance Number Message Server
Production S/4HANA PRD 00 prd-ms...
DEV - ERP Development DEV 00 dev-ms...
QA System QAS 01 qa-ms...

SAP Logon pad showing Description/Name, System ID, Instance Number, and Message Server columns

[!IMPORTANT] Copy the Description/Name text exactly as it appears - spaces, slashes, and capitalisation all matter. If the value in connection_name doesn't match exactly, the server will return "SAP Logon connection entry not found".

[!NOTE] connection_name is only used by the Desktop backend (SAP GUI desktop client). The WebGUI backend connects directly to host and does not use SAP Logon, so you can leave connection_name empty or omit it.

Multiple entries for the same SAP system

The dictionary key (e.g. "dev", "prod") is only used to look up systems in the config. It has no connection to the SAP system itself. The connection_name field is what identifies the SAP Logon entry for desktop backends. This distinction allows you to configure multiple entries for the same SAP system with different clients or credentials:

{
  "default_system": "dev-100",
  "systems": {
    "dev-100": {
      "connection_name": "DEV - ERP Development",
      "host": "https://dev-sap.example.com:44300",
      "client": "100",
      "user": "DEV_USER",
      "password": "DEV_PASSWORD"
    },
    "dev-200": {
      "connection_name": "DEV - ERP Development",
      "host": "https://dev-sap.example.com:44300",
      "client": "200",
      "user": "QA_USER",
      "password": "QA_PASSWORD"
    }
  }
}

Both entries share the same connection_name (same SAP Logon entry) but use different clients and credentials.

MCP JSON Configuration

Once your systems.json is ready, whoever configured the MCP server needs to point it at the credentials file via SAP_CONFIG_FILE. Both servers below read the same file - this is the key advantage over putting credentials in each server's env block separately:

{
  "mcpServers": {
    "sap-abap": {
      "command": "mcp-server-abap",
      "env": {
        "SAP_CONFIG_FILE": "/home/user/.config/sap-mcp/systems.json"
      }
    },
    "sap-webgui": {
      "command": "run-sapgui-mcp-server",
      "env": {
        "SAP_CONFIG_FILE": "/home/user/.config/sap-mcp/systems.json"
      }
    }
  }
}

[!TIP] Both servers read the same config file with the same credentials - no duplication needed.


Developers

This section is for developers building or extending MCP servers that use this package.

Python

Installation

pip install sap-mcp-config

Usage

import sys

from pydantic import ValidationError

from sap_mcp_config import load_default

try:
    # Load from SAP_CONFIG_FILE env var or ~/.config/sap-mcp/systems.json
    cfg = load_default()
except FileNotFoundError:
    print("Config file not found. Create ~/.config/sap-mcp/systems.json")
    sys.exit(1)
except ValidationError as e:
    print(f"Configuration error:\n{e}")
    sys.exit(1)

# Access the default system
dev = cfg.get_default()
print(dev.host, dev.client, dev.user)

# Access a specific system
prod = cfg.systems["prod"]
print(prod.host, prod.client, prod.user)

# Password is a SecretStr - it won't leak in print/logs
print(dev)  # password=SecretStr('**********')

# Access the actual password value when needed
password = dev.password.get_secret_value()

Extending the Configuration

Subclass SAPSystem to add your own fields:

from pydantic import ConfigDict
from sap_mcp_config import SAPSystem

class MySAPSystem(SAPSystem):
    model_config = ConfigDict()  # unfreeze for subclass

    custom_timeout: int = 30

Development

pip install -e ".[tests]"
PYTHONPATH=src pytest unittests

Or via tox:

pip install tox
tox -e tests       # unit tests
tox -e linting     # pylint
tox -e type_check  # mypy --strict
tox -e coverage    # coverage with 80% minimum

Go

Installation

go get github.com/Hochfrequenz/sap-mcp-config

Usage

package main

import (
    "fmt"
    "os"

    sapmcpconfig "github.com/Hochfrequenz/sap-mcp-config"
)

func main() {
    // Load from SAP_CONFIG_FILE env var or ~/.config/sap-mcp/systems.json
    cfg, err := sapmcpconfig.LoadDefault()
    if err != nil {
        fmt.Fprintf(os.Stderr, "Configuration error:\n%s\n", err)
        os.Exit(1)
    }

    // Access the default system
    dev := cfg.GetDefault()
    fmt.Println(dev.Host, dev.Client, dev.User)

    // Access a specific system
    prod := cfg.Systems["prod"]
    fmt.Println(prod.Host, prod.Client, prod.User)

    // Password is safe to print - it won't leak
    fmt.Println(dev) // Output: SAPSystem{ConnectionName:DEV - ERP Development Host:https://... Client:100 User:DEV_USER Password:*** Language:DE}
}

Extending the Configuration

Embed SAPSystem in your own struct:

type MySAPSystem struct {
    sapmcpconfig.SAPSystem
    CustomTimeout int `json:"custom_timeout"`
}

Development

go test ./...

Error Messages (Python and Go)

Both implementations validate eagerly and return all errors at once. A misconfigured file like this:

{
  "default_system": "missing",
  "systems": {
    "dev": { "host": "ftp://wrong", "client": "1", "user": "u" }
  }
}

...will report all problems in a single error:

invalid configuration:
  - default_system "missing" not found in systems
  - system "dev": host must start with http:// or https://, got "ftp://wrong"
  - system "dev": client must be a 3-digit string (e.g. "100"), got "1"
  - system "dev": must have both user and password, or neither (for OAuth2)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sap_mcp_config-1.0.0.tar.gz (50.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sap_mcp_config-1.0.0-py3-none-any.whl (9.3 kB view details)

Uploaded Python 3

File details

Details for the file sap_mcp_config-1.0.0.tar.gz.

File metadata

  • Download URL: sap_mcp_config-1.0.0.tar.gz
  • Upload date:
  • Size: 50.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sap_mcp_config-1.0.0.tar.gz
Algorithm Hash digest
SHA256 dcab4c345a7036835a3e39950b722d81b674d2c9bd38c484775994a1ae7ee867
MD5 14956008b0e5f866e16cc6758b852031
BLAKE2b-256 70946b1af3da2f4954697cc87f4e8fd533e4ebfc96b73ab4e435f8a83fa33442

See more details on using hashes here.

Provenance

The following attestation bundles were made for sap_mcp_config-1.0.0.tar.gz:

Publisher: python-publish.yml on Hochfrequenz/sap-mcp-config

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sap_mcp_config-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: sap_mcp_config-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 9.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sap_mcp_config-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5fc441af854296d87ba33d430dda70fe1bce0e48f7e74ca0d072e84d1425b37b
MD5 40f1cc39befb9e3dce5b8a5122fd83e2
BLAKE2b-256 5d9d4b3b6df90ccdff96229cd11ec4c219896d08f7fffdfc90f9da671fbd949b

See more details on using hashes here.

Provenance

The following attestation bundles were made for sap_mcp_config-1.0.0-py3-none-any.whl:

Publisher: python-publish.yml on Hochfrequenz/sap-mcp-config

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page