Files
2026-06-25 16:15:46 +07:00

426 lines
16 KiB
YAML

name: Build and Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Version tag (e.g., v1.32.0)'
required: true
type: string
jobs:
# ── Build binaries ───────────────────────────────────────────────────────────
build-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: macos-cargo-${{ hashFiles('Cargo.lock') }}
restore-keys: macos-cargo-
- name: Build release binary
run: cargo build --release
- name: Package binary
run: |
mkdir -p dist/mcp-mt5-quant-macos
cp target/release/mt5-quant dist/mcp-mt5-quant-macos/
cp -r config dist/mcp-mt5-quant-macos/
cp README.md dist/mcp-mt5-quant-macos/
cp -r docs dist/mcp-mt5-quant-macos/
cd dist
tar -czf mcp-mt5-quant-macos-arm64.tar.gz mcp-mt5-quant-macos
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: macos-binary
path: dist/mcp-mt5-quant-macos-arm64.tar.gz
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: linux-cargo-${{ hashFiles('Cargo.lock') }}
restore-keys: linux-cargo-
- name: Build release binary
run: cargo build --release
- name: Package binary
run: |
mkdir -p dist/mcp-mt5-quant-linux
cp target/release/mt5-quant dist/mcp-mt5-quant-linux/
cp -r config dist/mcp-mt5-quant-linux/
cp README.md dist/mcp-mt5-quant-linux/
cp -r docs dist/mcp-mt5-quant-linux/
cd dist
tar -czf mcp-mt5-quant-linux-x64.tar.gz mcp-mt5-quant-linux
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: linux-binary
path: dist/mcp-mt5-quant-linux-x64.tar.gz
# ── Cargo Publish ────────────────────────────────────────────────────────────
cargo-publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: cargo-publish-${{ hashFiles('Cargo.lock') }}
restore-keys: cargo-publish-
- name: Publish to crates.io
run: cargo publish --no-verify --allow-dirty
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
# ── GitHub Release ───────────────────────────────────────────────────────────
release:
needs: [build-macos, build-linux, cargo-publish]
runs-on: ubuntu-latest
permissions:
contents: write
env:
RELEASE_TAG: ${{ github.event.inputs.version || github.ref_name }}
steps:
- uses: actions/checkout@v4
- name: Download macOS artifact
uses: actions/download-artifact@v4
with:
name: macos-binary
path: dist
- name: Download Linux artifact
uses: actions/download-artifact@v4
with:
name: linux-binary
path: dist
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.RELEASE_TAG }}
name: ${{ env.RELEASE_TAG }}
files: |
dist/mcp-mt5-quant-macos-arm64.tar.gz
dist/mcp-mt5-quant-linux-x64.tar.gz
draft: false
prerelease: false
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ── MCP Package ──────────────────────────────────────────────────────────────
# Builds the installable MCP package (binary + config + docs),
# computes its SHA256, and uploads to the release.
build-mcp-package:
needs: release
runs-on: macos-latest
permissions:
contents: write
outputs:
sha256: ${{ steps.compute-sha256.outputs.sha256 }}
env:
RELEASE_TAG: ${{ github.event.inputs.version || github.ref_name }}
steps:
- uses: actions/checkout@v4
- name: Download macOS binary
uses: actions/download-artifact@v4
with:
name: macos-binary
path: dist
- name: Build MCP package
run: |
mkdir -p mcp-package/mcp-server/bin
cd dist && tar -xzf mcp-mt5-quant-macos-arm64.tar.gz && cd ..
cp dist/mcp-mt5-quant-macos/mt5-quant mcp-package/mcp-server/bin/
cp -r config mcp-package/
cp -r docs mcp-package/
cp README.md mcp-package/
cp server.json mcp-package/
cd mcp-package && tar -czf ../mcp-mt5-quant-macos-arm64.tar.gz . && cd ..
- name: Compute SHA256
id: compute-sha256
run: |
SHA256=$(shasum -a 256 mcp-mt5-quant-macos-arm64.tar.gz | awk '{print $1}')
echo "sha256=$SHA256" >> "$GITHUB_OUTPUT"
echo "MCP Package SHA256: $SHA256"
- name: Upload MCP package to release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.RELEASE_TAG }}
files: mcp-mt5-quant-macos-arm64.tar.gz
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload MCP package artifact
uses: actions/upload-artifact@v4
with:
name: mcp-package
path: mcp-mt5-quant-macos-arm64.tar.gz
# ── Update server.json SHA256 ────────────────────────────────────────────────
# Commits the computed SHA256 back to master so server.json always
# reflects the latest published package hash.
update-server-json:
needs: build-mcp-package
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
ref: master
fetch-depth: 1
token: ${{ secrets.GITHUB_TOKEN }}
- name: Patch server.json
env:
PKG_SHA256: ${{ needs.build-mcp-package.outputs.sha256 }}
RELEASE_TAG: ${{ github.event.inputs.version || github.ref_name }}
run: |
VERSION="${RELEASE_TAG#v}"
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
VERSION="$VERSION" PKG_SHA256="$PKG_SHA256" python3 - <<'PYEOF'
import json, os, re
sha256 = os.environ['PKG_SHA256']
version = os.environ['VERSION']
with open('server.json') as f:
data = json.load(f)
data['version'] = version
for pkg in data.get('packages', []):
pkg['version'] = version
pkg['fileSha256'] = sha256
if 'identifier' in pkg:
pkg['identifier'] = re.sub(
r'/v[0-9]+\.[0-9]+\.[0-9]+/',
f'/v{version}/',
pkg['identifier']
)
with open('server.json', 'w') as f:
json.dump(data, f, indent=2)
f.write('\n')
print(f"Patched: version={version}, sha256={sha256[:16]}...")
PYEOF
- name: Commit server.json
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add server.json
if git diff --cached --quiet; then
echo "server.json unchanged — no commit needed"
else
git commit -m "ci: update server.json SHA256 for v${VERSION} [skip ci]"
git push origin master
echo "Committed server.json update"
fi
# ── MCP Registry Publish ─────────────────────────────────────────────────────
mcp-publish:
needs: [build-mcp-package, update-server-json]
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for GitHub OIDC
steps:
- uses: actions/checkout@v4
with:
ref: master # Pull master so server.json has the correct SHA256
- name: Download MCP package
uses: actions/download-artifact@v4
with:
name: mcp-package
path: .
- name: Install mcp-publisher
id: install-publisher
run: |
# Fetch the download URL for linux_amd64 directly from the release assets API
# (asset name format changed in v1.6.0 — look it up rather than constructing it)
URL=$(curl -sf \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/modelcontextprotocol/registry/releases/latest" \
| python3 -c "
import sys, json
r = json.load(sys.stdin)
tag = r['tag_name']
assets = r.get('assets', [])
match = next((a['browser_download_url'] for a in assets
if 'linux' in a['name'] and 'amd64' in a['name']
and a['name'].endswith('.tar.gz')
and 'sbom' not in a['name']
and 'sigstore' not in a['name']), None)
if match:
print(match)
else:
print(f'https://github.com/modelcontextprotocol/registry/releases/download/{tag}/mcp-publisher_linux_amd64.tar.gz', file=sys.stderr)
sys.exit(1)
" 2>/dev/null)
if [[ -z "$URL" ]]; then
echo "installed=false" >> "$GITHUB_OUTPUT"
echo "Could not resolve mcp-publisher download URL"
else
echo "Downloading: $URL"
if curl -fsSL -o mcp-publisher.tar.gz "$URL"; then
tar -xzf mcp-publisher.tar.gz 2>/dev/null || true
BINARY=$(find . -maxdepth 3 -name "mcp-publisher" ! -path "./.git/*" | head -1)
if [[ -n "$BINARY" && -f "$BINARY" ]]; then
chmod +x "$BINARY"
sudo mv "$BINARY" /usr/local/bin/mcp-publisher
echo "installed=true" >> "$GITHUB_OUTPUT"
echo "Installed: $(mcp-publisher --version 2>/dev/null || echo 'ok')"
else
echo "installed=false" >> "$GITHUB_OUTPUT"
echo "Binary not found in archive"
fi
rm -f mcp-publisher.tar.gz
else
echo "installed=false" >> "$GITHUB_OUTPUT"
echo "Download failed: $URL"
fi
fi
- name: Validate server.json before publish
id: validate
run: |
python3 - <<'PYEOF'
import json, sys
with open('server.json') as f:
data = json.load(f)
print(f" name: {data.get('name')}")
print(f" version: {data.get('version')}")
ok = True
for pkg in data.get('packages', []):
sha = pkg.get('fileSha256', '')
ident = pkg.get('identifier', '')
print(f" sha256: {sha}")
print(f" url: {ident}")
if sha in ('', 'TBD_CI_WILL_UPDATE', 'TBD_UPDATED_BY_CI'):
print('ERROR: fileSha256 is a placeholder — publish aborted')
ok = False
sys.exit(0 if ok else 1)
PYEOF
- name: Publish to MCP Registry
if: steps.install-publisher.outputs.installed == 'true' && steps.validate.outcome == 'success'
run: |
echo "=== Authenticating with GitHub OIDC ==="
mcp-publisher login github-oidc || {
echo "OIDC login failed"
exit 1
}
echo "=== Publishing ==="
mcp-publisher publish && echo "✓ Published to MCP Registry" || {
echo ""
echo "══════════════════════════════════════════════════════════"
echo " AUTOMATED MCP PUBLISH FAILED — manual steps:"
echo "══════════════════════════════════════════════════════════"
echo " 1. Download: https://github.com/modelcontextprotocol/registry/releases"
echo " 2. ./mcp-publisher login github"
echo " 3. ./mcp-publisher publish"
echo " Web UI: https://registry.modelcontextprotocol.io"
echo "══════════════════════════════════════════════════════════"
exit 0 # Don't fail the workflow — release succeeded
}
- name: Skip notice
if: steps.install-publisher.outputs.installed != 'true'
run: |
echo "mcp-publisher not installed — skipping automated publish"
echo "Manual: https://registry.modelcontextprotocol.io"
# ── Release Summary ──────────────────────────────────────────────────────────
release-info:
needs: [mcp-publish]
runs-on: ubuntu-latest
env:
RELEASE_TAG: ${{ github.event.inputs.version || github.ref_name }}
steps:
- name: Summary
run: |
echo ""
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ Release ${RELEASE_TAG} complete! "
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""
echo "GitHub Release:"
echo " https://github.com/masdevid/mt5-quant/releases/tag/${RELEASE_TAG}"
echo ""
echo "MCP Registry: io.github.masdevid/mt5-quant"
echo ""
echo "── MCP Client Registration ──────────────────────────────────"
echo ""
echo "Claude Code:"
echo " claude mcp add io.github.masdevid/mt5-quant -- ~/.local/bin/mt5-quant"
echo ""
echo "Windsurf (~/.codeium/windsurf/mcp_config.json):"
echo ' {"mcpServers": {"io.github.masdevid/mt5-quant": {"command": "~/.local/bin/mt5-quant"}}}'
echo ""
echo "Cursor / VS Code (~/.cursor/mcp.json):"
echo ' {"mcpServers": {"mt5-quant": {"command": "~/.local/bin/mt5-quant"}}}'
echo ""
echo "─────────────────────────────────────────────────────────────"