name: Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
build:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
archive: tar.gz
binary: task-graph-mcp
- target: x86_64-apple-darwin
os: macos-latest
archive: tar.gz
binary: task-graph-mcp
- target: aarch64-apple-darwin
os: macos-latest
archive: tar.gz
binary: task-graph-mcp
- target: x86_64-pc-windows-msvc
os: windows-latest
archive: zip
binary: task-graph-mcp.exe
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Build
run: cargo build --release --target ${{ matrix.target }}
- name: Package (Unix)
if: matrix.os != 'windows-latest'
run: |
cd target/${{ matrix.target }}/release
tar czvf ../../../task-graph-mcp-${{ matrix.target }}.tar.gz task-graph-mcp
cd ../../..
- name: Package (Windows)
if: matrix.os == 'windows-latest'
run: |
cd target/${{ matrix.target }}/release
7z a ../../../task-graph-mcp-${{ matrix.target }}.zip task-graph-mcp.exe
cd ../../..
- name: Extract version from tag
id: version
shell: bash
run: |
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
else
echo "version=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')" >> "$GITHUB_OUTPUT"
fi
- name: Create MCPB bundle
shell: bash
run: |
VERSION="${{ steps.version.outputs.version }}"
TARGET="${{ matrix.target }}"
BINARY="${{ matrix.binary }}"
mkdir -p mcpb-staging
cp "target/${TARGET}/release/${BINARY}" mcpb-staging/
cat > mcpb-staging/manifest.json << EOF
{
"manifest_version": "0.3",
"name": "task-graph-mcp",
"version": "${VERSION}",
"description": "MCP server for agent task workflows with phases, prompts, gates, and multi-agent coordination",
"author": {
"name": "Oortonaut",
"url": "https://github.com/Oortonaut"
},
"license": "Apache-2.0",
"repository": "https://github.com/Oortonaut/task-graph-mcp",
"server": {
"type": "binary",
"entry_point": "${BINARY}",
"mcp_config": {
"command": "${BINARY}",
"args": [],
"env": {}
}
},
"tools": [
{"name": "connect", "description": "Register agent and join workflow"},
{"name": "create", "description": "Create a new task"},
{"name": "create_tree", "description": "Create a task hierarchy from YAML"},
{"name": "update", "description": "Update task state, description, or dependencies"},
{"name": "get", "description": "Get full task details"},
{"name": "list_tasks", "description": "List and filter tasks"},
{"name": "delete", "description": "Delete a task"},
{"name": "rename", "description": "Rename a task ID"},
{"name": "claim", "description": "Claim a ready task"},
{"name": "scan", "description": "Get task tree with agent context"},
{"name": "thinking", "description": "Record agent reasoning"},
{"name": "query", "description": "Run read-only SQL queries"},
{"name": "link", "description": "Add dependency between tasks"},
{"name": "unlink", "description": "Remove dependency between tasks"},
{"name": "mark_file", "description": "Lock a file for an agent"},
{"name": "unmark_file", "description": "Release a file lock"},
{"name": "list_marks", "description": "List active file locks"},
{"name": "check_gates", "description": "Evaluate workflow gate conditions"},
{"name": "list_workflows", "description": "List available workflows"},
{"name": "add_overlay", "description": "Add a dynamic workflow overlay"},
{"name": "remove_overlay", "description": "Remove a workflow overlay"},
{"name": "give_feedback", "description": "Record inter-agent feedback"},
{"name": "list_feedback", "description": "List recorded agent feedback"},
{"name": "list_skills", "description": "List available bundled skills"},
{"name": "get_skill", "description": "Get bundled skill content"},
{"name": "cleanup_stale", "description": "Evict stale workers"}
],
"keywords": ["mcp", "agent-workflow", "multi-agent", "task-management", "coordination"]
}
EOF
cd mcpb-staging
if command -v zip &> /dev/null; then
zip -r "../task-graph-mcp-${TARGET}.mcpb" .
elif command -v 7z &> /dev/null; then
7z a -tzip "../task-graph-mcp-${TARGET}.mcpb" .
else
echo "No zip tool available" && exit 1
fi
cd ..
# Compute SHA-256
if command -v sha256sum &> /dev/null; then
SHA=$(sha256sum "task-graph-mcp-${TARGET}.mcpb" | awk '{print $1}')
elif command -v shasum &> /dev/null; then
SHA=$(shasum -a 256 "task-graph-mcp-${TARGET}.mcpb" | awk '{print $1}')
else
SHA=$(openssl dgst -sha256 "task-graph-mcp-${TARGET}.mcpb" | awk '{print $NF}')
fi
echo "sha256=${SHA}" >> "$GITHUB_OUTPUT"
echo "${TARGET}=${SHA}" > "mcpb-sha256-${TARGET}.txt"
id: mcpb
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: task-graph-mcp-${{ matrix.target }}
path: |
task-graph-mcp-${{ matrix.target }}.${{ matrix.archive }}
task-graph-mcp-${{ matrix.target }}.mcpb
mcpb-sha256-${{ matrix.target }}.txt
release:
name: Create Release
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Extract version from tag
id: version
run: echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
- name: Generate server.json with SHA-256 hashes
run: |
VERSION="${{ steps.version.outputs.version }}"
# Read SHA-256 hashes
SHA_LINUX=$(cat artifacts/task-graph-mcp-x86_64-unknown-linux-gnu/mcpb-sha256-x86_64-unknown-linux-gnu.txt | cut -d= -f2)
SHA_MACOS_X86=$(cat artifacts/task-graph-mcp-x86_64-apple-darwin/mcpb-sha256-x86_64-apple-darwin.txt | cut -d= -f2)
SHA_MACOS_ARM=$(cat artifacts/task-graph-mcp-aarch64-apple-darwin/mcpb-sha256-aarch64-apple-darwin.txt | cut -d= -f2)
SHA_WINDOWS=$(cat artifacts/task-graph-mcp-x86_64-pc-windows-msvc/mcpb-sha256-x86_64-pc-windows-msvc.txt | cut -d= -f2)
cat > server.json << EOF
{
"\$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.Oortonaut/task-graph-mcp",
"description": "MCP server for agent task workflows with phases, prompts, gates, and multi-agent coordination",
"version": "${VERSION}",
"repository": {
"url": "https://github.com/Oortonaut/task-graph-mcp",
"source": "github"
},
"packages": [
{
"registryType": "mcpb",
"identifier": "https://github.com/Oortonaut/task-graph-mcp/releases/download/v${VERSION}/task-graph-mcp-x86_64-unknown-linux-gnu.mcpb",
"version": "${VERSION}",
"fileSha256": "${SHA_LINUX}",
"transport": { "type": "stdio" }
},
{
"registryType": "mcpb",
"identifier": "https://github.com/Oortonaut/task-graph-mcp/releases/download/v${VERSION}/task-graph-mcp-x86_64-apple-darwin.mcpb",
"version": "${VERSION}",
"fileSha256": "${SHA_MACOS_X86}",
"transport": { "type": "stdio" }
},
{
"registryType": "mcpb",
"identifier": "https://github.com/Oortonaut/task-graph-mcp/releases/download/v${VERSION}/task-graph-mcp-aarch64-apple-darwin.mcpb",
"version": "${VERSION}",
"fileSha256": "${SHA_MACOS_ARM}",
"transport": { "type": "stdio" }
},
{
"registryType": "mcpb",
"identifier": "https://github.com/Oortonaut/task-graph-mcp/releases/download/v${VERSION}/task-graph-mcp-x86_64-pc-windows-msvc.mcpb",
"version": "${VERSION}",
"fileSha256": "${SHA_WINDOWS}",
"transport": { "type": "stdio" }
}
]
}
EOF
echo "Generated server.json:"
cat server.json
- name: Upload release artifacts
uses: softprops/action-gh-release@v2
with:
draft: false
files: |
artifacts/**/*.tar.gz
artifacts/**/*.zip
artifacts/**/*.mcpb
server.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install mcp-publisher
run: |
curl -fsSL https://registry.modelcontextprotocol.io/publisher/install.sh | sh || true
which mcp-publisher || echo "mcp-publisher not available, skipping registry publish"
- name: Publish to MCP Registry
if: success()
run: |
if command -v mcp-publisher &> /dev/null; then
mcp-publisher login github-oidc
mcp-publisher publish
else
echo "::warning::mcp-publisher not installed. Publish server.json manually after release."
fi