name: Release binaries
on:
push:
tags: ["v*"]
workflow_dispatch:
inputs:
tag:
description: "Tag to build and attach to (e.g. v0.1.5)"
required: true
permissions:
contents: write
jobs:
build:
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
- os: macos-14
target: aarch64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-msvc
steps:
- uses: actions/checkout@v4
- name: Install the Rust target
run: rustup target add ${{ matrix.target }}
- name: Build
run: cargo build --release --bin effectfence --target ${{ matrix.target }}
- name: Prove the binary answers MCP introspection (unix)
if: runner.os != 'Windows'
run: |
set -euo pipefail
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2026-07-28","capabilities":{},"clientInfo":{"name":"ci","version":"0"}}}' \
| ./target/${{ matrix.target }}/release/effectfence | tee out.json
grep -q '"serverInfo"' out.json
grep -q 'effectfence' out.json
- name: Prove the binary answers MCP introspection (windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$req = '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2026-07-28","capabilities":{},"clientInfo":{"name":"ci","version":"0"}}}'
$out = $req | & ".\target\${{ matrix.target }}\release\effectfence.exe"
$out | Out-File -Encoding utf8 out.json
if ($out -notmatch '"serverInfo"') { throw "no serverInfo in initialize response" }
if ($out -notmatch 'effectfence') { throw "server did not identify as effectfence" }
- name: Package (unix)
if: runner.os != 'Windows'
run: |
set -euo pipefail
tar -czf effectfence-${{ matrix.target }}.tar.gz \
-C target/${{ matrix.target }}/release effectfence
shasum -a 256 effectfence-${{ matrix.target }}.tar.gz \
> effectfence-${{ matrix.target }}.tar.gz.sha256
- name: Package (windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
Compress-Archive -Path "target\${{ matrix.target }}\release\effectfence.exe" `
-DestinationPath "effectfence-${{ matrix.target }}.zip"
$h = (Get-FileHash "effectfence-${{ matrix.target }}.zip" -Algorithm SHA256).Hash.ToLower()
"$h effectfence-${{ matrix.target }}.zip" |
Out-File -Encoding ascii "effectfence-${{ matrix.target }}.zip.sha256"
- uses: actions/upload-artifact@v4
with:
name: effectfence-${{ matrix.target }}
path: |
effectfence-${{ matrix.target }}.tar.gz*
effectfence-${{ matrix.target }}.zip*
if-no-files-found: error
publish:
name: attach every platform to the release
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: Publish to the release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.event.inputs.tag || github.ref_name }}
run: |
set -euo pipefail
ls -la artifacts
gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 \
|| gh release create "$TAG" --repo "$GITHUB_REPOSITORY" --title "$TAG" \
--notes "Prebuilt EffectFence MCP server binaries for Linux (x64, arm64), macOS (Apple silicon) and Windows (x64). No Rust toolchain required. Each binary answered an MCP \`initialize\` on its own platform before being attached."
gh release upload "$TAG" artifacts/* --repo "$GITHUB_REPOSITORY" --clobber