image-generation-mcp 1.0.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.
Files changed (80) hide show
  1. image_generation_mcp-1.0.0/.github/codeql/codeql-config.yml +1 -0
  2. image_generation_mcp-1.0.0/.github/workflows/ci.yml +165 -0
  3. image_generation_mcp-1.0.0/.github/workflows/claude-code-review.yml +54 -0
  4. image_generation_mcp-1.0.0/.github/workflows/claude.yml +39 -0
  5. image_generation_mcp-1.0.0/.github/workflows/codeql.yml +31 -0
  6. image_generation_mcp-1.0.0/.github/workflows/docs.yml +48 -0
  7. image_generation_mcp-1.0.0/.github/workflows/release.yml +232 -0
  8. image_generation_mcp-1.0.0/.gitignore +21 -0
  9. image_generation_mcp-1.0.0/.gitleaks.toml +8 -0
  10. image_generation_mcp-1.0.0/CHANGELOG.md +7 -0
  11. image_generation_mcp-1.0.0/CLAUDE.md +46 -0
  12. image_generation_mcp-1.0.0/Dockerfile +44 -0
  13. image_generation_mcp-1.0.0/LICENSE +21 -0
  14. image_generation_mcp-1.0.0/PKG-INFO +337 -0
  15. image_generation_mcp-1.0.0/README.md +294 -0
  16. image_generation_mcp-1.0.0/TEMPLATE.md +121 -0
  17. image_generation_mcp-1.0.0/codecov.yml +32 -0
  18. image_generation_mcp-1.0.0/compose.yml +23 -0
  19. image_generation_mcp-1.0.0/docker-entrypoint.sh +48 -0
  20. image_generation_mcp-1.0.0/docs/configuration.md +84 -0
  21. image_generation_mcp-1.0.0/docs/decisions/0001-multi-provider-architecture.md +94 -0
  22. image_generation_mcp-1.0.0/docs/decisions/0002-provider-protocol-and-registry.md +92 -0
  23. image_generation_mcp-1.0.0/docs/decisions/0003-a1111-model-aware-presets.md +60 -0
  24. image_generation_mcp-1.0.0/docs/decisions/0004-keyword-based-provider-selection.md +82 -0
  25. image_generation_mcp-1.0.0/docs/decisions/0005-hybrid-background-tasks.md +93 -0
  26. image_generation_mcp-1.0.0/docs/decisions/0006-image-asset-model.md +130 -0
  27. image_generation_mcp-1.0.0/docs/deployment/docker.md +37 -0
  28. image_generation_mcp-1.0.0/docs/deployment/oidc.md +209 -0
  29. image_generation_mcp-1.0.0/docs/design/provider-system.md +250 -0
  30. image_generation_mcp-1.0.0/docs/getting-started/claude-code.md +72 -0
  31. image_generation_mcp-1.0.0/docs/getting-started/claude-desktop.md +110 -0
  32. image_generation_mcp-1.0.0/docs/getting-started/installation.md +66 -0
  33. image_generation_mcp-1.0.0/docs/guides/authentication.md +220 -0
  34. image_generation_mcp-1.0.0/docs/guides/image-assets.md +31 -0
  35. image_generation_mcp-1.0.0/docs/guides/prompt-writing.md +183 -0
  36. image_generation_mcp-1.0.0/docs/index.md +99 -0
  37. image_generation_mcp-1.0.0/docs/prompts.md +55 -0
  38. image_generation_mcp-1.0.0/docs/providers/a1111.md +112 -0
  39. image_generation_mcp-1.0.0/docs/providers/index.md +55 -0
  40. image_generation_mcp-1.0.0/docs/providers/openai.md +93 -0
  41. image_generation_mcp-1.0.0/docs/providers/placeholder.md +42 -0
  42. image_generation_mcp-1.0.0/docs/resources.md +132 -0
  43. image_generation_mcp-1.0.0/docs/tools.md +109 -0
  44. image_generation_mcp-1.0.0/examples/bearer-auth.env +5 -0
  45. image_generation_mcp-1.0.0/examples/oidc.env +9 -0
  46. image_generation_mcp-1.0.0/mkdocs.yml +126 -0
  47. image_generation_mcp-1.0.0/pyproject.toml +131 -0
  48. image_generation_mcp-1.0.0/scripts/rename.sh +65 -0
  49. image_generation_mcp-1.0.0/server.json +37 -0
  50. image_generation_mcp-1.0.0/src/image_generation_mcp/__init__.py +1 -0
  51. image_generation_mcp-1.0.0/src/image_generation_mcp/_server_deps.py +96 -0
  52. image_generation_mcp-1.0.0/src/image_generation_mcp/_server_prompts.py +188 -0
  53. image_generation_mcp-1.0.0/src/image_generation_mcp/_server_resources.py +212 -0
  54. image_generation_mcp-1.0.0/src/image_generation_mcp/_server_tools.py +180 -0
  55. image_generation_mcp-1.0.0/src/image_generation_mcp/cli.py +143 -0
  56. image_generation_mcp-1.0.0/src/image_generation_mcp/config.py +137 -0
  57. image_generation_mcp-1.0.0/src/image_generation_mcp/mcp_server.py +265 -0
  58. image_generation_mcp-1.0.0/src/image_generation_mcp/processing.py +199 -0
  59. image_generation_mcp-1.0.0/src/image_generation_mcp/providers/__init__.py +24 -0
  60. image_generation_mcp-1.0.0/src/image_generation_mcp/providers/a1111.py +239 -0
  61. image_generation_mcp-1.0.0/src/image_generation_mcp/providers/openai.py +222 -0
  62. image_generation_mcp-1.0.0/src/image_generation_mcp/providers/placeholder.py +115 -0
  63. image_generation_mcp-1.0.0/src/image_generation_mcp/providers/selector.py +126 -0
  64. image_generation_mcp-1.0.0/src/image_generation_mcp/providers/types.py +113 -0
  65. image_generation_mcp-1.0.0/src/image_generation_mcp/service.py +377 -0
  66. image_generation_mcp-1.0.0/tests/__init__.py +0 -0
  67. image_generation_mcp-1.0.0/tests/conftest.py +18 -0
  68. image_generation_mcp-1.0.0/tests/test_a1111_provider.py +242 -0
  69. image_generation_mcp-1.0.0/tests/test_image_assets.py +188 -0
  70. image_generation_mcp-1.0.0/tests/test_mcp_server.py +117 -0
  71. image_generation_mcp-1.0.0/tests/test_openai_provider.py +242 -0
  72. image_generation_mcp-1.0.0/tests/test_placeholder.py +75 -0
  73. image_generation_mcp-1.0.0/tests/test_processing.py +185 -0
  74. image_generation_mcp-1.0.0/tests/test_prompts.py +32 -0
  75. image_generation_mcp-1.0.0/tests/test_resources.py +168 -0
  76. image_generation_mcp-1.0.0/tests/test_selector.py +100 -0
  77. image_generation_mcp-1.0.0/tests/test_service.py +78 -0
  78. image_generation_mcp-1.0.0/tests/test_tasks.py +46 -0
  79. image_generation_mcp-1.0.0/tests/test_types.py +121 -0
  80. image_generation_mcp-1.0.0/uv.lock +2975 -0
@@ -0,0 +1 @@
1
+ name: "CodeQL config"
@@ -0,0 +1,165 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ lint:
12
+ name: Lint
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v4
19
+ with:
20
+ version: "latest"
21
+
22
+ - name: Set up Python
23
+ run: uv python install 3.12
24
+
25
+ - name: Install dependencies
26
+ run: uv sync --all-extras
27
+
28
+ - name: Run ruff check
29
+ run: uv run ruff check src/ tests/
30
+
31
+ - name: Run ruff format check
32
+ run: uv run ruff format --check src/ tests/
33
+
34
+ typecheck:
35
+ name: Type Check
36
+ runs-on: ubuntu-latest
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+
40
+ - name: Install uv
41
+ uses: astral-sh/setup-uv@v4
42
+ with:
43
+ version: "latest"
44
+
45
+ - name: Set up Python
46
+ run: uv python install 3.12
47
+
48
+ - name: Install dependencies
49
+ run: uv sync --all-extras
50
+
51
+ - name: Run mypy
52
+ run: uv run mypy src/
53
+
54
+ test:
55
+ name: Test (Python ${{ matrix.python-version }})
56
+ runs-on: ubuntu-latest
57
+ continue-on-error: ${{ matrix.experimental || false }}
58
+ permissions:
59
+ contents: read
60
+ statuses: write
61
+ strategy:
62
+ fail-fast: false
63
+ matrix:
64
+ include:
65
+ - python-version: "3.11"
66
+ experimental: false
67
+ - python-version: "3.12"
68
+ experimental: false
69
+ - python-version: "3.13"
70
+ experimental: false
71
+ - python-version: "3.14"
72
+ experimental: true
73
+ steps:
74
+ - uses: actions/checkout@v4
75
+
76
+ - name: Install uv
77
+ uses: astral-sh/setup-uv@v4
78
+ with:
79
+ version: "latest"
80
+
81
+ - name: Set up Python ${{ matrix.python-version }}
82
+ run: uv python install ${{ matrix.python-version }}
83
+
84
+ - name: Install dependencies
85
+ run: uv sync --all-extras
86
+
87
+ - name: Run tests with coverage
88
+ run: uv run pytest --cov --cov-report=xml
89
+
90
+ - name: Upload coverage to Codecov
91
+ if: matrix.python-version == '3.13'
92
+ uses: codecov/codecov-action@v5
93
+ with:
94
+ files: ./coverage.xml
95
+ fail_ci_if_error: false
96
+ override_pr: ${{ github.event.pull_request.number }}
97
+ env:
98
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
99
+
100
+ - name: Post codecov/patch status for non-Python PRs
101
+ if: matrix.python-version == '3.13' && github.event_name == 'pull_request'
102
+ uses: actions/github-script@v7
103
+ with:
104
+ github-token: ${{ secrets.GITHUB_TOKEN }}
105
+ script: |
106
+ const { data: files } = await github.rest.pulls.listFiles({
107
+ owner: context.repo.owner,
108
+ repo: context.repo.repo,
109
+ pull_number: context.payload.pull_request.number,
110
+ });
111
+ const hasPythonSourceChanges = files.some(
112
+ f => f.filename.endsWith('.py')
113
+ );
114
+ if (!hasPythonSourceChanges) {
115
+ const headSha = context.payload.pull_request.head.sha;
116
+ core.info(`No Python source changes — posting codecov/patch: success to ${headSha}`);
117
+ await github.rest.repos.createCommitStatus({
118
+ owner: context.repo.owner,
119
+ repo: context.repo.repo,
120
+ sha: headSha,
121
+ state: 'success',
122
+ context: 'codecov/patch',
123
+ description: 'Coverage not affected',
124
+ target_url: 'https://app.codecov.io/gh/pvliesdonk/image-generation-mcp',
125
+ });
126
+ } else {
127
+ core.info('Python source changes detected — Codecov will post patch status');
128
+ }
129
+
130
+ audit:
131
+ name: Dependency Audit
132
+ runs-on: ubuntu-latest
133
+ permissions:
134
+ contents: read
135
+ steps:
136
+ - uses: actions/checkout@v4
137
+
138
+ - name: Install uv
139
+ uses: astral-sh/setup-uv@v4
140
+ with:
141
+ version: "latest"
142
+
143
+ - name: Set up Python
144
+ run: uv python install 3.12
145
+
146
+ - name: Export dependency list (excluding local project)
147
+ run: uv export --all-extras --frozen --no-emit-project --no-hashes -o ${{ runner.temp }}/requirements.txt
148
+
149
+ - name: Run pip-audit
150
+ run: uvx pip-audit --strict --progress-spinner off -r ${{ runner.temp }}/requirements.txt
151
+
152
+ secrets:
153
+ name: Secret Detection
154
+ runs-on: ubuntu-latest
155
+ permissions:
156
+ contents: read
157
+ steps:
158
+ - uses: actions/checkout@v4
159
+ with:
160
+ fetch-depth: 0
161
+
162
+ - name: Run gitleaks
163
+ uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2
164
+ env:
165
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,54 @@
1
+ name: Claude Code Review
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize]
6
+
7
+ jobs:
8
+ claude-review:
9
+ if: github.actor != 'dependabot[bot]'
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ pull-requests: write
14
+ id-token: write
15
+
16
+ steps:
17
+ - name: Checkout repository
18
+ uses: actions/checkout@v4
19
+ with:
20
+ fetch-depth: 1
21
+
22
+ - name: Run Claude Code Review
23
+ id: claude-review
24
+ uses: anthropics/claude-code-action@v1
25
+ continue-on-error: true
26
+ with:
27
+ claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
28
+ track_progress: true
29
+ prompt: |
30
+ REPO: ${{ github.repository }}
31
+ PR NUMBER: ${{ github.event.pull_request.number }}
32
+
33
+ Perform a DIFFERENTIAL code review. Only review the CHANGES in this PR.
34
+
35
+ Steps:
36
+ 1. Run `gh pr diff ${{ github.event.pull_request.number }}` to see what changed
37
+ 2. Read CLAUDE.md for project conventions
38
+ 3. Read docs/design.md for the authoritative design specification
39
+ 4. Review the changed code for:
40
+ - Bugs or logic errors
41
+ - Security issues
42
+ - Convention violations (from CLAUDE.md)
43
+ - Missing tests for new code
44
+ - Type safety issues
45
+ - Design conformance: does the implementation match docs/design.md?
46
+ Check data types, method signatures, error handling, and database schema.
47
+
48
+ Use `mcp__github_inline_comment__create_inline_comment` for specific line feedback.
49
+ Use `gh pr comment` for summary feedback.
50
+
51
+ Be concise. Focus on actionable issues. Don't comment on unchanged code.
52
+
53
+ claude_args: |
54
+ --allowedTools mcp__github_inline_comment__create_inline_comment,Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr comment:*),Read,Grep,Glob
@@ -0,0 +1,39 @@
1
+ name: Claude Code
2
+
3
+ on:
4
+ issue_comment:
5
+ types: [created]
6
+ pull_request_review_comment:
7
+ types: [created]
8
+ issues:
9
+ types: [opened, assigned]
10
+ pull_request_review:
11
+ types: [submitted]
12
+
13
+ jobs:
14
+ claude:
15
+ if: |
16
+ (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
17
+ (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
18
+ (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
19
+ (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
20
+ runs-on: ubuntu-latest
21
+ permissions:
22
+ contents: read
23
+ pull-requests: read
24
+ issues: read
25
+ id-token: write
26
+ actions: read
27
+ steps:
28
+ - name: Checkout repository
29
+ uses: actions/checkout@v4
30
+ with:
31
+ fetch-depth: 1
32
+
33
+ - name: Run Claude Code
34
+ id: claude
35
+ uses: anthropics/claude-code-action@v1
36
+ with:
37
+ claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
38
+ additional_permissions: |
39
+ actions: read
@@ -0,0 +1,31 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ schedule:
9
+ - cron: "0 6 * * 1" # Weekly on Monday at 06:00 UTC
10
+
11
+ permissions:
12
+ actions: read
13
+ contents: read
14
+ security-events: write
15
+
16
+ jobs:
17
+ analyze:
18
+ name: CodeQL Analysis
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Initialize CodeQL
24
+ uses: github/codeql-action/init@v3
25
+ with:
26
+ languages: python
27
+ queries: security-extended
28
+ config-file: .github/codeql/codeql-config.yml
29
+
30
+ - name: Perform CodeQL Analysis
31
+ uses: github/codeql-action/analyze@v3
@@ -0,0 +1,48 @@
1
+ name: Docs
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ permissions:
7
+ contents: read
8
+ pages: write
9
+ id-token: write
10
+
11
+ concurrency:
12
+ group: "pages"
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ deploy:
17
+ environment:
18
+ name: github-pages
19
+ url: ${{ steps.deployment.outputs.page_url }}
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v4
26
+ with:
27
+ version: "latest"
28
+
29
+ - name: Set up Python
30
+ run: uv python install 3.12
31
+
32
+ - name: Install docs dependencies
33
+ run: uv sync --extra docs
34
+
35
+ - name: Build docs
36
+ run: uv run mkdocs build
37
+
38
+ - name: Setup Pages
39
+ uses: actions/configure-pages@v5
40
+
41
+ - name: Upload artifact
42
+ uses: actions/upload-pages-artifact@v3
43
+ with:
44
+ path: site/
45
+
46
+ - name: Deploy to GitHub Pages
47
+ id: deployment
48
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,232 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ force:
7
+ description: 'Force version bump (leave empty for auto)'
8
+ type: choice
9
+ default: ''
10
+ options:
11
+ - ''
12
+ - patch
13
+ - minor
14
+ - major
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ release:
21
+ runs-on: ubuntu-latest
22
+ concurrency:
23
+ group: release
24
+ cancel-in-progress: false
25
+
26
+ permissions:
27
+ contents: write
28
+ id-token: write
29
+
30
+ steps:
31
+ - name: Checkout repository
32
+ uses: actions/checkout@v4
33
+ with:
34
+ fetch-depth: 0
35
+ ref: ${{ github.ref_name }}
36
+ token: ${{ secrets.RELEASE_TOKEN }}
37
+
38
+ - name: Install uv
39
+ uses: astral-sh/setup-uv@v4
40
+ with:
41
+ version: "0.6"
42
+
43
+ - name: Setup Python
44
+ run: uv python install 3.12
45
+
46
+ - name: Semantic Version Release
47
+ id: release
48
+ uses: python-semantic-release/python-semantic-release@v10.5.3
49
+ with:
50
+ github_token: ${{ secrets.RELEASE_TOKEN }}
51
+ git_committer_name: "github-actions"
52
+ git_committer_email: "actions@users.noreply.github.com"
53
+ force: ${{ inputs.force }}
54
+
55
+ - name: Update server.json to released version
56
+ if: steps.release.outputs.released == 'true'
57
+ env:
58
+ VERSION: ${{ steps.release.outputs.version }}
59
+ run: |
60
+ jq --arg v "$VERSION" '
61
+ .version = $v |
62
+ .packages |= map(
63
+ if .registryType == "pypi" then .version = $v
64
+ elif .registryType == "oci" then .identifier = ("ghcr.io/pvliesdonk/image-generation-mcp:" + $v)
65
+ else . end
66
+ )
67
+ ' server.json > server.json.tmp
68
+ mv server.json.tmp server.json
69
+ git config user.name "github-actions"
70
+ git config user.email "actions@users.noreply.github.com"
71
+ git add server.json
72
+ git diff --cached --quiet || git commit -m "chore: update server.json to v${VERSION} [skip ci]"
73
+ git push
74
+
75
+ - name: Build package
76
+ if: steps.release.outputs.released == 'true'
77
+ run: uv build
78
+
79
+ - name: Generate SBOM
80
+ if: steps.release.outputs.released == 'true'
81
+ uses: anchore/sbom-action@57aae528053a48a3f6235f2d9461b05fbcb7366d # v0.23.1
82
+ with:
83
+ path: .
84
+ format: cyclonedx-json
85
+ output-file: sbom.cdx.json
86
+ upload-artifact: false
87
+ upload-release-assets: false
88
+
89
+ - name: Upload SBOM to GitHub Release
90
+ if: steps.release.outputs.released == 'true'
91
+ run: gh release upload ${{ steps.release.outputs.tag }} sbom.cdx.json
92
+ env:
93
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
94
+
95
+ - name: Upload to GitHub Release Assets
96
+ uses: python-semantic-release/publish-action@v10.5.3
97
+ if: steps.release.outputs.released == 'true'
98
+ with:
99
+ github_token: ${{ secrets.GITHUB_TOKEN }}
100
+ tag: ${{ steps.release.outputs.tag }}
101
+
102
+ - name: Upload build artifacts
103
+ if: steps.release.outputs.released == 'true'
104
+ uses: actions/upload-artifact@v4
105
+ with:
106
+ name: dist
107
+ path: dist/
108
+
109
+ outputs:
110
+ released: ${{ steps.release.outputs.released }}
111
+ version: ${{ steps.release.outputs.version }}
112
+ tag: ${{ steps.release.outputs.tag }}
113
+
114
+ publish-pypi:
115
+ needs: release
116
+ if: needs.release.outputs.released == 'true'
117
+ runs-on: ubuntu-latest
118
+ environment:
119
+ name: pypi
120
+ url: https://pypi.org/p/image-generation-mcp
121
+
122
+ permissions:
123
+ id-token: write
124
+
125
+ steps:
126
+ - name: Download build artifacts
127
+ uses: actions/download-artifact@v4
128
+ with:
129
+ name: dist
130
+ path: dist/
131
+
132
+ - name: Publish to PyPI
133
+ uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
134
+ with:
135
+ packages-dir: dist/
136
+ print-hash: true
137
+ verbose: true
138
+
139
+ publish-docker:
140
+ needs: release
141
+ if: needs.release.outputs.released == 'true'
142
+ runs-on: ubuntu-latest
143
+
144
+ permissions:
145
+ contents: read
146
+ packages: write
147
+ id-token: write
148
+ attestations: write
149
+
150
+ env:
151
+ REGISTRY: ghcr.io
152
+ IMAGE_NAME: ${{ github.repository }}
153
+
154
+ steps:
155
+ - name: Checkout repository
156
+ uses: actions/checkout@v4
157
+ with:
158
+ ref: ${{ needs.release.outputs.tag }}
159
+ fetch-depth: 1
160
+
161
+ - name: Set up QEMU
162
+ uses: docker/setup-qemu-action@v3
163
+
164
+ - name: Set up Docker Buildx
165
+ uses: docker/setup-buildx-action@v3
166
+
167
+ - name: Log in to Container Registry
168
+ uses: docker/login-action@v3
169
+ with:
170
+ registry: ${{ env.REGISTRY }}
171
+ username: ${{ github.actor }}
172
+ password: ${{ secrets.GITHUB_TOKEN }}
173
+
174
+ - name: Extract version components
175
+ id: version
176
+ env:
177
+ VERSION: ${{ needs.release.outputs.version }}
178
+ run: |
179
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
180
+ echo "major=$(echo "$VERSION" | cut -d. -f1)" >> $GITHUB_OUTPUT
181
+ echo "minor=$(echo "$VERSION" | cut -d. -f1-2)" >> $GITHUB_OUTPUT
182
+
183
+ - name: Extract metadata (tags, labels)
184
+ id: meta
185
+ uses: docker/metadata-action@v5
186
+ with:
187
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
188
+ tags: |
189
+ type=raw,value=latest
190
+ type=raw,value=v${{ steps.version.outputs.version }}
191
+ type=raw,value=v${{ steps.version.outputs.minor }}
192
+ type=raw,value=v${{ steps.version.outputs.major }}
193
+ labels: |
194
+ org.opencontainers.image.title=image-generation-mcp
195
+ org.opencontainers.image.description=FastMCP server template
196
+ org.opencontainers.image.vendor=pvliesdonk
197
+
198
+ - name: Build and push Docker image
199
+ id: build-push
200
+ uses: docker/build-push-action@v6
201
+ with:
202
+ context: .
203
+ platforms: linux/amd64,linux/arm64
204
+ push: true
205
+ tags: ${{ steps.meta.outputs.tags }}
206
+ labels: ${{ steps.meta.outputs.labels }}
207
+ cache-from: type=gha
208
+ cache-to: type=gha,mode=max
209
+
210
+ - name: Generate artifact attestation
211
+ uses: actions/attest-build-provenance@v2
212
+ with:
213
+ subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
214
+ subject-digest: ${{ steps.build-push.outputs.digest }}
215
+ push-to-registry: true
216
+
217
+ - name: Generate SBOM for Docker image
218
+ uses: anchore/sbom-action@57aae528053a48a3f6235f2d9461b05fbcb7366d # v0.23.1
219
+ with:
220
+ image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-push.outputs.digest }}
221
+ format: cyclonedx-json
222
+ output-file: sbom-docker.cdx.json
223
+ upload-artifact: false
224
+ upload-release-assets: false
225
+
226
+ - name: Attest Docker SBOM
227
+ uses: actions/attest-sbom@v2
228
+ with:
229
+ subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
230
+ subject-digest: ${{ steps.build-push.outputs.digest }}
231
+ sbom-path: sbom-docker.cdx.json
232
+ push-to-registry: true
@@ -0,0 +1,21 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ *.egg
9
+ .venv/
10
+ venv/
11
+ .env
12
+ *.so
13
+ .mypy_cache/
14
+ .pytest_cache/
15
+ .ruff_cache/
16
+ .coverage
17
+ coverage.xml
18
+ htmlcov/
19
+ *.npy
20
+ *.npz
21
+ site/
@@ -0,0 +1,8 @@
1
+ [allowlist]
2
+ description = "Allow test/example tokens"
3
+ regexes = [
4
+ # Test bearer tokens in test files and examples
5
+ '''my-secret-token''',
6
+ '''test-secret''',
7
+ '''your-generated-token''',
8
+ ]
@@ -0,0 +1,7 @@
1
+ # CHANGELOG
2
+
3
+ <!-- version list -->
4
+
5
+ ## v1.0.0 (2026-03-19)
6
+
7
+ - Initial Release
@@ -0,0 +1,46 @@
1
+ # image-generation-mcp
2
+
3
+ FastMCP server scaffold. See [TEMPLATE.md](TEMPLATE.md) for customisation guide.
4
+
5
+ ## Project Structure
6
+
7
+ ```
8
+ src/image_generation_mcp/
9
+ mcp_server.py -- FastMCP server factory + auth wiring (don't modify)
10
+ config.py -- env var loading; add domain config fields here
11
+ cli.py -- CLI entry point (serve command)
12
+ _server_deps.py -- lifespan + Depends() DI; replace placeholder service
13
+ _server_tools.py -- MCP tools; replace example tools with domain tools
14
+ _server_resources.py -- MCP resources; add domain resources here
15
+ _server_prompts.py -- MCP prompts; add domain prompts here
16
+ ```
17
+
18
+ ## Conventions
19
+
20
+ - Python 3.11+
21
+ - `uv` for package management, `ruff` for linting/formatting (line length 88)
22
+ - `hatchling` build backend
23
+ - Conventional commits: `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `chore:`
24
+ - Google-style docstrings on all public functions
25
+ - `logging.getLogger(__name__)` throughout, no `print()`
26
+ - Type hints everywhere
27
+
28
+ ## Key Patterns
29
+
30
+ - Library is sync; MCP layer uses `asyncio.to_thread()` for blocking calls
31
+ - Write tools tagged `tags={"write"}`, hidden via `mcp.disable(tags={"write"})` in read-only mode
32
+ - Auth: `_build_bearer_auth()` + `_build_oidc_auth()` called in `create_server()`; MultiAuth when both set
33
+ - `_ENV_PREFIX` in `config.py` controls all env var names — change once, affects everything
34
+
35
+ ## Documentation
36
+
37
+ Every PR that changes user-facing behavior must update the corresponding documentation:
38
+
39
+ - **New/changed tools or resources** → update `docs/tools.md` and `docs/resources.md`
40
+ - **New/changed env vars** → update `docs/configuration.md` AND the README config table
41
+ - **New/changed provider behavior** → update the provider's page in `docs/providers/`
42
+ - **New MCP client configuration** → update `docs/getting-started/claude-desktop.md` or `claude-code.md`
43
+
44
+ The architect-reviewer conformance check includes documentation currency. A PR that adds a tool without documenting it is incomplete.
45
+
46
+ Internal design docs (`docs/design/`, `docs/decisions/`) are developer reference — they are NOT part of the mkdocs site. ADRs are created/updated as part of implementation issues, not documentation issues.