Shared configuration models for MCP servers that connect to SAP systems
Project description
sap-mcp-config
The standard way to manage SAP credentials for MCP servers.
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 sapwebgui.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
.envfile support —SAP_CONFIG_FILEcan be set in a.envfile- Easy to extend — subclass
SAPSystemin Python or embed the struct in Go to add project-specific fields
MCP JSON Configuration
This package integrates naturally with the MCP JSON configuration standard. Point your MCP server to the shared config file via the SAP_CONFIG_FILE environment variable:
{
"mcpServers": {
"sap-abap": {
"command": "mcp-server-abap",
"env": {
"SAP_CONFIG_FILE": "/home/user/.config/sap-mcp/systems.json"
}
},
"sap-webgui": {
"command": "sapwebgui-mcp",
"env": {
"SAP_CONFIG_FILE": "/home/user/.config/sap-mcp/systems.json"
}
}
}
}
Both servers read the same config file with the same credentials — no duplication.
Installation
Go
go get github.com/Hochfrequenz/sap-mcp-config
Python
pip install sap-mcp-config
Configuration File
Create ~/.config/sap-mcp/systems.json (or systems.yaml — format is auto-detected by extension):
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
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. |
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 |
Important: 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.
Validation rules:
- At least one system must be defined
default_systemmust reference an existing system keyhostis required and must start withhttp://orhttps://client, if set, must be exactly 3 digitslanguage, if set, must be"DE"or"EN"- Either both
userandpasswordmust be set, or neither (for OAuth2)
Usage
Go
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}
}
Python
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()
Error Messages
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)
This way users fix everything in one pass instead of playing whack-a-mole.
Extending the Configuration
Both languages make it easy to add project-specific fields on top of the shared base.
Python
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
Go
Embed SAPSystem in your own struct:
type MySAPSystem struct {
sapmcpconfig.SAPSystem
CustomTimeout int `json:"custom_timeout"`
}
Development
Go
go test ./...
Python
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
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sap_mcp_config-0.1.0.tar.gz.
File metadata
- Download URL: sap_mcp_config-0.1.0.tar.gz
- Upload date:
- Size: 17.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a0f54121315f472b58890f7ff990c12a0f404ebb1a67609f39ee88d5efb94d56
|
|
| MD5 |
3591453a26f408219cbcadf1dabff6fe
|
|
| BLAKE2b-256 |
065dd63cd5ef7f83196fd80f896b711ed3c0fd5efdf25a92601e361503de5d6d
|
Provenance
The following attestation bundles were made for sap_mcp_config-0.1.0.tar.gz:
Publisher:
python-publish.yml on Hochfrequenz/sap-mcp-config
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sap_mcp_config-0.1.0.tar.gz -
Subject digest:
a0f54121315f472b58890f7ff990c12a0f404ebb1a67609f39ee88d5efb94d56 - Sigstore transparency entry: 1205972712
- Sigstore integration time:
-
Permalink:
Hochfrequenz/sap-mcp-config@6bd61555c9f647a0c3302b6e8cfed87ebd251638 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Hochfrequenz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@6bd61555c9f647a0c3302b6e8cfed87ebd251638 -
Trigger Event:
release
-
Statement type:
File details
Details for the file sap_mcp_config-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sap_mcp_config-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8f32d0d626c8565ffffa5869f3ad4d1dff3ce9bc008ef497ee06529898c02a8
|
|
| MD5 |
2c884b98304357d1a16c8939b2803009
|
|
| BLAKE2b-256 |
0eed39aacf15e63a3cc35ccabd17ff045c36eea3afd3e02dce24cf9ec4774efb
|
Provenance
The following attestation bundles were made for sap_mcp_config-0.1.0-py3-none-any.whl:
Publisher:
python-publish.yml on Hochfrequenz/sap-mcp-config
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sap_mcp_config-0.1.0-py3-none-any.whl -
Subject digest:
f8f32d0d626c8565ffffa5869f3ad4d1dff3ce9bc008ef497ee06529898c02a8 - Sigstore transparency entry: 1205972756
- Sigstore integration time:
-
Permalink:
Hochfrequenz/sap-mcp-config@6bd61555c9f647a0c3302b6e8cfed87ebd251638 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Hochfrequenz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@6bd61555c9f647a0c3302b6e8cfed87ebd251638 -
Trigger Event:
release
-
Statement type: