keycloak-mcp-server 0.1.0__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.
- keycloak_mcp_server-0.1.0/.containerignore +43 -0
- keycloak_mcp_server-0.1.0/.devcontainer/devcontainer.json +33 -0
- keycloak_mcp_server-0.1.0/.env.example +35 -0
- keycloak_mcp_server-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +101 -0
- keycloak_mcp_server-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- keycloak_mcp_server-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +79 -0
- keycloak_mcp_server-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +36 -0
- keycloak_mcp_server-0.1.0/.github/dependabot.yml +32 -0
- keycloak_mcp_server-0.1.0/.github/workflows/pre-commit.yml +35 -0
- keycloak_mcp_server-0.1.0/.github/workflows/publish-pypi.yml +89 -0
- keycloak_mcp_server-0.1.0/.github/workflows/stale.yml +46 -0
- keycloak_mcp_server-0.1.0/.github/workflows/test.yml +47 -0
- keycloak_mcp_server-0.1.0/.gitignore +71 -0
- keycloak_mcp_server-0.1.0/.pre-commit-config.yaml +47 -0
- keycloak_mcp_server-0.1.0/.python-version +1 -0
- keycloak_mcp_server-0.1.0/CHANGELOG.md +21 -0
- keycloak_mcp_server-0.1.0/CONTRIBUTING.md +253 -0
- keycloak_mcp_server-0.1.0/Containerfile +24 -0
- keycloak_mcp_server-0.1.0/LICENSE +201 -0
- keycloak_mcp_server-0.1.0/Makefile +105 -0
- keycloak_mcp_server-0.1.0/PKG-INFO +294 -0
- keycloak_mcp_server-0.1.0/README.md +262 -0
- keycloak_mcp_server-0.1.0/SECURITY.md +57 -0
- keycloak_mcp_server-0.1.0/compose.yaml +26 -0
- keycloak_mcp_server-0.1.0/deployment/openshift/buildconfig.yaml +29 -0
- keycloak_mcp_server-0.1.0/deployment/openshift/configmap.yaml +22 -0
- keycloak_mcp_server-0.1.0/deployment/openshift/deployment.yaml +69 -0
- keycloak_mcp_server-0.1.0/deployment/openshift/imagestream.yaml +10 -0
- keycloak_mcp_server-0.1.0/deployment/openshift/kustomization.yaml +16 -0
- keycloak_mcp_server-0.1.0/deployment/openshift/pvc.yaml +13 -0
- keycloak_mcp_server-0.1.0/deployment/openshift/route.yaml +16 -0
- keycloak_mcp_server-0.1.0/deployment/openshift/secret.yaml +14 -0
- keycloak_mcp_server-0.1.0/deployment/openshift/service.yaml +17 -0
- keycloak_mcp_server-0.1.0/docs/architecture.md +276 -0
- keycloak_mcp_server-0.1.0/docs/authentication.md +194 -0
- keycloak_mcp_server-0.1.0/docs/ci-cd.md +92 -0
- keycloak_mcp_server-0.1.0/docs/deployment.md +79 -0
- keycloak_mcp_server-0.1.0/docs/development.md +245 -0
- keycloak_mcp_server-0.1.0/docs/keycloak-tools.md +124 -0
- keycloak_mcp_server-0.1.0/docs/tutorial.md +201 -0
- keycloak_mcp_server-0.1.0/examples/README.md +106 -0
- keycloak_mcp_server-0.1.0/examples/fastmcp_client.py +109 -0
- keycloak_mcp_server-0.1.0/examples/keycloak_client.py +66 -0
- keycloak_mcp_server-0.1.0/examples/langgraph_client.py +247 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/__init__.py +3 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/py.typed +0 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/README.md +35 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/__init__.py +1 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/api.py +64 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/assets/README.md +83 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/keycloak_api/__init__.py +1 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/keycloak_api/auth.py +202 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/keycloak_api/service.py +190 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/main.py +144 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/mcp.py +54 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/settings.py +206 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/tools/README.md +84 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/tools/__init__.py +1 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/src/tools/keycloak_tools.py +593 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/utils/__init__.py +1 -0
- keycloak_mcp_server-0.1.0/keycloak_mcp_server/utils/pylogger.py +204 -0
- keycloak_mcp_server-0.1.0/pyproject.toml +125 -0
- keycloak_mcp_server-0.1.0/tests/README.md +129 -0
- keycloak_mcp_server-0.1.0/tests/conftest.py +163 -0
- keycloak_mcp_server-0.1.0/tests/test_api.py +160 -0
- keycloak_mcp_server-0.1.0/tests/test_auth_discovery.py +63 -0
- keycloak_mcp_server-0.1.0/tests/test_basic.py +299 -0
- keycloak_mcp_server-0.1.0/tests/test_keycloak.py +469 -0
- keycloak_mcp_server-0.1.0/tests/test_keycloak_oauth.py +417 -0
- keycloak_mcp_server-0.1.0/tests/test_main.py +307 -0
- keycloak_mcp_server-0.1.0/tests/test_mcp.py +128 -0
- keycloak_mcp_server-0.1.0/tests/test_settings.py +159 -0
- keycloak_mcp_server-0.1.0/tests/test_utils.py +580 -0
- keycloak_mcp_server-0.1.0/uv.lock +3220 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Git and version control
|
|
2
|
+
.git/
|
|
3
|
+
.gitignore
|
|
4
|
+
.gitlab-ci.yml
|
|
5
|
+
|
|
6
|
+
# Python cache and build artifacts
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*$py.class
|
|
10
|
+
.pytest_cache/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
build/
|
|
13
|
+
dist/
|
|
14
|
+
|
|
15
|
+
# IDE and editor files
|
|
16
|
+
.cursor/
|
|
17
|
+
.vscode/
|
|
18
|
+
*.swp
|
|
19
|
+
*.swo
|
|
20
|
+
*~
|
|
21
|
+
|
|
22
|
+
# Development and documentation
|
|
23
|
+
LICENSE
|
|
24
|
+
Makefile
|
|
25
|
+
.pre-commit-config.yaml
|
|
26
|
+
|
|
27
|
+
# OS generated files
|
|
28
|
+
.DS_Store
|
|
29
|
+
.DS_Store?
|
|
30
|
+
._*
|
|
31
|
+
Thumbs.db
|
|
32
|
+
|
|
33
|
+
# Local environment, credentials, and OAuth state
|
|
34
|
+
.env
|
|
35
|
+
.venv/
|
|
36
|
+
.keycloak-oauth/
|
|
37
|
+
|
|
38
|
+
# Test files (optional - remove if you want tests in container)
|
|
39
|
+
tests/
|
|
40
|
+
|
|
41
|
+
# Container files themselves
|
|
42
|
+
Containerfile
|
|
43
|
+
.containerignore
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Keycloak MCP Server",
|
|
3
|
+
"image": "mcr.microsoft.com/devcontainers/python:3.12",
|
|
4
|
+
"postCreateCommand": "curl -LsSf https://astral.sh/uv/install.sh | sh && \"$HOME/.local/bin/uv\" sync --locked && \"$HOME/.local/bin/uv\" run --locked pre-commit install && if [ ! -f .env ]; then cp .env.example .env; fi",
|
|
5
|
+
"customizations": {
|
|
6
|
+
"vscode": {
|
|
7
|
+
"settings": {
|
|
8
|
+
"python.defaultInterpreterPath": ".venv/bin/python",
|
|
9
|
+
"python.terminal.activateEnvironment": false,
|
|
10
|
+
"[python]": {
|
|
11
|
+
"editor.defaultFormatter": "charliermarsh.ruff",
|
|
12
|
+
"editor.formatOnSave": true
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"extensions": [
|
|
16
|
+
"charliermarsh.ruff",
|
|
17
|
+
"ms-python.python",
|
|
18
|
+
"ms-python.mypy-type-checker",
|
|
19
|
+
"ms-python.debugpy",
|
|
20
|
+
"tamasfe.even-better-toml"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"forwardPorts": [
|
|
25
|
+
5001
|
|
26
|
+
],
|
|
27
|
+
"containerEnv": {
|
|
28
|
+
"PYTHONPATH": "${containerWorkspaceFolder}"
|
|
29
|
+
},
|
|
30
|
+
"remoteEnv": {
|
|
31
|
+
"PATH": "${containerEnv:HOME}/.local/bin:${containerEnv:PATH}"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Copy to .env. Discovery-only mode works without Keycloak credentials.
|
|
2
|
+
MCP_HOST=localhost
|
|
3
|
+
MCP_PORT=5001
|
|
4
|
+
MCP_HOST_ENDPOINT=http://localhost:5001
|
|
5
|
+
# http and streamable-http both use /mcp; sse is the legacy /sse transport.
|
|
6
|
+
MCP_TRANSPORT_PROTOCOL=http
|
|
7
|
+
ENABLE_AUTH=False
|
|
8
|
+
ENVIRONMENT=development
|
|
9
|
+
PYTHON_LOG_LEVEL=INFO
|
|
10
|
+
|
|
11
|
+
# For browser OAuth, enable ENABLE_AUTH and configure the persistent signing key.
|
|
12
|
+
# Register a public keycloak-mcp client in your realm, with redirect:
|
|
13
|
+
# http://localhost:5001/auth/callback (see docs/authentication.md)
|
|
14
|
+
# Base URL before /realms; legacy WildFly distributions add /auth.
|
|
15
|
+
KEYCLOAK_SERVER_URL=https://keycloak.example.com
|
|
16
|
+
KEYCLOAK_REALM=myrealm
|
|
17
|
+
KEYCLOAK_OAUTH_CLIENT_ID=keycloak-mcp
|
|
18
|
+
# Public client: no Keycloak client secret.
|
|
19
|
+
# Optional only for a confidential upstream client:
|
|
20
|
+
# KEYCLOAK_OAUTH_CLIENT_SECRET=
|
|
21
|
+
# Generate once: uv run python -c 'import secrets; print(secrets.token_urlsafe(48))'
|
|
22
|
+
# KEYCLOAK_OAUTH_SIGNING_KEY=
|
|
23
|
+
# Add an audience mapper for the client's own ID and require it here.
|
|
24
|
+
KEYCLOAK_OAUTH_AUDIENCE=keycloak-mcp
|
|
25
|
+
KEYCLOAK_OAUTH_SCOPES="openid profile email"
|
|
26
|
+
KEYCLOAK_OAUTH_STORAGE_DIR=.keycloak-oauth
|
|
27
|
+
KEYCLOAK_TIMEOUT=30
|
|
28
|
+
# TLS verification stays enabled; use a PEM bundle for internal certificate issuers.
|
|
29
|
+
# KEYCLOAK_CA_BUNDLE=/path/to/trusted-ca-bundle.pem
|
|
30
|
+
# Downstream clients use random loopback callback ports; these defaults allow them.
|
|
31
|
+
# KEYCLOAK_OAUTH_CLIENT_REDIRECT_URIS=["http://localhost:*/*","http://127.0.0.1:*/*"]
|
|
32
|
+
|
|
33
|
+
# Optional single-user localhost shortcut with ENABLE_AUTH=False only.
|
|
34
|
+
# Must be removed before enabling OAuth. No service-account login is performed.
|
|
35
|
+
# KEYCLOAK_DEV_ACCESS_TOKEN=
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: Report a bug or unexpected behavior.
|
|
3
|
+
title: "[Bug]: "
|
|
4
|
+
labels: ["type/bug", "status/triage"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for reporting a bug! Please fill out the sections below so we can reproduce and fix it.
|
|
10
|
+
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: description
|
|
13
|
+
attributes:
|
|
14
|
+
label: Describe the bug
|
|
15
|
+
description: A clear and concise description of what the bug is.
|
|
16
|
+
placeholder: When I call the multiply tool with...
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: steps
|
|
22
|
+
attributes:
|
|
23
|
+
label: Steps to reproduce
|
|
24
|
+
description: Minimal steps to reproduce the behavior.
|
|
25
|
+
placeholder: |
|
|
26
|
+
1. Start the server with `make local`
|
|
27
|
+
2. Send a request to `/mcp` with payload...
|
|
28
|
+
3. Observe the error...
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
|
|
32
|
+
- type: textarea
|
|
33
|
+
id: expected
|
|
34
|
+
attributes:
|
|
35
|
+
label: Expected behavior
|
|
36
|
+
description: What did you expect to happen?
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
39
|
+
|
|
40
|
+
- type: textarea
|
|
41
|
+
id: actual
|
|
42
|
+
attributes:
|
|
43
|
+
label: Actual behavior
|
|
44
|
+
description: What actually happened? Include error messages or logs if available.
|
|
45
|
+
validations:
|
|
46
|
+
required: true
|
|
47
|
+
|
|
48
|
+
- type: input
|
|
49
|
+
id: version
|
|
50
|
+
attributes:
|
|
51
|
+
label: Version
|
|
52
|
+
description: Which version of the server are you running?
|
|
53
|
+
placeholder: "0.1.0"
|
|
54
|
+
validations:
|
|
55
|
+
required: true
|
|
56
|
+
|
|
57
|
+
- type: dropdown
|
|
58
|
+
id: transport
|
|
59
|
+
attributes:
|
|
60
|
+
label: Transport protocol
|
|
61
|
+
description: Which transport protocol are you using?
|
|
62
|
+
options:
|
|
63
|
+
- streamable-http
|
|
64
|
+
- sse
|
|
65
|
+
- http
|
|
66
|
+
- Not applicable
|
|
67
|
+
validations:
|
|
68
|
+
required: true
|
|
69
|
+
|
|
70
|
+
- type: textarea
|
|
71
|
+
id: environment
|
|
72
|
+
attributes:
|
|
73
|
+
label: Environment
|
|
74
|
+
description: |
|
|
75
|
+
Provide details about your environment.
|
|
76
|
+
placeholder: |
|
|
77
|
+
- OS: macOS 15.2 / Ubuntu 24.04 / etc.
|
|
78
|
+
- Python: 3.12.2
|
|
79
|
+
- Deployment: local / container / OpenShift
|
|
80
|
+
render: markdown
|
|
81
|
+
validations:
|
|
82
|
+
required: false
|
|
83
|
+
|
|
84
|
+
- type: textarea
|
|
85
|
+
id: logs
|
|
86
|
+
attributes:
|
|
87
|
+
label: Relevant logs
|
|
88
|
+
description: Paste any relevant log output. This will be formatted as code automatically.
|
|
89
|
+
render: shell
|
|
90
|
+
validations:
|
|
91
|
+
required: false
|
|
92
|
+
|
|
93
|
+
- type: checkboxes
|
|
94
|
+
id: checklist
|
|
95
|
+
attributes:
|
|
96
|
+
label: Checklist
|
|
97
|
+
options:
|
|
98
|
+
- label: I searched existing issues and this is not a duplicate.
|
|
99
|
+
required: true
|
|
100
|
+
- label: I am using a supported Python version (3.12+).
|
|
101
|
+
required: false
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Questions & Discussions
|
|
4
|
+
url: https://github.com/drtinkerer/keycloak-mcp-server/discussions
|
|
5
|
+
about: Ask questions, share ideas, or discuss the project.
|
|
6
|
+
- name: Security Vulnerabilities
|
|
7
|
+
url: https://github.com/drtinkerer/keycloak-mcp-server/security/advisories/new
|
|
8
|
+
about: Report security vulnerabilities privately (do NOT use public issues).
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
name: Feature Request
|
|
2
|
+
description: Suggest a new feature or improvement.
|
|
3
|
+
title: "[Feature]: "
|
|
4
|
+
labels: ["type/feature", "status/triage"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for suggesting a feature! Please describe the problem and your proposed solution.
|
|
10
|
+
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: problem
|
|
13
|
+
attributes:
|
|
14
|
+
label: Problem statement
|
|
15
|
+
description: What problem are you trying to solve? What's the use case?
|
|
16
|
+
placeholder: I'm always frustrated when...
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: solution
|
|
22
|
+
attributes:
|
|
23
|
+
label: Proposed solution
|
|
24
|
+
description: Describe the solution you'd like.
|
|
25
|
+
placeholder: I would like the server to...
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: alternatives
|
|
31
|
+
attributes:
|
|
32
|
+
label: Alternatives considered
|
|
33
|
+
description: Any alternative solutions or workarounds you've considered?
|
|
34
|
+
validations:
|
|
35
|
+
required: false
|
|
36
|
+
|
|
37
|
+
- type: dropdown
|
|
38
|
+
id: area
|
|
39
|
+
attributes:
|
|
40
|
+
label: Area
|
|
41
|
+
description: Which part of the project does this relate to?
|
|
42
|
+
options:
|
|
43
|
+
- MCP Tools
|
|
44
|
+
- Server Core
|
|
45
|
+
- OAuth / Authentication
|
|
46
|
+
- Storage
|
|
47
|
+
- Deployment / Infrastructure
|
|
48
|
+
- CI/CD
|
|
49
|
+
- Documentation
|
|
50
|
+
- Other
|
|
51
|
+
validations:
|
|
52
|
+
required: true
|
|
53
|
+
|
|
54
|
+
- type: dropdown
|
|
55
|
+
id: priority
|
|
56
|
+
attributes:
|
|
57
|
+
label: How important is this to you?
|
|
58
|
+
options:
|
|
59
|
+
- Nice to have
|
|
60
|
+
- Important - affects my workflow
|
|
61
|
+
- Critical - blocking my use case
|
|
62
|
+
validations:
|
|
63
|
+
required: true
|
|
64
|
+
|
|
65
|
+
- type: textarea
|
|
66
|
+
id: context
|
|
67
|
+
attributes:
|
|
68
|
+
label: Additional context
|
|
69
|
+
description: Any other context, screenshots, or examples.
|
|
70
|
+
validations:
|
|
71
|
+
required: false
|
|
72
|
+
|
|
73
|
+
- type: checkboxes
|
|
74
|
+
id: contribution
|
|
75
|
+
attributes:
|
|
76
|
+
label: Contribution
|
|
77
|
+
options:
|
|
78
|
+
- label: I would be willing to submit a PR for this feature.
|
|
79
|
+
required: false
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
## Description
|
|
2
|
+
|
|
3
|
+
<!-- Briefly describe what this PR does and why. -->
|
|
4
|
+
|
|
5
|
+
## Related Issues
|
|
6
|
+
|
|
7
|
+
<!-- Link related issues: Closes #123, Fixes #456 -->
|
|
8
|
+
|
|
9
|
+
## Type of Change
|
|
10
|
+
|
|
11
|
+
- [ ] Bug fix (non-breaking change that fixes an issue)
|
|
12
|
+
- [ ] New feature (non-breaking change that adds functionality)
|
|
13
|
+
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
|
14
|
+
- [ ] Documentation update
|
|
15
|
+
- [ ] Refactoring (no functional changes)
|
|
16
|
+
- [ ] CI/CD or infrastructure change
|
|
17
|
+
- [ ] Dependency update
|
|
18
|
+
|
|
19
|
+
## Checklist
|
|
20
|
+
|
|
21
|
+
- [ ] My code follows the project's coding standards (Ruff, MyPy, pydocstyle)
|
|
22
|
+
- [ ] I have added tests that prove my fix is effective or my feature works
|
|
23
|
+
- [ ] All new and existing tests pass (`make test`)
|
|
24
|
+
- [ ] Pre-commit hooks pass (`make pre-commit`)
|
|
25
|
+
- [ ] Code coverage remains >= 80% (`make coverage`)
|
|
26
|
+
- [ ] I have updated documentation where necessary
|
|
27
|
+
- [ ] I have updated `CHANGELOG.md` (if applicable)
|
|
28
|
+
- [ ] My PR title follows [Conventional Commits](https://www.conventionalcommits.org/) format
|
|
29
|
+
|
|
30
|
+
## Testing
|
|
31
|
+
|
|
32
|
+
<!-- Describe how you tested your changes. -->
|
|
33
|
+
|
|
34
|
+
## Screenshots / Logs
|
|
35
|
+
|
|
36
|
+
<!-- If applicable, add screenshots or log output. -->
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
updates:
|
|
4
|
+
# Python dependencies (pip)
|
|
5
|
+
- package-ecosystem: "pip"
|
|
6
|
+
directory: "/"
|
|
7
|
+
schedule:
|
|
8
|
+
interval: "weekly"
|
|
9
|
+
day: "monday"
|
|
10
|
+
open-pull-requests-limit: 10
|
|
11
|
+
labels:
|
|
12
|
+
- "type/dependency"
|
|
13
|
+
- "area/python"
|
|
14
|
+
commit-message:
|
|
15
|
+
prefix: "build(deps):"
|
|
16
|
+
reviewers:
|
|
17
|
+
- "drtinkerer"
|
|
18
|
+
|
|
19
|
+
# GitHub Actions
|
|
20
|
+
- package-ecosystem: "github-actions"
|
|
21
|
+
directory: "/"
|
|
22
|
+
schedule:
|
|
23
|
+
interval: "weekly"
|
|
24
|
+
day: "monday"
|
|
25
|
+
open-pull-requests-limit: 5
|
|
26
|
+
labels:
|
|
27
|
+
- "type/dependency"
|
|
28
|
+
- "area/ci"
|
|
29
|
+
commit-message:
|
|
30
|
+
prefix: "ci(deps):"
|
|
31
|
+
reviewers:
|
|
32
|
+
- "drtinkerer"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Pre-commit
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
11
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
12
|
+
|
|
13
|
+
env:
|
|
14
|
+
PYTHON_VERSION: "3.12"
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
pre-commit:
|
|
18
|
+
name: Pre Commit
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout code
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Install uv
|
|
26
|
+
uses: astral-sh/setup-uv@v3
|
|
27
|
+
with:
|
|
28
|
+
version: "latest"
|
|
29
|
+
|
|
30
|
+
- name: Install locked dependencies
|
|
31
|
+
run: uv sync --locked --python ${{ env.PYTHON_VERSION }}
|
|
32
|
+
|
|
33
|
+
- name: Run Pre Commit
|
|
34
|
+
run: |
|
|
35
|
+
uv run --locked pre-commit run --all-files
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
publish_to_test:
|
|
9
|
+
description: 'Publish to Test PyPI instead of PyPI'
|
|
10
|
+
required: false
|
|
11
|
+
default: false
|
|
12
|
+
type: boolean
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v3
|
|
25
|
+
|
|
26
|
+
- name: Check release tag matches package version
|
|
27
|
+
if: github.event_name == 'release'
|
|
28
|
+
run: |
|
|
29
|
+
version=$(uv version --short)
|
|
30
|
+
if [ "${{ github.event.release.tag_name }}" != "v${version}" ]; then
|
|
31
|
+
echo "Release tag ${{ github.event.release.tag_name }} does not match pyproject version v${version}"
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
- name: Build package
|
|
36
|
+
run: uv build
|
|
37
|
+
|
|
38
|
+
- name: Check package
|
|
39
|
+
run: uvx twine check dist/*
|
|
40
|
+
|
|
41
|
+
- name: Upload build artifacts
|
|
42
|
+
uses: actions/upload-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: dist
|
|
45
|
+
path: dist/
|
|
46
|
+
|
|
47
|
+
test:
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
strategy:
|
|
50
|
+
matrix:
|
|
51
|
+
python-version: ['3.12', '3.13']
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/checkout@v4
|
|
54
|
+
|
|
55
|
+
- name: Install uv
|
|
56
|
+
uses: astral-sh/setup-uv@v3
|
|
57
|
+
|
|
58
|
+
- name: Install locked dependencies
|
|
59
|
+
run: uv sync --locked --python ${{ matrix.python-version }}
|
|
60
|
+
|
|
61
|
+
- name: Run tests
|
|
62
|
+
env:
|
|
63
|
+
ENABLE_AUTH: "False"
|
|
64
|
+
run: uv run --locked pytest --cov=keycloak_mcp_server --cov-report=term-missing
|
|
65
|
+
|
|
66
|
+
publish:
|
|
67
|
+
needs: [build, test]
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
environment:
|
|
70
|
+
name: ${{ github.event.inputs.publish_to_test == 'true' && 'test-pypi' || 'pypi' }}
|
|
71
|
+
url: ${{ github.event.inputs.publish_to_test == 'true' && 'https://test.pypi.org/p/keycloak-mcp-server' || 'https://pypi.org/p/keycloak-mcp-server' }}
|
|
72
|
+
permissions:
|
|
73
|
+
id-token: write # Required for PyPI trusted publishing
|
|
74
|
+
steps:
|
|
75
|
+
- name: Download build artifacts
|
|
76
|
+
uses: actions/download-artifact@v4
|
|
77
|
+
with:
|
|
78
|
+
name: dist
|
|
79
|
+
path: dist/
|
|
80
|
+
|
|
81
|
+
- name: Publish to Test PyPI
|
|
82
|
+
if: github.event.inputs.publish_to_test == 'true'
|
|
83
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
84
|
+
with:
|
|
85
|
+
repository-url: https://test.pypi.org/legacy/
|
|
86
|
+
|
|
87
|
+
- name: Publish to PyPI
|
|
88
|
+
if: github.event.inputs.publish_to_test != 'true'
|
|
89
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Stale Issues and PRs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: "0 9 * * 1" # Every Monday at 9:00 UTC
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}
|
|
10
|
+
cancel-in-progress: false
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
issues: write
|
|
14
|
+
pull-requests: write
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
stale:
|
|
18
|
+
name: Close stale issues and PRs
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/stale@v11
|
|
22
|
+
with:
|
|
23
|
+
stale-issue-message: >
|
|
24
|
+
This issue has been automatically marked as stale because it has not
|
|
25
|
+
had activity in the last 60 days. It will be closed in 14 days if no
|
|
26
|
+
further activity occurs. If this issue is still relevant, please
|
|
27
|
+
comment or remove the stale label.
|
|
28
|
+
stale-pr-message: >
|
|
29
|
+
This pull request has been automatically marked as stale because it
|
|
30
|
+
has not had activity in the last 30 days. It will be closed in 14
|
|
31
|
+
days if no further activity occurs. If this PR is still in progress,
|
|
32
|
+
please comment or push new commits.
|
|
33
|
+
close-issue-message: >
|
|
34
|
+
This issue was closed because it has been stale for 14 days with no
|
|
35
|
+
activity. Feel free to reopen if still relevant.
|
|
36
|
+
close-pr-message: >
|
|
37
|
+
This pull request was closed because it has been stale for 14 days
|
|
38
|
+
with no activity. Feel free to reopen if still relevant.
|
|
39
|
+
days-before-issue-stale: 60
|
|
40
|
+
days-before-pr-stale: 30
|
|
41
|
+
days-before-issue-close: 14
|
|
42
|
+
days-before-pr-close: 14
|
|
43
|
+
stale-issue-label: "status/stale"
|
|
44
|
+
stale-pr-label: "status/stale"
|
|
45
|
+
exempt-issue-labels: "priority/high,status/blocked,good first issue"
|
|
46
|
+
exempt-pr-labels: "priority/high,status/blocked"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
11
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
name: Test Suite
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
strategy:
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.12", "3.13"]
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout code
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Install uv
|
|
26
|
+
uses: astral-sh/setup-uv@v3
|
|
27
|
+
with:
|
|
28
|
+
version: "latest"
|
|
29
|
+
|
|
30
|
+
- name: Install locked dependencies
|
|
31
|
+
run: uv sync --locked --python ${{ matrix.python-version }}
|
|
32
|
+
|
|
33
|
+
- name: Run tests with coverage
|
|
34
|
+
env:
|
|
35
|
+
ENABLE_AUTH: "False"
|
|
36
|
+
run: |
|
|
37
|
+
uv run --locked pytest --cov=keycloak_mcp_server --cov-report=xml --cov-report=term-missing --cov-fail-under=80
|
|
38
|
+
|
|
39
|
+
- name: Upload coverage reports to Codecov
|
|
40
|
+
uses: codecov/codecov-action@v4
|
|
41
|
+
with:
|
|
42
|
+
file: ./coverage.xml
|
|
43
|
+
flags: unittests
|
|
44
|
+
name: codecov-umbrella
|
|
45
|
+
fail_ci_if_error: false
|
|
46
|
+
env:
|
|
47
|
+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
dist/
|
|
13
|
+
eggs/
|
|
14
|
+
.eggs/
|
|
15
|
+
*.egg-info/
|
|
16
|
+
*.egg
|
|
17
|
+
MANIFEST
|
|
18
|
+
|
|
19
|
+
# Unit test / coverage reports
|
|
20
|
+
htmlcov/
|
|
21
|
+
.tox/
|
|
22
|
+
.nox/
|
|
23
|
+
.coverage
|
|
24
|
+
.coverage.*
|
|
25
|
+
.cache
|
|
26
|
+
coverage.xml
|
|
27
|
+
*.cover
|
|
28
|
+
*.py,cover
|
|
29
|
+
.hypothesis/
|
|
30
|
+
.pytest_cache/
|
|
31
|
+
|
|
32
|
+
# Environments
|
|
33
|
+
.env
|
|
34
|
+
.keycloak-oauth/
|
|
35
|
+
.venv
|
|
36
|
+
env/
|
|
37
|
+
venv/
|
|
38
|
+
|
|
39
|
+
# mypy
|
|
40
|
+
.mypy_cache/
|
|
41
|
+
.dmypy.json
|
|
42
|
+
dmypy.json
|
|
43
|
+
|
|
44
|
+
# Ruff
|
|
45
|
+
.ruff_cache/
|
|
46
|
+
|
|
47
|
+
# pytype
|
|
48
|
+
.pytype/
|
|
49
|
+
|
|
50
|
+
# IDE files
|
|
51
|
+
.cursor/
|
|
52
|
+
.vscode/
|
|
53
|
+
.idea/
|
|
54
|
+
*.swp
|
|
55
|
+
*.swo
|
|
56
|
+
*~
|
|
57
|
+
|
|
58
|
+
# OS generated files
|
|
59
|
+
.DS_Store
|
|
60
|
+
Thumbs.db
|
|
61
|
+
|
|
62
|
+
# Logs
|
|
63
|
+
*.log
|
|
64
|
+
|
|
65
|
+
# Project-specific
|
|
66
|
+
bandit-report.json
|
|
67
|
+
safety-report.json
|
|
68
|
+
.safety-project.ini
|
|
69
|
+
build.log
|
|
70
|
+
*.tmp
|
|
71
|
+
*.bak
|