glpi-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.
- glpi_mcp_server-0.1.0/.dockerignore +33 -0
- glpi_mcp_server-0.1.0/.env.example +123 -0
- glpi_mcp_server-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +82 -0
- glpi_mcp_server-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- glpi_mcp_server-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +27 -0
- glpi_mcp_server-0.1.0/.github/dependabot.yml +19 -0
- glpi_mcp_server-0.1.0/.github/workflows/pre-commit.yml +27 -0
- glpi_mcp_server-0.1.0/.github/workflows/publish.yml +202 -0
- glpi_mcp_server-0.1.0/.github/workflows/release.yml +72 -0
- glpi_mcp_server-0.1.0/.gitignore +238 -0
- glpi_mcp_server-0.1.0/.pre-commit-config.yaml +80 -0
- glpi_mcp_server-0.1.0/CHANGELOG.md +5 -0
- glpi_mcp_server-0.1.0/CITATION.cff +22 -0
- glpi_mcp_server-0.1.0/CONTRIBUTING.md +34 -0
- glpi_mcp_server-0.1.0/Dockerfile +62 -0
- glpi_mcp_server-0.1.0/LICENSE +21 -0
- glpi_mcp_server-0.1.0/MANIFEST.in +3 -0
- glpi_mcp_server-0.1.0/PKG-INFO +710 -0
- glpi_mcp_server-0.1.0/README.md +656 -0
- glpi_mcp_server-0.1.0/SECURITY.md +24 -0
- glpi_mcp_server-0.1.0/fastmcp.json +18 -0
- glpi_mcp_server-0.1.0/pyproject.toml +156 -0
- glpi_mcp_server-0.1.0/server.json +533 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/__init__.py +6 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/auth.py +509 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/glpi_client.py +992 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/healthcheck.py +72 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/models.py +281 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/retry.py +224 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/rsql.py +147 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/sentry_init.py +95 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/server.py +291 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/tools/__init__.py +34 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/tools/administration.py +268 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/tools/assets.py +251 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/tools/common.py +412 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/tools/documents.py +137 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/tools/errors.py +73 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/tools/generic.py +331 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/tools/itil.py +585 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/tools/knowledgebase.py +228 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/tools/session.py +128 -0
- glpi_mcp_server-0.1.0/src/glpi_mcp/utils.py +160 -0
- glpi_mcp_server-0.1.0/tests/__init__.py +3 -0
- glpi_mcp_server-0.1.0/tests/conftest.py +224 -0
- glpi_mcp_server-0.1.0/tests/test_auth.py +421 -0
- glpi_mcp_server-0.1.0/tests/test_client.py +523 -0
- glpi_mcp_server-0.1.0/tests/test_config.py +298 -0
- glpi_mcp_server-0.1.0/tests/test_dry_run.py +126 -0
- glpi_mcp_server-0.1.0/tests/test_healthcheck.py +279 -0
- glpi_mcp_server-0.1.0/tests/test_rsql.py +66 -0
- glpi_mcp_server-0.1.0/tests/test_sentry_init.py +39 -0
- glpi_mcp_server-0.1.0/tests/test_settings_documented.py +58 -0
- glpi_mcp_server-0.1.0/tests/test_tools.py +531 -0
- glpi_mcp_server-0.1.0/tests/test_utils.py +157 -0
- glpi_mcp_server-0.1.0/uv.lock +2317 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Docker ignore file to reduce build context size
|
|
2
|
+
**/__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
.Python
|
|
7
|
+
*.so
|
|
8
|
+
.git
|
|
9
|
+
.gitignore
|
|
10
|
+
.github
|
|
11
|
+
.vscode
|
|
12
|
+
.idea
|
|
13
|
+
*.md
|
|
14
|
+
!README.md
|
|
15
|
+
.env
|
|
16
|
+
.env.*
|
|
17
|
+
!.env.example
|
|
18
|
+
*.log
|
|
19
|
+
.coverage
|
|
20
|
+
.pytest_cache
|
|
21
|
+
.mypy_cache
|
|
22
|
+
dist/
|
|
23
|
+
build/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
screenshots/
|
|
26
|
+
docker-compose.yml
|
|
27
|
+
Dockerfile*
|
|
28
|
+
*.tar
|
|
29
|
+
*.zip
|
|
30
|
+
.venv/
|
|
31
|
+
venv/
|
|
32
|
+
.ruff_cache/
|
|
33
|
+
.mcpregistry_*
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# GLPI MCP Server Environment Configuration
|
|
2
|
+
# Needs GLPI 11.0.6+ or 12 with the High-Level API enabled
|
|
3
|
+
# (Setup > General > API) and an OAuth client (Setup > OAuth clients).
|
|
4
|
+
|
|
5
|
+
# GLPI Connection Details
|
|
6
|
+
# GLPI root URL, without /api.php
|
|
7
|
+
GLPI_URL=https://glpi.example.com
|
|
8
|
+
|
|
9
|
+
# OAuth client from Setup > OAuth clients (allow the Password grant and the
|
|
10
|
+
# scopes below; also the Authorization Code grant for GLPI_OAUTH_LOGIN)
|
|
11
|
+
GLPI_CLIENT_ID=your-client-id
|
|
12
|
+
GLPI_CLIENT_SECRET=your-client-secret
|
|
13
|
+
|
|
14
|
+
# GLPI account the tools act as (OAuth password grant)
|
|
15
|
+
GLPI_USERNAME=glpi-mcp
|
|
16
|
+
GLPI_PASSWORD=change-me
|
|
17
|
+
|
|
18
|
+
# OAuth scopes to request, space- or comma-separated (default: api user)
|
|
19
|
+
# Add graphql to use glpi_graphql_query
|
|
20
|
+
# GLPI_SCOPES=api user
|
|
21
|
+
|
|
22
|
+
# High-Level API version: auto (default; 3.0 on GLPI 12, 2.3 on GLPI 11), 2.3 or 3.0
|
|
23
|
+
GLPI_API_VERSION=auto
|
|
24
|
+
|
|
25
|
+
# Optional: entity and profile to work in (GLPI-Entity / GLPI-Profile headers)
|
|
26
|
+
# GLPI_ENTITY=0
|
|
27
|
+
# GLPI_ENTITY_RECURSIVE=true
|
|
28
|
+
# GLPI_PROFILE=4
|
|
29
|
+
|
|
30
|
+
# SSL Configuration
|
|
31
|
+
GLPI_VERIFY_SSL=true
|
|
32
|
+
# Total seconds allowed for one request, retries included
|
|
33
|
+
GLPI_TIMEOUT=30
|
|
34
|
+
|
|
35
|
+
# Per-user GLPI access (HTTP transports only; pick at most one)
|
|
36
|
+
# GLPI_TOKEN_PASSTHROUGH: each MCP client sends its own GLPI OAuth access token
|
|
37
|
+
# as 'Authorization: Bearer <token>'; GLPI_USERNAME/GLPI_PASSWORD are not used.
|
|
38
|
+
# GLPI_TOKEN_PASSTHROUGH=false
|
|
39
|
+
# GLPI_OAUTH_LOGIN: MCP clients sign in with their GLPI account through this
|
|
40
|
+
# server (OAuth with Dynamic Client Registration). Register
|
|
41
|
+
# GLPI_OAUTH_BASE_URL + GLPI_OAUTH_REDIRECT_PATH as the OAuth client's
|
|
42
|
+
# redirect URI in GLPI.
|
|
43
|
+
# GLPI_OAUTH_LOGIN=false
|
|
44
|
+
# GLPI_OAUTH_BASE_URL=https://glpi-mcp.example.com
|
|
45
|
+
# GLPI_OAUTH_REDIRECT_PATH=/auth/callback
|
|
46
|
+
# GLPI_OAUTH_ALLOWED_REDIRECT_URIS=
|
|
47
|
+
|
|
48
|
+
# Read-Only Mode
|
|
49
|
+
# Set READ_ONLY_MODE true to disable all write operations (create, update, delete)
|
|
50
|
+
READ_ONLY_MODE=false
|
|
51
|
+
|
|
52
|
+
# Dry-Run Mode
|
|
53
|
+
# Set DRY_RUN_MODE true to make write tools return the request they would send
|
|
54
|
+
# instead of changing GLPI
|
|
55
|
+
DRY_RUN_MODE=false
|
|
56
|
+
|
|
57
|
+
# Disabled Tags
|
|
58
|
+
# Comma-separated list of tags to disable tools for (empty by default)
|
|
59
|
+
# Example: DISABLED_TAGS=assets,knowledgebase,graphql
|
|
60
|
+
DISABLED_TAGS=
|
|
61
|
+
|
|
62
|
+
# Response Size Limit
|
|
63
|
+
# Maximum size of a tool response in bytes (empty = unlimited)
|
|
64
|
+
# RESPONSE_MAX_SIZE=500000
|
|
65
|
+
|
|
66
|
+
# Logging Configuration
|
|
67
|
+
LOG_LEVEL=INFO
|
|
68
|
+
|
|
69
|
+
# Rate Limiting
|
|
70
|
+
# Set RATE_LIMIT_ENABLED true to enable rate limiting
|
|
71
|
+
RATE_LIMIT_ENABLED=false
|
|
72
|
+
RATE_LIMIT_MAX_REQUESTS=60
|
|
73
|
+
RATE_LIMIT_WINDOW_MINUTES=1
|
|
74
|
+
|
|
75
|
+
# Tool Search Transform (Optional)
|
|
76
|
+
# Set TOOL_SEARCH_ENABLED true to replace full tool listings with search_tools + call_tool
|
|
77
|
+
TOOL_SEARCH_ENABLED=false
|
|
78
|
+
# Search strategy: bm25 (natural language) or regex (pattern match)
|
|
79
|
+
TOOL_SEARCH_STRATEGY=bm25
|
|
80
|
+
# Maximum number of tools returned by search_tools
|
|
81
|
+
TOOL_SEARCH_MAX_RESULTS=5
|
|
82
|
+
|
|
83
|
+
# Sentry Error Tracking (Optional)
|
|
84
|
+
# Set SENTRY_DSN to enable error tracking and performance monitoring
|
|
85
|
+
# SENTRY_DSN=https://your-key@o12345.ingest.us.sentry.io/6789
|
|
86
|
+
# Optional Sentry configuration
|
|
87
|
+
# SENTRY_TRACES_SAMPLE_RATE=1.0
|
|
88
|
+
# SENTRY_SEND_DEFAULT_PII=false
|
|
89
|
+
# SENTRY_ENVIRONMENT=production
|
|
90
|
+
# SENTRY_RELEASE=1.2.3
|
|
91
|
+
# SENTRY_PROFILE_SESSION_SAMPLE_RATE=1.0
|
|
92
|
+
# SENTRY_PROFILE_LIFECYCLE=trace
|
|
93
|
+
# SENTRY_ENABLE_LOGS=true
|
|
94
|
+
|
|
95
|
+
# MCP Transport Configuration
|
|
96
|
+
# Transport type: 'stdio' (default), 'sse' (Server-Sent Events), or 'http' (HTTP Streamable)
|
|
97
|
+
# 'streamable-http' is accepted as an alias for 'http'. Any other value stops
|
|
98
|
+
# the server at startup.
|
|
99
|
+
MCP_TRANSPORT=stdio
|
|
100
|
+
|
|
101
|
+
# HTTP Transport Settings (used when MCP_TRANSPORT=sse or MCP_TRANSPORT=http)
|
|
102
|
+
# Host to bind the HTTP server (default: 127.0.0.1)
|
|
103
|
+
# MCP_HTTP_HOST=127.0.0.1
|
|
104
|
+
# Port to bind the HTTP server (default: 8000)
|
|
105
|
+
# MCP_HTTP_PORT=8000
|
|
106
|
+
# Optional bearer token for authentication (leave empty for no auth)
|
|
107
|
+
# MCP_HTTP_BEARER_TOKEN=
|
|
108
|
+
|
|
109
|
+
# OIDC / OAuth Authentication (used when MCP_TRANSPORT=sse or MCP_TRANSPORT=http)
|
|
110
|
+
# Lets MCP clients sign in through an external identity provider; tools then
|
|
111
|
+
# act as GLPI_USERNAME. All four are required to enable it; takes precedence
|
|
112
|
+
# over MCP_HTTP_BEARER_TOKEN.
|
|
113
|
+
# OIDC_CONFIG_URL=https://id.example.com/.well-known/openid-configuration
|
|
114
|
+
# OIDC_CLIENT_ID=
|
|
115
|
+
# OIDC_CLIENT_SECRET=
|
|
116
|
+
# Public URL of this server
|
|
117
|
+
# OIDC_BASE_URL=https://glpi-mcp.example.com
|
|
118
|
+
# Optional OIDC settings
|
|
119
|
+
# OIDC_REDIRECT_PATH=/auth/callback
|
|
120
|
+
# OIDC_REQUIRED_SCOPES=
|
|
121
|
+
# OIDC_ALLOWED_REDIRECT_URIS=
|
|
122
|
+
# OIDC_VERIFY_ID_TOKEN=false
|
|
123
|
+
# OIDC_FORWARD_RESOURCE=false
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something in glpi-mcp does not work as expected
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Remove tokens, passwords and anything else private from what you paste below.
|
|
9
|
+
For security issues, use [private vulnerability reporting](https://github.com/mhajder/glpi-mcp/security/advisories/new) instead.
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: description
|
|
12
|
+
attributes:
|
|
13
|
+
label: What happened?
|
|
14
|
+
description: Include the tool you called and the error or wrong result.
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: reproduce
|
|
19
|
+
attributes:
|
|
20
|
+
label: Steps to reproduce
|
|
21
|
+
placeholder: |
|
|
22
|
+
1. Call tool `...` with arguments `...`
|
|
23
|
+
2. ...
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
- type: textarea
|
|
27
|
+
id: expected
|
|
28
|
+
attributes:
|
|
29
|
+
label: Expected behavior
|
|
30
|
+
validations:
|
|
31
|
+
required: true
|
|
32
|
+
- type: input
|
|
33
|
+
id: version
|
|
34
|
+
attributes:
|
|
35
|
+
label: glpi-mcp version
|
|
36
|
+
placeholder: e.g. 0.1.0
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
39
|
+
- type: input
|
|
40
|
+
id: product-version
|
|
41
|
+
attributes:
|
|
42
|
+
label: GLPI version
|
|
43
|
+
placeholder: "e.g. 11.0.11 (API 2.3) or 12.0.0 (API 3.0)"
|
|
44
|
+
validations:
|
|
45
|
+
required: true
|
|
46
|
+
- type: dropdown
|
|
47
|
+
id: install
|
|
48
|
+
attributes:
|
|
49
|
+
label: Installation method
|
|
50
|
+
options:
|
|
51
|
+
- uvx / pip (PyPI)
|
|
52
|
+
- Docker image (ghcr.io)
|
|
53
|
+
- From source
|
|
54
|
+
validations:
|
|
55
|
+
required: true
|
|
56
|
+
- type: dropdown
|
|
57
|
+
id: transport
|
|
58
|
+
attributes:
|
|
59
|
+
label: MCP transport
|
|
60
|
+
options:
|
|
61
|
+
- stdio
|
|
62
|
+
- http (Streamable HTTP)
|
|
63
|
+
- sse
|
|
64
|
+
validations:
|
|
65
|
+
required: true
|
|
66
|
+
- type: input
|
|
67
|
+
id: client
|
|
68
|
+
attributes:
|
|
69
|
+
label: MCP client
|
|
70
|
+
placeholder: e.g. Claude Desktop, Claude Code, Open WebUI
|
|
71
|
+
- type: textarea
|
|
72
|
+
id: config
|
|
73
|
+
attributes:
|
|
74
|
+
label: Relevant configuration
|
|
75
|
+
description: Non-secret settings only, such as READ_ONLY_MODE, DISABLED_TAGS or TOOL_SEARCH_ENABLED. Never paste tokens.
|
|
76
|
+
render: shell
|
|
77
|
+
- type: textarea
|
|
78
|
+
id: logs
|
|
79
|
+
attributes:
|
|
80
|
+
label: Logs
|
|
81
|
+
description: Run with LOG_LEVEL=DEBUG if you can, and redact anything private.
|
|
82
|
+
render: text
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a new tool or an improvement
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: What problem would this solve?
|
|
9
|
+
description: What do you want to do with GLPI that the server cannot do today?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: Proposed solution
|
|
16
|
+
description: For a new tool, describe its name, arguments and what it returns.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: input
|
|
20
|
+
id: api
|
|
21
|
+
attributes:
|
|
22
|
+
label: GLPI API reference
|
|
23
|
+
description: Link to the GLPI API endpoint or docs this would use, if you know it.
|
|
24
|
+
- type: textarea
|
|
25
|
+
id: alternatives
|
|
26
|
+
attributes:
|
|
27
|
+
label: Alternatives considered
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "github-actions"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "daily"
|
|
7
|
+
groups:
|
|
8
|
+
github-actions:
|
|
9
|
+
patterns:
|
|
10
|
+
- "*"
|
|
11
|
+
- package-ecosystem: "uv"
|
|
12
|
+
directory: "/"
|
|
13
|
+
schedule:
|
|
14
|
+
interval: "daily"
|
|
15
|
+
groups:
|
|
16
|
+
uv-dependencies:
|
|
17
|
+
dependency-type: "production"
|
|
18
|
+
uv-dev-dependencies:
|
|
19
|
+
dependency-type: "development"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Pre-commit Checks
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
prek:
|
|
15
|
+
name: Run prek
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
|
|
21
|
+
- name: Install the latest version of uv and set the python version
|
|
22
|
+
uses: astral-sh/setup-uv@v7
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.15"
|
|
25
|
+
|
|
26
|
+
- name: Run prek
|
|
27
|
+
uses: j178/prek-action@v2
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
tags:
|
|
7
|
+
- "v*.*.*"
|
|
8
|
+
|
|
9
|
+
env:
|
|
10
|
+
REGISTRY: ghcr.io
|
|
11
|
+
IMAGE_NAME: ${{ github.repository }}
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
publish-docker:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
packages: write
|
|
19
|
+
id-token: write # Required to sign the build provenance attestation
|
|
20
|
+
attestations: write # Required to store the build provenance attestation
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- name: Checkout repository
|
|
24
|
+
uses: actions/checkout@v7
|
|
25
|
+
|
|
26
|
+
- name: Set up QEMU
|
|
27
|
+
uses: docker/setup-qemu-action@v4
|
|
28
|
+
|
|
29
|
+
- name: Set up Docker Buildx
|
|
30
|
+
uses: docker/setup-buildx-action@v4
|
|
31
|
+
|
|
32
|
+
- name: Log in to GitHub Container Registry
|
|
33
|
+
if: github.event_name != 'pull_request'
|
|
34
|
+
uses: docker/login-action@v4
|
|
35
|
+
with:
|
|
36
|
+
registry: ${{ env.REGISTRY }}
|
|
37
|
+
username: ${{ github.actor }}
|
|
38
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
39
|
+
|
|
40
|
+
- name: Extract metadata for Docker
|
|
41
|
+
id: meta
|
|
42
|
+
uses: docker/metadata-action@v6
|
|
43
|
+
with:
|
|
44
|
+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
45
|
+
tags: |
|
|
46
|
+
# Set latest tag for main branch
|
|
47
|
+
type=raw,value=latest,enable={{is_default_branch}}
|
|
48
|
+
# Tag with branch name (e.g., main, develop)
|
|
49
|
+
type=ref,event=branch
|
|
50
|
+
# Tag with PR number (e.g., pr-2)
|
|
51
|
+
type=ref,event=pr
|
|
52
|
+
# Tag with semver - v1.2.3 -> 1.2.3
|
|
53
|
+
type=semver,pattern={{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
|
54
|
+
# Tag with major.minor - v1.2.3 -> 1.2
|
|
55
|
+
type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
|
56
|
+
# Tag with major - v1.2.3 -> 1
|
|
57
|
+
type=semver,pattern={{major}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
|
58
|
+
# Tag with git sha
|
|
59
|
+
type=sha,format=short
|
|
60
|
+
|
|
61
|
+
- name: Build and push Docker image
|
|
62
|
+
id: build
|
|
63
|
+
uses: docker/build-push-action@v7
|
|
64
|
+
with:
|
|
65
|
+
context: .
|
|
66
|
+
platforms: linux/amd64,linux/arm64
|
|
67
|
+
push: ${{ github.event_name != 'pull_request' }}
|
|
68
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
69
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
70
|
+
cache-from: type=gha
|
|
71
|
+
cache-to: type=gha,mode=max
|
|
72
|
+
provenance: mode=max
|
|
73
|
+
sbom: true
|
|
74
|
+
|
|
75
|
+
- name: Attest image build provenance
|
|
76
|
+
if: github.event_name != 'pull_request'
|
|
77
|
+
uses: actions/attest@v4
|
|
78
|
+
with:
|
|
79
|
+
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
80
|
+
subject-digest: ${{ steps.build.outputs.digest }}
|
|
81
|
+
push-to-registry: true
|
|
82
|
+
# Storage records are only supported for organization-owned repositories
|
|
83
|
+
create-storage-record: false
|
|
84
|
+
|
|
85
|
+
publish-pypi:
|
|
86
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
87
|
+
runs-on: ubuntu-latest
|
|
88
|
+
environment:
|
|
89
|
+
name: pypi
|
|
90
|
+
url: https://pypi.org/p/glpi-mcp-server
|
|
91
|
+
permissions:
|
|
92
|
+
id-token: write # Mandatory for Trusted Publishing
|
|
93
|
+
attestations: write # Required to store the build provenance attestation
|
|
94
|
+
|
|
95
|
+
steps:
|
|
96
|
+
- name: Checkout code
|
|
97
|
+
uses: actions/checkout@v7
|
|
98
|
+
|
|
99
|
+
- name: Install the latest version of uv and set the python version
|
|
100
|
+
uses: astral-sh/setup-uv@v7
|
|
101
|
+
with:
|
|
102
|
+
python-version: "3.15"
|
|
103
|
+
|
|
104
|
+
- name: Install dependencies
|
|
105
|
+
run: uv sync --locked --all-extras --no-dev
|
|
106
|
+
|
|
107
|
+
- name: Build package
|
|
108
|
+
run: uv build
|
|
109
|
+
|
|
110
|
+
- name: Attest package build provenance
|
|
111
|
+
id: attest
|
|
112
|
+
uses: actions/attest@v4
|
|
113
|
+
with:
|
|
114
|
+
subject-path: dist/*
|
|
115
|
+
|
|
116
|
+
- name: Collect release assets
|
|
117
|
+
env:
|
|
118
|
+
BUNDLE_PATH: ${{ steps.attest.outputs.bundle-path }}
|
|
119
|
+
run: |
|
|
120
|
+
mkdir release-assets
|
|
121
|
+
cp dist/* release-assets/
|
|
122
|
+
cp "$BUNDLE_PATH" "release-assets/${GITHUB_REPOSITORY#*/}-${GITHUB_REF_NAME#v}.sigstore.json"
|
|
123
|
+
|
|
124
|
+
- name: Upload release assets
|
|
125
|
+
uses: actions/upload-artifact@v7
|
|
126
|
+
with:
|
|
127
|
+
name: release-assets
|
|
128
|
+
path: release-assets/
|
|
129
|
+
|
|
130
|
+
- name: Publish package distributions to PyPI
|
|
131
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
132
|
+
|
|
133
|
+
upload-release-assets:
|
|
134
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
135
|
+
runs-on: ubuntu-latest
|
|
136
|
+
needs: [publish-pypi]
|
|
137
|
+
permissions:
|
|
138
|
+
contents: write # Required to upload assets to the GitHub release
|
|
139
|
+
|
|
140
|
+
steps:
|
|
141
|
+
- name: Download release assets
|
|
142
|
+
uses: actions/download-artifact@v8
|
|
143
|
+
with:
|
|
144
|
+
name: release-assets
|
|
145
|
+
path: release-assets
|
|
146
|
+
|
|
147
|
+
- name: Upload assets to the GitHub release
|
|
148
|
+
env:
|
|
149
|
+
GH_TOKEN: ${{ github.token }}
|
|
150
|
+
run: |
|
|
151
|
+
# release.yml creates the release in parallel with this workflow
|
|
152
|
+
for attempt in $(seq 1 10); do
|
|
153
|
+
if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" > /dev/null 2>&1; then
|
|
154
|
+
gh release upload "$GITHUB_REF_NAME" release-assets/* --repo "$GITHUB_REPOSITORY" --clobber
|
|
155
|
+
exit 0
|
|
156
|
+
fi
|
|
157
|
+
echo "Release $GITHUB_REF_NAME not found yet, retrying in 15s ($attempt/10)"
|
|
158
|
+
sleep 15
|
|
159
|
+
done
|
|
160
|
+
echo "::error::Release $GITHUB_REF_NAME not found"
|
|
161
|
+
exit 1
|
|
162
|
+
|
|
163
|
+
publish-mcp-registry:
|
|
164
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
165
|
+
runs-on: ubuntu-latest
|
|
166
|
+
needs: [publish-pypi, publish-docker]
|
|
167
|
+
permissions:
|
|
168
|
+
id-token: write # Required for OIDC authentication
|
|
169
|
+
contents: read
|
|
170
|
+
|
|
171
|
+
steps:
|
|
172
|
+
- name: Checkout code
|
|
173
|
+
uses: actions/checkout@v7
|
|
174
|
+
|
|
175
|
+
- name: Install mcp-publisher
|
|
176
|
+
run: |
|
|
177
|
+
curl -fsSL --retry 5 --retry-all-errors --retry-delay 10 "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
|
|
178
|
+
chmod +x mcp-publisher
|
|
179
|
+
|
|
180
|
+
- name: Publish server to MCP Registry
|
|
181
|
+
run: |
|
|
182
|
+
max_attempts=5
|
|
183
|
+
for attempt in $(seq 1 "$max_attempts"); do
|
|
184
|
+
if ./mcp-publisher login github-oidc; then
|
|
185
|
+
if output=$(./mcp-publisher publish 2>&1); then
|
|
186
|
+
echo "$output"
|
|
187
|
+
exit 0
|
|
188
|
+
fi
|
|
189
|
+
echo "$output"
|
|
190
|
+
# An earlier attempt may have published before its response was lost
|
|
191
|
+
if grep -q "cannot publish duplicate version" <<< "$output"; then
|
|
192
|
+
echo "This version is already in the MCP Registry"
|
|
193
|
+
exit 0
|
|
194
|
+
fi
|
|
195
|
+
fi
|
|
196
|
+
if [ "$attempt" -lt "$max_attempts" ]; then
|
|
197
|
+
echo "::warning::MCP Registry publish attempt $attempt/$max_attempts failed, retrying in $((attempt * 20))s"
|
|
198
|
+
sleep $((attempt * 20))
|
|
199
|
+
fi
|
|
200
|
+
done
|
|
201
|
+
echo "::error::MCP Registry publish failed after $max_attempts attempts"
|
|
202
|
+
exit 1
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
create-release:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
outputs:
|
|
14
|
+
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
15
|
+
tag_name: ${{ steps.get_version.outputs.tag_name }}
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout code
|
|
19
|
+
uses: actions/checkout@v7
|
|
20
|
+
|
|
21
|
+
- name: Get version from tag
|
|
22
|
+
id: get_version
|
|
23
|
+
run: |
|
|
24
|
+
echo "tag_name=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
|
|
25
|
+
echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
|
|
26
|
+
|
|
27
|
+
- name: Build release notes
|
|
28
|
+
env:
|
|
29
|
+
TAG: ${{ steps.get_version.outputs.tag_name }}
|
|
30
|
+
VERSION: ${{ steps.get_version.outputs.version }}
|
|
31
|
+
IMAGE: ghcr.io/${{ github.repository }}
|
|
32
|
+
run: |
|
|
33
|
+
# Same tags as docker/metadata-action in publish.yml: pre-releases only get the full version
|
|
34
|
+
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
35
|
+
IMAGE_TAGS="\`$VERSION\`, \`${VERSION%.*}\`, \`${VERSION%%.*}\`"
|
|
36
|
+
else
|
|
37
|
+
IMAGE_TAGS="\`$VERSION\`"
|
|
38
|
+
fi
|
|
39
|
+
PKG_NAME=$(grep -m1 '^name' pyproject.toml | sed 's/.*= *"\(.*\)"/\1/')
|
|
40
|
+
CHANGELOG=$(awk -v heading="## $TAG " '
|
|
41
|
+
index($0, heading) == 1 { flag = 1; next }
|
|
42
|
+
/^## / { if (flag) exit }
|
|
43
|
+
flag && (started || NF) { started = 1; print }
|
|
44
|
+
' CHANGELOG.md)
|
|
45
|
+
{
|
|
46
|
+
echo "## Release $TAG"
|
|
47
|
+
echo ""
|
|
48
|
+
echo "### 🐳 Docker Image"
|
|
49
|
+
echo ""
|
|
50
|
+
echo "| Image | Tags |"
|
|
51
|
+
echo "|-------|------|"
|
|
52
|
+
echo "| \`$IMAGE\` | $IMAGE_TAGS, \`sha-${GITHUB_SHA::7}\` |"
|
|
53
|
+
echo ""
|
|
54
|
+
echo "### 🐍 Python Package"
|
|
55
|
+
echo ""
|
|
56
|
+
echo "- **Package:** \`$PKG_NAME==$VERSION\`"
|
|
57
|
+
echo "- **Registry:** [PyPI](https://pypi.org/project/$PKG_NAME/$VERSION/)"
|
|
58
|
+
echo ""
|
|
59
|
+
echo "### 📋 Changelog"
|
|
60
|
+
echo ""
|
|
61
|
+
echo "${CHANGELOG:-No changelog entry found for this release.}"
|
|
62
|
+
} > release_notes.md
|
|
63
|
+
cat release_notes.md
|
|
64
|
+
|
|
65
|
+
- name: Create Release
|
|
66
|
+
id: create_release
|
|
67
|
+
uses: softprops/action-gh-release@v3
|
|
68
|
+
with:
|
|
69
|
+
tag_name: ${{ steps.get_version.outputs.tag_name }}
|
|
70
|
+
name: ${{ steps.get_version.outputs.tag_name }}
|
|
71
|
+
body_path: release_notes.md
|
|
72
|
+
prerelease: ${{ contains(steps.get_version.outputs.tag_name, '-') }}
|