mcp2mcpb 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.
- mcp2mcpb-0.1.0/.github/workflows/build-mcpb.yml +162 -0
- mcp2mcpb-0.1.0/.github/workflows/build-upstream.yml +137 -0
- mcp2mcpb-0.1.0/.github/workflows/check-upstream.yml +62 -0
- mcp2mcpb-0.1.0/.github/workflows/cicd.yml +295 -0
- mcp2mcpb-0.1.0/.gitignore +42 -0
- mcp2mcpb-0.1.0/.mcp.json +35 -0
- mcp2mcpb-0.1.0/.serena/.gitignore +2 -0
- mcp2mcpb-0.1.0/.serena/project.yml +135 -0
- mcp2mcpb-0.1.0/CHANGELOG.md +57 -0
- mcp2mcpb-0.1.0/CLAUDE.md +64 -0
- mcp2mcpb-0.1.0/LICENSE +21 -0
- mcp2mcpb-0.1.0/PKG-INFO +553 -0
- mcp2mcpb-0.1.0/README.md +520 -0
- mcp2mcpb-0.1.0/action.yml +182 -0
- mcp2mcpb-0.1.0/assets/claude-desktop-extensions.png +0 -0
- mcp2mcpb-0.1.0/assets/claude-desktop-install.png +0 -0
- mcp2mcpb-0.1.0/pyproject.toml +146 -0
- mcp2mcpb-0.1.0/scripts/check_version.py +82 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/__init__.py +6 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/__main__.py +486 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/bundler.py +177 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/exceptions.py +32 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/fetcher.py +252 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/generator.py +180 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/inspector.py +332 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/launch.py +145 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/licensing.py +67 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/models.py +241 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/packer.py +81 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/prober.py +103 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/py.typed +0 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/sandbox.py +351 -0
- mcp2mcpb-0.1.0/src/mcp2mcpb/ui.py +66 -0
- mcp2mcpb-0.1.0/tests/conftest.py +180 -0
- mcp2mcpb-0.1.0/tests/factories.py +151 -0
- mcp2mcpb-0.1.0/tests/test_bundler.py +350 -0
- mcp2mcpb-0.1.0/tests/test_cli.py +80 -0
- mcp2mcpb-0.1.0/tests/test_cli_more.py +374 -0
- mcp2mcpb-0.1.0/tests/test_conversion.py +257 -0
- mcp2mcpb-0.1.0/tests/test_coverage_small.py +250 -0
- mcp2mcpb-0.1.0/tests/test_fetcher.py +208 -0
- mcp2mcpb-0.1.0/tests/test_generator.py +406 -0
- mcp2mcpb-0.1.0/tests/test_inspector.py +147 -0
- mcp2mcpb-0.1.0/tests/test_launch.py +160 -0
- mcp2mcpb-0.1.0/tests/test_licensing.py +83 -0
- mcp2mcpb-0.1.0/tests/test_models.py +127 -0
- mcp2mcpb-0.1.0/tests/test_packer.py +103 -0
- mcp2mcpb-0.1.0/tests/test_prober.py +93 -0
- mcp2mcpb-0.1.0/tests/test_sandbox.py +208 -0
- mcp2mcpb-0.1.0/tests/test_sandbox_internals.py +402 -0
- mcp2mcpb-0.1.0/uv.lock +611 -0
- mcp2mcpb-0.1.0/versions.json +1 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
name: Build .mcpb bundle (reusable)
|
|
2
|
+
|
|
3
|
+
# Reusable workflow for MCP server authors. Add one job to your release
|
|
4
|
+
# pipeline:
|
|
5
|
+
#
|
|
6
|
+
# jobs:
|
|
7
|
+
# bundle:
|
|
8
|
+
# uses: Anselmoo/mcp2mcpb/.github/workflows/build-mcpb.yml@v1
|
|
9
|
+
# with:
|
|
10
|
+
# package: my-mcp-server
|
|
11
|
+
# registry: pypi
|
|
12
|
+
# mode: complete
|
|
13
|
+
#
|
|
14
|
+
# Self-contained: it installs the published `mcp2mcpb` package from PyPI
|
|
15
|
+
# and runs the CLI directly (it does NOT depend on the composite action tag).
|
|
16
|
+
# Launch recipe (runner/entry-script/extras/subcommand/transport) is optional โ
|
|
17
|
+
# omit it and the converter auto-detects from the package (and any in-package
|
|
18
|
+
# [tool.mcpb]/mcpb.toml). On a `release` event the bundle is attached to the
|
|
19
|
+
# release automatically.
|
|
20
|
+
|
|
21
|
+
on:
|
|
22
|
+
workflow_call:
|
|
23
|
+
inputs:
|
|
24
|
+
package:
|
|
25
|
+
description: Package name on PyPI or npm.
|
|
26
|
+
required: true
|
|
27
|
+
type: string
|
|
28
|
+
registry:
|
|
29
|
+
description: "'pypi' or 'npm'."
|
|
30
|
+
required: false
|
|
31
|
+
type: string
|
|
32
|
+
default: pypi
|
|
33
|
+
version:
|
|
34
|
+
description: Exact version to bundle. Defaults to the release tag (v-stripped).
|
|
35
|
+
required: false
|
|
36
|
+
type: string
|
|
37
|
+
default: ""
|
|
38
|
+
mode:
|
|
39
|
+
description: "'complete' (vendor deps) or 'reference' (uvx/npx)."
|
|
40
|
+
required: false
|
|
41
|
+
type: string
|
|
42
|
+
default: complete
|
|
43
|
+
python-version:
|
|
44
|
+
description: Python version used when vendoring dependencies.
|
|
45
|
+
required: false
|
|
46
|
+
type: string
|
|
47
|
+
default: "3.12"
|
|
48
|
+
output-dir:
|
|
49
|
+
description: Directory where .mcpb files are written.
|
|
50
|
+
required: false
|
|
51
|
+
type: string
|
|
52
|
+
default: dist
|
|
53
|
+
mcp2mcpb-version:
|
|
54
|
+
description: Version spec of the mcp2mcpb package to install from PyPI.
|
|
55
|
+
required: false
|
|
56
|
+
type: string
|
|
57
|
+
default: ">=0.1"
|
|
58
|
+
runner:
|
|
59
|
+
description: "Launch runner: uvx | npx | uv-run | python | node (empty = infer)."
|
|
60
|
+
required: false
|
|
61
|
+
type: string
|
|
62
|
+
default: ""
|
|
63
|
+
entry-script:
|
|
64
|
+
description: Console script (PyPI) / bin name (npm) to launch (empty = auto-detect).
|
|
65
|
+
required: false
|
|
66
|
+
type: string
|
|
67
|
+
default: ""
|
|
68
|
+
extras:
|
|
69
|
+
description: Space-separated package extras (PyPI/uv only), e.g. "mcp".
|
|
70
|
+
required: false
|
|
71
|
+
type: string
|
|
72
|
+
default: ""
|
|
73
|
+
subcommand:
|
|
74
|
+
description: Arguments appended after the entry script, e.g. "start-mcp-server".
|
|
75
|
+
required: false
|
|
76
|
+
type: string
|
|
77
|
+
default: ""
|
|
78
|
+
transport:
|
|
79
|
+
description: "Transport flag: stdio | none | auto (empty = auto)."
|
|
80
|
+
required: false
|
|
81
|
+
type: string
|
|
82
|
+
default: ""
|
|
83
|
+
no-probe:
|
|
84
|
+
description: Disable the --help auto-detection probe.
|
|
85
|
+
required: false
|
|
86
|
+
type: boolean
|
|
87
|
+
default: false
|
|
88
|
+
attach-to-release:
|
|
89
|
+
description: Attach the .mcpb files to the GitHub Release on a 'release' event.
|
|
90
|
+
required: false
|
|
91
|
+
type: boolean
|
|
92
|
+
default: true
|
|
93
|
+
|
|
94
|
+
jobs:
|
|
95
|
+
build-mcpb:
|
|
96
|
+
name: Build .mcpb bundle
|
|
97
|
+
runs-on: ubuntu-latest
|
|
98
|
+
permissions:
|
|
99
|
+
contents: write # needed to attach assets to a release
|
|
100
|
+
steps:
|
|
101
|
+
- name: Set up uv
|
|
102
|
+
uses: astral-sh/setup-uv@v4
|
|
103
|
+
with:
|
|
104
|
+
version: latest
|
|
105
|
+
|
|
106
|
+
- name: Set up Python
|
|
107
|
+
uses: actions/setup-python@v5
|
|
108
|
+
with:
|
|
109
|
+
python-version: ${{ inputs.python-version }}
|
|
110
|
+
|
|
111
|
+
- name: Install mcp2mcpb
|
|
112
|
+
shell: bash
|
|
113
|
+
env:
|
|
114
|
+
SPEC: ${{ inputs.mcp2mcpb-version }}
|
|
115
|
+
run: uv pip install --system "mcp2mcpb${SPEC}"
|
|
116
|
+
|
|
117
|
+
- name: Resolve version
|
|
118
|
+
id: resolve-version
|
|
119
|
+
shell: bash
|
|
120
|
+
env:
|
|
121
|
+
VERSION_INPUT: ${{ inputs.version }}
|
|
122
|
+
run: |
|
|
123
|
+
VERSION="$VERSION_INPUT"
|
|
124
|
+
if [[ -z "$VERSION" && -n "$GITHUB_REF_NAME" ]]; then
|
|
125
|
+
VERSION="${GITHUB_REF_NAME#v}"
|
|
126
|
+
fi
|
|
127
|
+
if [[ -z "$VERSION" ]]; then
|
|
128
|
+
echo "Error: could not resolve version. Set the 'version' input." >&2
|
|
129
|
+
exit 1
|
|
130
|
+
fi
|
|
131
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
132
|
+
|
|
133
|
+
- name: Build .mcpb bundle
|
|
134
|
+
shell: bash
|
|
135
|
+
env:
|
|
136
|
+
PACKAGE: ${{ inputs.package }}
|
|
137
|
+
REGISTRY: ${{ inputs.registry }}
|
|
138
|
+
VERSION: ${{ steps.resolve-version.outputs.version }}
|
|
139
|
+
MODE: ${{ inputs.mode }}
|
|
140
|
+
OUTPUT_DIR: ${{ inputs.output-dir }}
|
|
141
|
+
RUNNER: ${{ inputs.runner }}
|
|
142
|
+
ENTRY_SCRIPT: ${{ inputs.entry-script }}
|
|
143
|
+
EXTRAS: ${{ inputs.extras }}
|
|
144
|
+
SUBCOMMAND: ${{ inputs.subcommand }}
|
|
145
|
+
TRANSPORT: ${{ inputs.transport }}
|
|
146
|
+
NO_PROBE: ${{ inputs.no-probe }}
|
|
147
|
+
run: |
|
|
148
|
+
ARGS=( "$PACKAGE" --registry "$REGISTRY" --pin "$VERSION"
|
|
149
|
+
--mode "$MODE" --output "$OUTPUT_DIR" )
|
|
150
|
+
[[ -n "$RUNNER" ]] && ARGS+=( --runner "$RUNNER" )
|
|
151
|
+
[[ -n "$ENTRY_SCRIPT" ]] && ARGS+=( --entry-script "$ENTRY_SCRIPT" )
|
|
152
|
+
for extra in $EXTRAS; do ARGS+=( --extra "$extra" ); done
|
|
153
|
+
[[ -n "$SUBCOMMAND" ]] && ARGS+=( --subcommand "$SUBCOMMAND" )
|
|
154
|
+
[[ -n "$TRANSPORT" ]] && ARGS+=( --transport "$TRANSPORT" )
|
|
155
|
+
[[ "$NO_PROBE" == "true" ]] && ARGS+=( --no-probe )
|
|
156
|
+
python -m mcp2mcpb "${ARGS[@]}"
|
|
157
|
+
|
|
158
|
+
- name: Attach to GitHub Release
|
|
159
|
+
if: inputs.attach-to-release && github.event_name == 'release'
|
|
160
|
+
uses: softprops/action-gh-release@v2
|
|
161
|
+
with:
|
|
162
|
+
files: ${{ inputs.output-dir }}/*.mcpb
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
name: Build .mcpb bundles (upstream)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
package:
|
|
7
|
+
description: Package name
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
version:
|
|
11
|
+
description: Exact upstream version to bundle
|
|
12
|
+
required: true
|
|
13
|
+
type: string
|
|
14
|
+
registry:
|
|
15
|
+
description: pypi or npm
|
|
16
|
+
required: true
|
|
17
|
+
default: pypi
|
|
18
|
+
type: choice
|
|
19
|
+
options: [pypi, npm]
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
build:
|
|
23
|
+
name: Build (${{ matrix.platform }})
|
|
24
|
+
strategy:
|
|
25
|
+
fail-fast: false
|
|
26
|
+
matrix:
|
|
27
|
+
include:
|
|
28
|
+
- os: ubuntu-latest
|
|
29
|
+
platform: linux-x86_64
|
|
30
|
+
- os: macos-13
|
|
31
|
+
platform: macos-x86_64
|
|
32
|
+
- os: macos-latest
|
|
33
|
+
platform: macos-arm64
|
|
34
|
+
- os: windows-latest
|
|
35
|
+
platform: windows-x86_64
|
|
36
|
+
|
|
37
|
+
runs-on: ${{ matrix.os }}
|
|
38
|
+
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
|
|
42
|
+
- uses: astral-sh/setup-uv@v4
|
|
43
|
+
|
|
44
|
+
- name: Set up Python
|
|
45
|
+
uses: actions/setup-python@v5
|
|
46
|
+
with:
|
|
47
|
+
python-version: "3.12"
|
|
48
|
+
|
|
49
|
+
- name: Install mcp2mcpb
|
|
50
|
+
run: uv pip install --system -e ".[dev]"
|
|
51
|
+
|
|
52
|
+
- name: Build .mcpb bundle
|
|
53
|
+
run: |
|
|
54
|
+
python -m mcp2mcpb \
|
|
55
|
+
"${{ inputs.package }}" \
|
|
56
|
+
--registry "${{ inputs.registry }}" \
|
|
57
|
+
--pin "${{ inputs.version }}" \
|
|
58
|
+
--mode complete \
|
|
59
|
+
--output dist/
|
|
60
|
+
|
|
61
|
+
- name: Upload artifact
|
|
62
|
+
uses: actions/upload-artifact@v4
|
|
63
|
+
with:
|
|
64
|
+
name: mcpb-${{ matrix.platform }}
|
|
65
|
+
path: dist/*.mcpb
|
|
66
|
+
if-no-files-found: error
|
|
67
|
+
|
|
68
|
+
release:
|
|
69
|
+
name: Create GitHub Release
|
|
70
|
+
needs: build
|
|
71
|
+
runs-on: ubuntu-latest
|
|
72
|
+
permissions:
|
|
73
|
+
contents: write
|
|
74
|
+
|
|
75
|
+
steps:
|
|
76
|
+
- uses: actions/checkout@v4
|
|
77
|
+
with:
|
|
78
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
79
|
+
|
|
80
|
+
- name: Download all platform artifacts
|
|
81
|
+
uses: actions/download-artifact@v4
|
|
82
|
+
with:
|
|
83
|
+
path: dist/
|
|
84
|
+
merge-multiple: true
|
|
85
|
+
|
|
86
|
+
- name: List produced files
|
|
87
|
+
run: ls -lh dist/*.mcpb
|
|
88
|
+
|
|
89
|
+
- name: Create GitHub Release
|
|
90
|
+
uses: softprops/action-gh-release@v2
|
|
91
|
+
with:
|
|
92
|
+
tag_name: "${{ inputs.package }}-v${{ inputs.version }}"
|
|
93
|
+
name: "${{ inputs.package }} ${{ inputs.version }}"
|
|
94
|
+
files: dist/*.mcpb
|
|
95
|
+
generate_release_notes: false
|
|
96
|
+
body: |
|
|
97
|
+
## ${{ inputs.package }} ${{ inputs.version }}
|
|
98
|
+
|
|
99
|
+
One-click `.mcpb` bundles for Claude Desktop and any MCPB-compatible client.
|
|
100
|
+
|
|
101
|
+
### Installation
|
|
102
|
+
|
|
103
|
+
1. Download the `.mcpb` file for your platform below.
|
|
104
|
+
2. Open Claude Desktop โ Settings โ Extensions.
|
|
105
|
+
3. Drag and drop the `.mcpb` file into the Extensions page.
|
|
106
|
+
|
|
107
|
+
### Platform files
|
|
108
|
+
|
|
109
|
+
| File | Platform |
|
|
110
|
+
|------|----------|
|
|
111
|
+
| `*-linux-x86_64.mcpb` | Linux (x86_64) |
|
|
112
|
+
| `*-macos-x86_64.mcpb` | macOS (Intel) |
|
|
113
|
+
| `*-macos-arm64.mcpb` | macOS (Apple Silicon) |
|
|
114
|
+
| `*-windows-x86_64.mcpb` | Windows (x86_64) |
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
*Built by [mcp2mcpb](https://github.com/Anselmoo/mcp2mcpb)*
|
|
118
|
+
|
|
119
|
+
- name: Update versions.json
|
|
120
|
+
run: |
|
|
121
|
+
python - <<'EOF'
|
|
122
|
+
import json
|
|
123
|
+
from pathlib import Path
|
|
124
|
+
f = Path("versions.json")
|
|
125
|
+
versions = json.loads(f.read_text()) if f.exists() else {}
|
|
126
|
+
versions["${{ inputs.registry }}/${{ inputs.package }}"] = "${{ inputs.version }}"
|
|
127
|
+
f.write_text(json.dumps(versions, indent=2, sort_keys=True) + "\n")
|
|
128
|
+
EOF
|
|
129
|
+
|
|
130
|
+
- name: Commit updated versions.json
|
|
131
|
+
run: |
|
|
132
|
+
git config user.name "github-actions[bot]"
|
|
133
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
134
|
+
git add versions.json
|
|
135
|
+
git diff --cached --quiet || git commit -m \
|
|
136
|
+
"chore(versions): ${{ inputs.package }} โ ${{ inputs.version }}"
|
|
137
|
+
git push
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: Check upstream releases
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: "0 6 * * *" # daily 06:00 UTC
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
package:
|
|
9
|
+
description: Package name (e.g. mcp-server-fetch)
|
|
10
|
+
required: true
|
|
11
|
+
type: string
|
|
12
|
+
registry:
|
|
13
|
+
description: pypi or npm
|
|
14
|
+
required: true
|
|
15
|
+
default: pypi
|
|
16
|
+
type: choice
|
|
17
|
+
options: [pypi, npm]
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
check:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
permissions:
|
|
23
|
+
actions: write # needed to trigger workflow_dispatch
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- name: Set up Python
|
|
29
|
+
uses: actions/setup-python@v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.12"
|
|
32
|
+
|
|
33
|
+
- name: Install httpx
|
|
34
|
+
run: pip install httpx --quiet
|
|
35
|
+
|
|
36
|
+
- name: Check for new version
|
|
37
|
+
id: check
|
|
38
|
+
env:
|
|
39
|
+
PACKAGE: ${{ inputs.package || 'mcp-server-fetch' }}
|
|
40
|
+
REGISTRY: ${{ inputs.registry || 'pypi' }}
|
|
41
|
+
run: |
|
|
42
|
+
python scripts/check_version.py \
|
|
43
|
+
--package "$PACKAGE" \
|
|
44
|
+
--registry "$REGISTRY" \
|
|
45
|
+
--versions-file versions.json
|
|
46
|
+
|
|
47
|
+
- name: Trigger build if new version found
|
|
48
|
+
if: steps.check.outputs.new_version != ''
|
|
49
|
+
uses: actions/github-script@v7
|
|
50
|
+
with:
|
|
51
|
+
script: |
|
|
52
|
+
await github.rest.actions.createWorkflowDispatch({
|
|
53
|
+
owner: context.repo.owner,
|
|
54
|
+
repo: context.repo.repo,
|
|
55
|
+
workflow_id: 'build-upstream.yml',
|
|
56
|
+
ref: 'main',
|
|
57
|
+
inputs: {
|
|
58
|
+
package: '${{ steps.check.outputs.package }}',
|
|
59
|
+
version: '${{ steps.check.outputs.new_version }}',
|
|
60
|
+
registry: '${{ steps.check.outputs.registry }}',
|
|
61
|
+
},
|
|
62
|
+
})
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
name: ๐ CI/CD
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- feat/**
|
|
8
|
+
- fix/**
|
|
9
|
+
- chore/**
|
|
10
|
+
- docs/**
|
|
11
|
+
- refactor/**
|
|
12
|
+
- test/**
|
|
13
|
+
- ci/**
|
|
14
|
+
- perf/**
|
|
15
|
+
- style/**
|
|
16
|
+
- build/**
|
|
17
|
+
tags: ["v*.*.*"]
|
|
18
|
+
pull_request:
|
|
19
|
+
branches: [main]
|
|
20
|
+
workflow_dispatch:
|
|
21
|
+
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
|
|
25
|
+
concurrency:
|
|
26
|
+
group: ci-cd-${{ github.ref }}
|
|
27
|
+
cancel-in-progress: true
|
|
28
|
+
|
|
29
|
+
env:
|
|
30
|
+
PACKAGE_NAME: "mcp2mcpb"
|
|
31
|
+
PYTHON_VERSION: "3.12"
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
lint:
|
|
35
|
+
name: ๐ Lint & types
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
steps:
|
|
38
|
+
- name: Checkout
|
|
39
|
+
uses: actions/checkout@v6
|
|
40
|
+
with:
|
|
41
|
+
fetch-depth: 0 # rrt needs history for branch/commit/changelog checks
|
|
42
|
+
|
|
43
|
+
- name: Set up Python
|
|
44
|
+
uses: actions/setup-python@v6
|
|
45
|
+
with:
|
|
46
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
47
|
+
|
|
48
|
+
- name: Set up uv
|
|
49
|
+
uses: astral-sh/setup-uv@v7
|
|
50
|
+
with:
|
|
51
|
+
enable-cache: true
|
|
52
|
+
|
|
53
|
+
- name: Sync dependencies
|
|
54
|
+
run: uv sync --extra dev
|
|
55
|
+
|
|
56
|
+
- name: Ruff lint
|
|
57
|
+
run: uv run ruff check src tests
|
|
58
|
+
|
|
59
|
+
- name: Ruff format check
|
|
60
|
+
run: uv run ruff format --check src tests
|
|
61
|
+
|
|
62
|
+
- name: ty type check
|
|
63
|
+
run: uv run ty check
|
|
64
|
+
|
|
65
|
+
- name: Validate release policy (rrt)
|
|
66
|
+
if: github.event_name == 'pull_request' || startsWith(github.ref, 'refs/tags/')
|
|
67
|
+
uses: Anselmoo/repo-release-tools@v1.9.0
|
|
68
|
+
with:
|
|
69
|
+
check-branch-name: "true"
|
|
70
|
+
check-commit-subject: "true"
|
|
71
|
+
check-changelog: "true"
|
|
72
|
+
changelog-strategy: "release-only"
|
|
73
|
+
check-release-health: "true"
|
|
74
|
+
|
|
75
|
+
test:
|
|
76
|
+
name: ๐งช Tests (${{ matrix.python-version }})
|
|
77
|
+
needs: lint
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
strategy:
|
|
80
|
+
fail-fast: false
|
|
81
|
+
matrix:
|
|
82
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
83
|
+
steps:
|
|
84
|
+
- name: Checkout
|
|
85
|
+
uses: actions/checkout@v6
|
|
86
|
+
|
|
87
|
+
- name: Set up Python
|
|
88
|
+
uses: actions/setup-python@v6
|
|
89
|
+
with:
|
|
90
|
+
python-version: ${{ matrix.python-version }}
|
|
91
|
+
|
|
92
|
+
- name: Set up uv
|
|
93
|
+
uses: astral-sh/setup-uv@v7
|
|
94
|
+
with:
|
|
95
|
+
enable-cache: true
|
|
96
|
+
|
|
97
|
+
- name: Sync dependencies
|
|
98
|
+
run: uv sync --extra dev
|
|
99
|
+
|
|
100
|
+
- name: Run tests
|
|
101
|
+
run: uv run pytest --cov=src/mcp2mcpb --cov-report=xml
|
|
102
|
+
|
|
103
|
+
- name: Upload coverage to Codecov
|
|
104
|
+
uses: codecov/codecov-action@v5
|
|
105
|
+
with:
|
|
106
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
107
|
+
files: ./coverage.xml
|
|
108
|
+
flags: python-${{ matrix.python-version }}
|
|
109
|
+
name: mcp2mcpb-${{ matrix.python-version }}
|
|
110
|
+
fail_ci_if_error: false
|
|
111
|
+
verbose: false
|
|
112
|
+
|
|
113
|
+
build:
|
|
114
|
+
name: ๐ฆ Build package
|
|
115
|
+
needs: test
|
|
116
|
+
if: github.event_name != 'pull_request'
|
|
117
|
+
runs-on: ubuntu-latest
|
|
118
|
+
steps:
|
|
119
|
+
- name: Checkout
|
|
120
|
+
uses: actions/checkout@v6
|
|
121
|
+
|
|
122
|
+
- name: Set up Python
|
|
123
|
+
uses: actions/setup-python@v6
|
|
124
|
+
with:
|
|
125
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
126
|
+
|
|
127
|
+
- name: Set up uv
|
|
128
|
+
uses: astral-sh/setup-uv@v7
|
|
129
|
+
with:
|
|
130
|
+
enable-cache: true
|
|
131
|
+
|
|
132
|
+
- name: Build distributions
|
|
133
|
+
run: uv build
|
|
134
|
+
|
|
135
|
+
- name: Check distributions
|
|
136
|
+
run: uvx twine check dist/*
|
|
137
|
+
|
|
138
|
+
- name: Upload distribution artifacts
|
|
139
|
+
uses: actions/upload-artifact@v7
|
|
140
|
+
with:
|
|
141
|
+
name: python-package-distributions
|
|
142
|
+
path: dist/
|
|
143
|
+
|
|
144
|
+
sbom:
|
|
145
|
+
name: ๐ Generate SBOM
|
|
146
|
+
needs: build
|
|
147
|
+
if: github.event_name != 'pull_request'
|
|
148
|
+
runs-on: ubuntu-latest
|
|
149
|
+
permissions:
|
|
150
|
+
contents: read
|
|
151
|
+
steps:
|
|
152
|
+
- name: Checkout
|
|
153
|
+
uses: actions/checkout@v6
|
|
154
|
+
|
|
155
|
+
- name: Generate SBOM
|
|
156
|
+
uses: anchore/sbom-action@v0
|
|
157
|
+
with:
|
|
158
|
+
format: spdx-json
|
|
159
|
+
output-file: sbom.spdx.json
|
|
160
|
+
path: .
|
|
161
|
+
|
|
162
|
+
- name: Upload SBOM artifact
|
|
163
|
+
uses: actions/upload-artifact@v7
|
|
164
|
+
with:
|
|
165
|
+
name: sbom
|
|
166
|
+
path: sbom.spdx.json
|
|
167
|
+
|
|
168
|
+
attest:
|
|
169
|
+
name: ๐ก๏ธ Attest build provenance
|
|
170
|
+
needs: build
|
|
171
|
+
if: github.event_name != 'pull_request'
|
|
172
|
+
runs-on: ubuntu-latest
|
|
173
|
+
permissions:
|
|
174
|
+
contents: read
|
|
175
|
+
id-token: write
|
|
176
|
+
attestations: write
|
|
177
|
+
steps:
|
|
178
|
+
- name: Download distribution artifacts
|
|
179
|
+
uses: actions/download-artifact@v8
|
|
180
|
+
with:
|
|
181
|
+
name: python-package-distributions
|
|
182
|
+
path: dist/
|
|
183
|
+
|
|
184
|
+
- name: Generate provenance attestation
|
|
185
|
+
uses: actions/attest-build-provenance@v4
|
|
186
|
+
with:
|
|
187
|
+
subject-path: dist/*
|
|
188
|
+
|
|
189
|
+
publish-testpypi:
|
|
190
|
+
name: ๐งช Publish to TestPyPI
|
|
191
|
+
needs: [build, sbom, attest]
|
|
192
|
+
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
|
193
|
+
runs-on: ubuntu-latest
|
|
194
|
+
permissions:
|
|
195
|
+
id-token: write
|
|
196
|
+
environment:
|
|
197
|
+
name: testpypi
|
|
198
|
+
url: https://test.pypi.org/p/mcp2mcpb
|
|
199
|
+
steps:
|
|
200
|
+
- name: Download distribution artifacts
|
|
201
|
+
uses: actions/download-artifact@v8
|
|
202
|
+
with:
|
|
203
|
+
name: python-package-distributions
|
|
204
|
+
path: dist/
|
|
205
|
+
|
|
206
|
+
- name: Publish to TestPyPI
|
|
207
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
208
|
+
with:
|
|
209
|
+
repository-url: https://test.pypi.org/legacy/
|
|
210
|
+
skip-existing: true
|
|
211
|
+
|
|
212
|
+
verify-testpypi:
|
|
213
|
+
name: ๐งช Verify TestPyPI package
|
|
214
|
+
needs: publish-testpypi
|
|
215
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
|
216
|
+
runs-on: ubuntu-latest
|
|
217
|
+
steps:
|
|
218
|
+
- name: Set up Python
|
|
219
|
+
uses: actions/setup-python@v6
|
|
220
|
+
with:
|
|
221
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
222
|
+
|
|
223
|
+
- name: Upgrade pip
|
|
224
|
+
run: python -m pip install --upgrade pip
|
|
225
|
+
|
|
226
|
+
- name: Install package from TestPyPI
|
|
227
|
+
shell: bash
|
|
228
|
+
run: |
|
|
229
|
+
set -euo pipefail
|
|
230
|
+
VERSION="${GITHUB_REF_NAME#v}"
|
|
231
|
+
for attempt in {1..8}; do
|
|
232
|
+
if python -m pip install \
|
|
233
|
+
--index-url https://test.pypi.org/simple/ \
|
|
234
|
+
--extra-index-url https://pypi.org/simple/ \
|
|
235
|
+
"${PACKAGE_NAME}==${VERSION}"; then
|
|
236
|
+
break
|
|
237
|
+
fi
|
|
238
|
+
if [ "$attempt" -eq 8 ]; then
|
|
239
|
+
echo "Package was not installable from TestPyPI after retries."
|
|
240
|
+
exit 1
|
|
241
|
+
fi
|
|
242
|
+
echo "Retrying TestPyPI install in 20s (attempt ${attempt}/8)..."
|
|
243
|
+
sleep 20
|
|
244
|
+
done
|
|
245
|
+
|
|
246
|
+
- name: Smoke test installed CLI
|
|
247
|
+
run: mcp2mcpb --version
|
|
248
|
+
|
|
249
|
+
publish-pypi:
|
|
250
|
+
name: ๐ Publish to PyPI
|
|
251
|
+
needs: [build, sbom, attest, publish-testpypi, verify-testpypi]
|
|
252
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
|
253
|
+
runs-on: ubuntu-latest
|
|
254
|
+
permissions:
|
|
255
|
+
id-token: write
|
|
256
|
+
environment:
|
|
257
|
+
name: pypi
|
|
258
|
+
url: https://pypi.org/p/mcp2mcpb
|
|
259
|
+
steps:
|
|
260
|
+
- name: Download distribution artifacts
|
|
261
|
+
uses: actions/download-artifact@v8
|
|
262
|
+
with:
|
|
263
|
+
name: python-package-distributions
|
|
264
|
+
path: dist/
|
|
265
|
+
|
|
266
|
+
- name: Publish to PyPI
|
|
267
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
268
|
+
|
|
269
|
+
github-release:
|
|
270
|
+
name: ๐ Create GitHub release
|
|
271
|
+
needs: [publish-pypi, sbom]
|
|
272
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
|
273
|
+
runs-on: ubuntu-latest
|
|
274
|
+
permissions:
|
|
275
|
+
contents: write
|
|
276
|
+
steps:
|
|
277
|
+
- name: Download distribution artifacts
|
|
278
|
+
uses: actions/download-artifact@v8
|
|
279
|
+
with:
|
|
280
|
+
name: python-package-distributions
|
|
281
|
+
path: dist/
|
|
282
|
+
|
|
283
|
+
- name: Download SBOM artifact
|
|
284
|
+
uses: actions/download-artifact@v8
|
|
285
|
+
with:
|
|
286
|
+
name: sbom
|
|
287
|
+
path: .
|
|
288
|
+
|
|
289
|
+
- name: Create GitHub release
|
|
290
|
+
uses: softprops/action-gh-release@v2
|
|
291
|
+
with:
|
|
292
|
+
generate_release_notes: true
|
|
293
|
+
files: |
|
|
294
|
+
dist/*
|
|
295
|
+
sbom.spdx.json
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.eggs/
|
|
11
|
+
*.egg
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
env/
|
|
17
|
+
|
|
18
|
+
# uv
|
|
19
|
+
.uv/
|
|
20
|
+
|
|
21
|
+
# Testing / coverage
|
|
22
|
+
.pytest_cache/
|
|
23
|
+
.mypy_cache/
|
|
24
|
+
.ruff_cache/
|
|
25
|
+
.coverage
|
|
26
|
+
.coverage.*
|
|
27
|
+
htmlcov/
|
|
28
|
+
|
|
29
|
+
# IDEs
|
|
30
|
+
.idea/
|
|
31
|
+
.vscode/
|
|
32
|
+
|
|
33
|
+
# OS
|
|
34
|
+
.DS_Store
|
|
35
|
+
|
|
36
|
+
# Local Claude Code settings
|
|
37
|
+
.claude/settings.local.json
|
|
38
|
+
|
|
39
|
+
# mcp2mcpb artifacts
|
|
40
|
+
*.mcpb
|
|
41
|
+
.mcpb-cache/
|
|
42
|
+
docs/
|