sap-mcp-config 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sap_mcp_config-0.0.2/.gitattributes +2 -0
- sap_mcp_config-0.0.2/.github/dependabot.yml +14 -0
- sap_mcp_config-0.0.2/.github/workflows/go-coverage.yml +26 -0
- sap_mcp_config-0.0.2/.github/workflows/go-lint.yml +26 -0
- sap_mcp_config-0.0.2/.github/workflows/go-test.yml +23 -0
- sap_mcp_config-0.0.2/.github/workflows/packaging-test.yml +22 -0
- sap_mcp_config-0.0.2/.github/workflows/python-coverage.yml +22 -0
- sap_mcp_config-0.0.2/.github/workflows/python-formatting.yml +25 -0
- sap_mcp_config-0.0.2/.github/workflows/python-lint.yml +26 -0
- sap_mcp_config-0.0.2/.github/workflows/python-publish.yml +45 -0
- sap_mcp_config-0.0.2/.github/workflows/python-test.yml +26 -0
- sap_mcp_config-0.0.2/.gitignore +29 -0
- sap_mcp_config-0.0.2/LICENSE +21 -0
- sap_mcp_config-0.0.2/PKG-INFO +318 -0
- sap_mcp_config-0.0.2/README.md +277 -0
- sap_mcp_config-0.0.2/config.go +166 -0
- sap_mcp_config-0.0.2/config_test.go +220 -0
- sap_mcp_config-0.0.2/domain-specific-terms.txt +3 -0
- sap_mcp_config-0.0.2/go.mod +14 -0
- sap_mcp_config-0.0.2/go.sum +12 -0
- sap_mcp_config-0.0.2/pyproject.toml +92 -0
- sap_mcp_config-0.0.2/src/_sap_mcp_config_version.py +1 -0
- sap_mcp_config-0.0.2/src/sap_mcp_config/__init__.py +5 -0
- sap_mcp_config-0.0.2/src/sap_mcp_config/models.py +111 -0
- sap_mcp_config-0.0.2/src/sap_mcp_config/py.typed +0 -0
- sap_mcp_config-0.0.2/testdata/special_characters.json +26 -0
- sap_mcp_config-0.0.2/testdata/systems.json +27 -0
- sap_mcp_config-0.0.2/tox.ini +59 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "gomod"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
- package-ecosystem: "pip"
|
|
8
|
+
directory: "/"
|
|
9
|
+
schedule:
|
|
10
|
+
interval: "weekly"
|
|
11
|
+
- package-ecosystem: "github-actions"
|
|
12
|
+
directory: "/"
|
|
13
|
+
schedule:
|
|
14
|
+
interval: "weekly"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: "Go Coverage"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request: {}
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
coverage:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- name: Install Go
|
|
13
|
+
uses: actions/setup-go@v6
|
|
14
|
+
with:
|
|
15
|
+
go-version: "1.26.x"
|
|
16
|
+
- name: Checkout Code
|
|
17
|
+
uses: actions/checkout@v6
|
|
18
|
+
- name: Calc coverage
|
|
19
|
+
run: go test ./... -v -covermode=count -coverprofile=coverage.out
|
|
20
|
+
- name: Convert coverage to lcov
|
|
21
|
+
uses: jandelgado/gcov2lcov-action@v1.2.0
|
|
22
|
+
- name: Enforce Min Coverage
|
|
23
|
+
uses: VeryGoodOpenSource/very_good_coverage@v3.0.0
|
|
24
|
+
with:
|
|
25
|
+
path: "coverage.lcov"
|
|
26
|
+
min_coverage: 80
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: "Go Lint"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request: {}
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
golangci:
|
|
8
|
+
strategy:
|
|
9
|
+
matrix:
|
|
10
|
+
go-version: ["1.26.x"]
|
|
11
|
+
os: [ubuntu-latest]
|
|
12
|
+
runs-on: ${{ matrix.os }}
|
|
13
|
+
name: lint
|
|
14
|
+
steps:
|
|
15
|
+
- name: Install Go
|
|
16
|
+
uses: actions/setup-go@v6
|
|
17
|
+
with:
|
|
18
|
+
go-version: ${{ matrix.go-version }}
|
|
19
|
+
- uses: actions/checkout@v6
|
|
20
|
+
- name: golangci-lint
|
|
21
|
+
uses: golangci/golangci-lint-action@v9
|
|
22
|
+
with:
|
|
23
|
+
version: v2.11.4
|
|
24
|
+
args: --enable dupl,goconst,gocyclo
|
|
25
|
+
- name: fmt
|
|
26
|
+
run: golangci-lint fmt --diff --enable gofmt
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: "Go Tests"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request: {}
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
strategy:
|
|
11
|
+
matrix:
|
|
12
|
+
go-version: ["1.25.x", "1.26.x"]
|
|
13
|
+
os: [ubuntu-latest]
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
steps:
|
|
16
|
+
- name: Install Go
|
|
17
|
+
uses: actions/setup-go@v6
|
|
18
|
+
with:
|
|
19
|
+
go-version: ${{ matrix.go-version }}
|
|
20
|
+
- name: Checkout code
|
|
21
|
+
uses: actions/checkout@v6
|
|
22
|
+
- name: Test
|
|
23
|
+
run: go test ./...
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: "Packaging Test"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request: {}
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
check_packaging:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v6
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: actions/setup-python@v6
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.14"
|
|
17
|
+
- name: Install dependencies
|
|
18
|
+
run: |
|
|
19
|
+
python -m pip install --upgrade pip
|
|
20
|
+
pip install tox
|
|
21
|
+
- name: Run Packaging Test
|
|
22
|
+
run: tox -e test_packaging
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: "Python Coverage"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request: {}
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
coverage:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v6
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: actions/setup-python@v6
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.14"
|
|
17
|
+
- name: Install dependencies
|
|
18
|
+
run: |
|
|
19
|
+
python -m pip install --upgrade pip
|
|
20
|
+
pip install tox
|
|
21
|
+
- name: Run Tests and Record Coverage
|
|
22
|
+
run: tox -e coverage
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: "Python Formatting"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request: {}
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
format:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
tool: ["black", "isort"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
|
+
- name: Set up Python
|
|
17
|
+
uses: actions/setup-python@v6
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.14"
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: |
|
|
22
|
+
python -m pip install --upgrade pip
|
|
23
|
+
pip install .[formatting]
|
|
24
|
+
- name: ${{ matrix.tool }} Code Formatter
|
|
25
|
+
run: ${{ matrix.tool }} . --check
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: "Python Lint"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request: {}
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
pylint:
|
|
10
|
+
name: Python Code Quality and Lint
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
linter-env: ["linting", "type_check", "spell_check"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v6
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.14"
|
|
21
|
+
- name: Install Dependencies
|
|
22
|
+
run: |
|
|
23
|
+
python -m pip install --upgrade pip
|
|
24
|
+
pip install tox
|
|
25
|
+
- name: Run ${{ matrix.linter-env }} via Tox
|
|
26
|
+
run: tox -e ${{ matrix.linter-env }}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: "Publish to PyPI"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [created, edited]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
tests:
|
|
9
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v6
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: actions/setup-python@v6
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.14"
|
|
17
|
+
- name: Install tox
|
|
18
|
+
run: |
|
|
19
|
+
python -m pip install --upgrade pip
|
|
20
|
+
pip install tox
|
|
21
|
+
- name: Run tox
|
|
22
|
+
run: tox
|
|
23
|
+
|
|
24
|
+
build-n-publish:
|
|
25
|
+
name: Build and publish Python distributions to PyPI
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
environment: release
|
|
28
|
+
permissions:
|
|
29
|
+
id-token: write
|
|
30
|
+
needs: tests
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v6
|
|
33
|
+
- name: Set up Python
|
|
34
|
+
uses: actions/setup-python@v6
|
|
35
|
+
with:
|
|
36
|
+
python-version: "3.14"
|
|
37
|
+
- name: Install dependencies
|
|
38
|
+
run: |
|
|
39
|
+
python -m pip install --upgrade pip
|
|
40
|
+
pip install .[packaging]
|
|
41
|
+
- name: Build wheel and source distributions
|
|
42
|
+
run: python -m build
|
|
43
|
+
- name: Publish distribution to PyPI
|
|
44
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
45
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: "Python Tests"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request: {}
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
pytest:
|
|
10
|
+
runs-on: ${{ matrix.os }}
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
14
|
+
os: [ubuntu-latest]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
18
|
+
uses: actions/setup-python@v6
|
|
19
|
+
with:
|
|
20
|
+
python-version: ${{ matrix.python-version }}
|
|
21
|
+
- name: Install Dependencies
|
|
22
|
+
run: |
|
|
23
|
+
python -m pip install --upgrade pip
|
|
24
|
+
pip install tox
|
|
25
|
+
- name: Run the Unit Tests via Tox
|
|
26
|
+
run: tox -e tests
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Go
|
|
2
|
+
*.exe
|
|
3
|
+
*.exe~
|
|
4
|
+
*.dll
|
|
5
|
+
*.so
|
|
6
|
+
*.dylib
|
|
7
|
+
*.test
|
|
8
|
+
*.out
|
|
9
|
+
|
|
10
|
+
# Python
|
|
11
|
+
__pycache__/
|
|
12
|
+
*.py[cod]
|
|
13
|
+
*.egg-info/
|
|
14
|
+
dist/
|
|
15
|
+
build/
|
|
16
|
+
.tox/
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
htmlcov/
|
|
19
|
+
.coverage
|
|
20
|
+
src/_sap_mcp_config_version.py
|
|
21
|
+
|
|
22
|
+
# IDE
|
|
23
|
+
.idea/
|
|
24
|
+
.vscode/
|
|
25
|
+
*.swp
|
|
26
|
+
|
|
27
|
+
# Env
|
|
28
|
+
.env
|
|
29
|
+
.venv/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hochfrequenz Unternehmensberatung GmbH
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sap-mcp-config
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Shared configuration models for MCP servers that connect to SAP systems
|
|
5
|
+
Project-URL: Changelog, https://github.com/Hochfrequenz/sap-mcp-config/releases
|
|
6
|
+
Project-URL: Homepage, https://github.com/Hochfrequenz/sap-mcp-config
|
|
7
|
+
Author-email: Hochfrequenz Unternehmensberatung GmbH <info+github@hochfrequenz.de>
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: configuration,mcp,sap
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: pydantic>=2
|
|
23
|
+
Requires-Dist: python-dotenv>=1
|
|
24
|
+
Provides-Extra: coverage
|
|
25
|
+
Requires-Dist: coverage==7.13.5; extra == 'coverage'
|
|
26
|
+
Provides-Extra: formatting
|
|
27
|
+
Requires-Dist: black==26.3.1; extra == 'formatting'
|
|
28
|
+
Requires-Dist: isort==8.0.1; extra == 'formatting'
|
|
29
|
+
Provides-Extra: linting
|
|
30
|
+
Requires-Dist: pylint==4.0.5; extra == 'linting'
|
|
31
|
+
Provides-Extra: packaging
|
|
32
|
+
Requires-Dist: build==1.4.2; extra == 'packaging'
|
|
33
|
+
Requires-Dist: twine==6.2.0; extra == 'packaging'
|
|
34
|
+
Provides-Extra: spell-check
|
|
35
|
+
Requires-Dist: codespell==2.4.2; extra == 'spell-check'
|
|
36
|
+
Provides-Extra: tests
|
|
37
|
+
Requires-Dist: pytest==9.0.2; extra == 'tests'
|
|
38
|
+
Provides-Extra: type-check
|
|
39
|
+
Requires-Dist: mypy==1.20.0; extra == 'type-check'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# sap-mcp-config
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+

|
|
46
|
+

|
|
47
|
+
[](https://pkg.go.dev/github.com/Hochfrequenz/sap-mcp-config)
|
|
48
|
+
[](https://goreportcard.com/report/github.com/Hochfrequenz/sap-mcp-config)
|
|
49
|
+

|
|
50
|
+

|
|
51
|
+

|
|
52
|
+

|
|
53
|
+

|
|
54
|
+

|
|
55
|
+
|
|
56
|
+
**The standard way to manage SAP credentials for MCP servers.**
|
|
57
|
+
|
|
58
|
+
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.
|
|
59
|
+
|
|
60
|
+
Both [mcp-server-abap](https://github.com/Hochfrequenz/mcp-server-abap) (Go) and [sapwebgui.mcp](https://github.com/Hochfrequenz/sapwebgui.mcp) (Python) use this package.
|
|
61
|
+
|
|
62
|
+
The default config path (`~/.config/sap-mcp/systems.json`) follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/latest/).
|
|
63
|
+
|
|
64
|
+
## Features
|
|
65
|
+
|
|
66
|
+
- **One config file, two languages** — Go and Python read the same JSON, guaranteed by shared test fixtures
|
|
67
|
+
- **Validates eagerly** — reports _all_ errors at once so users fix everything in one pass
|
|
68
|
+
- **Passwords never leak in print/log output** — masked in `str()`/`repr()`/`fmt.Println()`/`fmt.Sprintf("%+v")` (Go: `fmt.Formatter`; Python: `pydantic.SecretStr`)
|
|
69
|
+
- **Immutable after loading** — frozen Pydantic models in Python; in Go, use the returned structs as read-only
|
|
70
|
+
- **`.env` file support** — `SAP_CONFIG_FILE` can be set in a `.env` file
|
|
71
|
+
- **Easy to extend** — subclass `SAPSystem` in Python or embed the struct in Go to add project-specific fields
|
|
72
|
+
|
|
73
|
+
## MCP JSON Configuration
|
|
74
|
+
|
|
75
|
+
This package integrates naturally with the [MCP JSON configuration standard](https://modelcontextprotocol.io/docs/concepts/transports). Point your MCP server to the shared config file via the `SAP_CONFIG_FILE` environment variable:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"mcpServers": {
|
|
80
|
+
"sap-abap": {
|
|
81
|
+
"command": "mcp-server-abap",
|
|
82
|
+
"env": {
|
|
83
|
+
"SAP_CONFIG_FILE": "/home/user/.config/sap-mcp/systems.json"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"sap-webgui": {
|
|
87
|
+
"command": "sapwebgui-mcp",
|
|
88
|
+
"env": {
|
|
89
|
+
"SAP_CONFIG_FILE": "/home/user/.config/sap-mcp/systems.json"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Both servers read the **same config file** with the **same credentials** — no duplication.
|
|
97
|
+
|
|
98
|
+
## Installation
|
|
99
|
+
|
|
100
|
+
### Go
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
go get github.com/Hochfrequenz/sap-mcp-config
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Python
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pip install sap-mcp-config
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Configuration File
|
|
113
|
+
|
|
114
|
+
Create `~/.config/sap-mcp/systems.json`:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"default_system": "dev",
|
|
119
|
+
"systems": {
|
|
120
|
+
"dev": {
|
|
121
|
+
"host": "https://your-sap-system:44300",
|
|
122
|
+
"client": "100",
|
|
123
|
+
"user": "YOUR_USER",
|
|
124
|
+
"password": "YOUR_PASSWORD",
|
|
125
|
+
"language": "DE"
|
|
126
|
+
},
|
|
127
|
+
"prod": {
|
|
128
|
+
"host": "https://prod-sap:44300",
|
|
129
|
+
"client": "200",
|
|
130
|
+
"user": "PROD_USER",
|
|
131
|
+
"password": "PROD_PASSWORD",
|
|
132
|
+
"language": "EN"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Override the config file location via the `SAP_CONFIG_FILE` environment variable:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
export SAP_CONFIG_FILE=/path/to/my/config.json
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
This also works from a `.env` file in the current directory.
|
|
145
|
+
|
|
146
|
+
### Fields
|
|
147
|
+
|
|
148
|
+
| Field | Type | Required | Default | Description |
|
|
149
|
+
|-------|------|----------|---------|-------------|
|
|
150
|
+
| `host` | string | yes | | SAP system base URL (must start with `http://` or `https://`) |
|
|
151
|
+
| `client` | string | no | `""` | SAP client/mandant, must be exactly 3 digits (e.g. `"100"`) |
|
|
152
|
+
| `user` | string | conditional | `""` | SAP username (omit for OAuth2) |
|
|
153
|
+
| `password` | string | conditional | `""` | SAP password (omit for OAuth2) |
|
|
154
|
+
| `language` | string | no | `"EN"` | Login language: `"DE"` or `"EN"` |
|
|
155
|
+
| `tls_skip_verify` | bool | no | `false` | Skip TLS certificate verification |
|
|
156
|
+
| `oauth2_client_id` | string | no | `""` | OAuth2 client ID for token-based auth |
|
|
157
|
+
|
|
158
|
+
**Validation rules:**
|
|
159
|
+
- At least one system must be defined
|
|
160
|
+
- `default_system` must reference an existing system
|
|
161
|
+
- `host` is required and must start with `http://` or `https://`
|
|
162
|
+
- `client`, if set, must be exactly 3 digits
|
|
163
|
+
- `language`, if set, must be `"DE"` or `"EN"`
|
|
164
|
+
- Either both `user` and `password` must be set, or neither (for OAuth2)
|
|
165
|
+
|
|
166
|
+
## Usage
|
|
167
|
+
|
|
168
|
+
### Go
|
|
169
|
+
|
|
170
|
+
```go
|
|
171
|
+
package main
|
|
172
|
+
|
|
173
|
+
import (
|
|
174
|
+
"fmt"
|
|
175
|
+
"os"
|
|
176
|
+
|
|
177
|
+
sapmcpconfig "github.com/Hochfrequenz/sap-mcp-config"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
func main() {
|
|
181
|
+
// Load from SAP_CONFIG_FILE env var or ~/.config/sap-mcp/systems.json
|
|
182
|
+
cfg, err := sapmcpconfig.LoadDefault()
|
|
183
|
+
if err != nil {
|
|
184
|
+
fmt.Fprintf(os.Stderr, "Configuration error:\n%s\n", err)
|
|
185
|
+
os.Exit(1)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Access the default system
|
|
189
|
+
dev := cfg.GetDefault()
|
|
190
|
+
fmt.Println(dev.Host, dev.Client, dev.User)
|
|
191
|
+
|
|
192
|
+
// Access a specific system
|
|
193
|
+
prod := cfg.Systems["prod"]
|
|
194
|
+
fmt.Println(prod.Host, prod.Client, prod.User)
|
|
195
|
+
|
|
196
|
+
// Password is safe to print — it won't leak
|
|
197
|
+
fmt.Println(dev) // Output: SAPSystem{Host:https://... Client:100 User:DEV_USER Password:*** Language:DE}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Python
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
import sys
|
|
205
|
+
|
|
206
|
+
from pydantic import ValidationError
|
|
207
|
+
|
|
208
|
+
from sap_mcp_config import load_default
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
# Load from SAP_CONFIG_FILE env var or ~/.config/sap-mcp/systems.json
|
|
212
|
+
cfg = load_default()
|
|
213
|
+
except FileNotFoundError:
|
|
214
|
+
print("Config file not found. Create ~/.config/sap-mcp/systems.json")
|
|
215
|
+
sys.exit(1)
|
|
216
|
+
except ValidationError as e:
|
|
217
|
+
print(f"Configuration error:\n{e}")
|
|
218
|
+
sys.exit(1)
|
|
219
|
+
|
|
220
|
+
# Access the default system
|
|
221
|
+
dev = cfg.get_default()
|
|
222
|
+
print(dev.host, dev.client, dev.user)
|
|
223
|
+
|
|
224
|
+
# Access a specific system
|
|
225
|
+
prod = cfg.systems["prod"]
|
|
226
|
+
print(prod.host, prod.client, prod.user)
|
|
227
|
+
|
|
228
|
+
# Password is a SecretStr — it won't leak in print/logs
|
|
229
|
+
print(dev) # password=SecretStr('**********')
|
|
230
|
+
|
|
231
|
+
# Access the actual password value when needed
|
|
232
|
+
password = dev.password.get_secret_value()
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Error Messages
|
|
236
|
+
|
|
237
|
+
Both implementations validate eagerly and return **all** errors at once. A misconfigured file like this:
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"default_system": "missing",
|
|
242
|
+
"systems": {
|
|
243
|
+
"dev": { "host": "ftp://wrong", "client": "1", "user": "u" }
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
...will report all problems in a single error:
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
invalid configuration:
|
|
252
|
+
- default_system "missing" not found in systems
|
|
253
|
+
- system "dev": host must start with http:// or https://, got "ftp://wrong"
|
|
254
|
+
- system "dev": client must be a 3-digit string (e.g. "100"), got "1"
|
|
255
|
+
- system "dev": must have both user and password, or neither (for OAuth2)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
This way users fix everything in one pass instead of playing whack-a-mole.
|
|
259
|
+
|
|
260
|
+
## Extending the Configuration
|
|
261
|
+
|
|
262
|
+
Both languages make it easy to add project-specific fields on top of the shared base.
|
|
263
|
+
|
|
264
|
+
### Python
|
|
265
|
+
|
|
266
|
+
Subclass `SAPSystem` to add your own fields:
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
from pydantic import ConfigDict
|
|
270
|
+
from sap_mcp_config import SAPSystem
|
|
271
|
+
|
|
272
|
+
class MySAPSystem(SAPSystem):
|
|
273
|
+
model_config = ConfigDict() # unfreeze for subclass
|
|
274
|
+
|
|
275
|
+
connection_name: str = ""
|
|
276
|
+
custom_timeout: int = 30
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Go
|
|
280
|
+
|
|
281
|
+
Embed `SAPSystem` in your own struct:
|
|
282
|
+
|
|
283
|
+
```go
|
|
284
|
+
type MySAPSystem struct {
|
|
285
|
+
sapmcpconfig.SAPSystem
|
|
286
|
+
ConnectionName string `json:"connection_name"`
|
|
287
|
+
CustomTimeout int `json:"custom_timeout"`
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Development
|
|
292
|
+
|
|
293
|
+
### Go
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
go test ./...
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Python
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
pip install -e ".[tests]"
|
|
303
|
+
PYTHONPATH=src pytest unittests
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Or via tox:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
pip install tox
|
|
310
|
+
tox -e tests # unit tests
|
|
311
|
+
tox -e linting # pylint
|
|
312
|
+
tox -e type_check # mypy --strict
|
|
313
|
+
tox -e coverage # coverage with 80% minimum
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## License
|
|
317
|
+
|
|
318
|
+
MIT
|