Skip to content

chore(deps): update ghcr.io/buildkite/buildkite-mcp-server docker tag to v0.11.1 #836

chore(deps): update ghcr.io/buildkite/buildkite-mcp-server docker tag to v0.11.1

chore(deps): update ghcr.io/buildkite/buildkite-mcp-server docker tag to v0.11.1 #836

Workflow file for this run

name: Update Server Tool Lists
on:
pull_request:
paths:
- 'registries/**/server.json'
workflow_dispatch:
inputs:
server:
description: 'Specific server to update (directory name, leave empty for all changed)'
required: false
type: string
permissions:
contents: write
pull-requests: write
jobs:
# Security check for fork PRs - prevents untrusted code execution with write permissions
security-check:
name: Security Check for Fork PRs
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
outputs:
is-fork: ${{ steps.check-fork.outputs.is-fork }}
has-label: ${{ steps.check-label.outputs.has-label }}
should-run: ${{ steps.check-fork.outputs.should-run }}
steps:
- name: Check if PR is from a fork
id: check-fork
run: |
# Get PR details from GitHub API
PR_DATA=$(gh pr view "$PR_NUMBER" --json isCrossRepository,labels --repo "$GH_REPOSITORY")
IS_FORK=$(echo "$PR_DATA" | jq -r '.isCrossRepository')
echo "is-fork=$IS_FORK" >> $GITHUB_OUTPUT
if [ "$IS_FORK" = "false" ]; then
echo "PR is from the same repository - workflow will run automatically"
echo "should-run=true" >> $GITHUB_OUTPUT
else
echo "PR is from a fork - checking for 'safe-to-update' label"
# Check if PR has the safe-to-update label
HAS_LABEL=$(echo "$PR_DATA" | jq -r '.labels | map(select(.name == "safe-to-update")) | length > 0')
if [ "$HAS_LABEL" = "true" ]; then
echo "PR has 'safe-to-update' label - workflow will run"
echo "should-run=true" >> $GITHUB_OUTPUT
else
echo "PR does not have 'safe-to-update' label - workflow will be skipped"
echo "should-run=false" >> $GITHUB_OUTPUT
fi
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
GH_REPOSITORY: ${{ github.repository }}
- name: Check label status
id: check-label
if: steps.check-fork.outputs.is-fork == 'true'
run: |
PR_DATA=$(gh pr view "$PR_NUMBER" --json labels --repo "$GH_REPOSITORY")
HAS_LABEL=$(echo "$PR_DATA" | jq -r '.labels | map(select(.name == "safe-to-update")) | length > 0')
echo "has-label=$HAS_LABEL" >> $GITHUB_OUTPUT
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
GH_REPOSITORY: ${{ github.repository }}
- name: Post instructions for fork PRs without label
if: steps.check-fork.outputs.is-fork == 'true' && steps.check-fork.outputs.should-run == 'false'
run: |
gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \
--method POST \
--field body="$(cat <<'BODY'
## Security Notice: Fork PR Tool Update Workflow
This PR is from a forked repository. For security reasons, the automatic tool list update workflow requires a maintainer to add the `safe-to-update` label before it will run.
A maintainer will review this PR and add the label if appropriate. The workflow will then automatically update the tool lists.
---
**Why is this needed?** This workflow executes code and connects to MCP servers specified in server.json files. To prevent potential security issues, we require manual verification for fork PRs.
BODY
)"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
detect-changes:
name: Detect Changed Servers
runs-on: ubuntu-latest
needs: [security-check]
if: |
always() &&
(github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' && needs.security-check.outputs.should-run == 'true'))
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
has-changes: ${{ steps.set-matrix.outputs.has-changes }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Get changed files
id: changed-files
run: |
if [ "$EVENT_NAME" = "pull_request" ]; then
# For PRs, get changed files between base and head
# Get changed server.json files
CHANGED_FILES=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -E '^registries/.*/servers/.*/server\.json$' || true)
else
# For workflow_dispatch, get files changed in the last commit
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD | grep -E '^registries/.*/servers/.*/server\.json$' || true)
fi
# Convert to JSON array
if [ -z "$CHANGED_FILES" ]; then
echo "all_changed_files=[]" >> $GITHUB_OUTPUT
else
JSON_ARRAY=$(echo "$CHANGED_FILES" | jq -R -s -c 'split("\n") | map(select(length > 0))')
echo "all_changed_files=$JSON_ARRAY" >> $GITHUB_OUTPUT
fi
env:
EVENT_NAME: ${{ github.event_name }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
- name: Validate server input
if: github.event_name == 'workflow_dispatch' && inputs.server != ''
run: |
if [[ ! "$INPUT_SERVER" =~ ^[a-zA-Z0-9._-]+$ ]]; then
echo "::error::Invalid server name: must contain only alphanumeric characters, dots, hyphens, and underscores"
exit 1
fi
env:
INPUT_SERVER: ${{ inputs.server }}
- name: Set matrix for changed servers
id: set-matrix
run: |
if [ "$EVENT_NAME" = "workflow_dispatch" ] && [ -n "$INPUT_SERVER" ]; then
# Manual run with specific server
SERVER_FILE="registries/toolhive/servers/${INPUT_SERVER}/server.json"
if [ -f "$SERVER_FILE" ]; then
echo "matrix={\"server\":[\"$SERVER_FILE\"]}" >> $GITHUB_OUTPUT
echo "has-changes=true" >> $GITHUB_OUTPUT
else
echo "Error: Server $INPUT_SERVER not found at $SERVER_FILE"
echo "has-changes=false" >> $GITHUB_OUTPUT
exit 1
fi
elif [ "$EVENT_NAME" = "workflow_dispatch" ]; then
# Manual run without specific server - process all server.json files
echo "Manual run without specific server - processing all server.json files"
ALL_SERVERS=$(find registries -path '*/servers/*/server.json' | sort)
if [ -z "$ALL_SERVERS" ]; then
echo "No server.json files found"
echo "has-changes=false" >> $GITHUB_OUTPUT
else
JSON_ARRAY=$(echo "$ALL_SERVERS" | jq -R -s -c 'split("\n") | map(select(length > 0))')
MATRIX=$(echo "$JSON_ARRAY" | jq -c '{server: .}')
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
echo "has-changes=true" >> $GITHUB_OUTPUT
echo "Files to process:"
echo "$JSON_ARRAY" | jq -r '.[]'
fi
else
# PR - use changed files
CHANGED_FILES="$ALL_CHANGED_FILES"
if [ "$CHANGED_FILES" = "[]" ]; then
echo "No server.json files changed"
echo "has-changes=false" >> $GITHUB_OUTPUT
else
MATRIX=$(echo "$CHANGED_FILES" | jq -c '{server: .}')
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
echo "has-changes=true" >> $GITHUB_OUTPUT
echo "Files to process:"
echo "$CHANGED_FILES" | jq -r '.[]'
fi
fi
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_SERVER: ${{ inputs.server }}
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
update-tools:
name: Update Tools for ${{ matrix.server }}
needs: detect-changes
if: needs.detect-changes.outputs.has-changes == 'true'
runs-on: ubuntu-latest
strategy:
matrix: ${{ fromJson(needs.detect-changes.outputs.matrix) }}
fail-fast: false
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref || github.ref }}
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
with:
go-version-file: 'go.mod'
cache: true
- name: Install ToolHive
uses: StacklokLabs/toolhive-actions/install@87b30f145f84b3186fd20e74c133111a5da24710 # v0
with:
version: 'v0.2.9'
- name: Build catalog
run: |
echo "Building catalog..."
go build -o /tmp/catalog ./cmd/catalog
- name: Extract server name
id: server-info
run: |
SERVER_DIR=$(dirname "$SERVER_FILE")
SERVER_NAME=$(basename "$SERVER_DIR")
# Derive a unique key including the registry name to avoid artifact
# collisions when the same server exists in multiple registries
# (e.g. registries/official/servers/heroku and registries/toolhive/servers/heroku).
REGISTRY_NAME=$(echo "$SERVER_FILE" | cut -d/ -f2)
SERVER_KEY="${REGISTRY_NAME}-${SERVER_NAME}"
echo "server-name=$SERVER_NAME" >> $GITHUB_OUTPUT
echo "server-key=$SERVER_KEY" >> $GITHUB_OUTPUT
echo "Processing server: $SERVER_NAME (key: $SERVER_KEY)"
env:
SERVER_FILE: ${{ matrix.server }}
- name: Update tool list
id: update
run: |
echo "Updating tools for $SERVER_NAME..."
# Run the update tool
if /tmp/catalog update-tools "$SERVER_FILE" -v; then
echo "update-status=success" >> $GITHUB_OUTPUT
# Check if file was modified
if git diff --quiet "$SERVER_FILE"; then
echo "No changes needed for $SERVER_FILE"
echo "changed=false" >> $GITHUB_OUTPUT
else
echo "Tools updated for $SERVER_FILE"
echo "changed=true" >> $GITHUB_OUTPUT
# Get the diff for the comment
DIFF=$(git diff "$SERVER_FILE" | head -100)
echo "diff<<EOF" >> $GITHUB_OUTPUT
echo "$DIFF" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
fi
else
echo "update-status=failed" >> $GITHUB_OUTPUT
echo "changed=false" >> $GITHUB_OUTPUT
# Check if warning was added
if git diff "$SERVER_FILE" | grep -q "WARNING"; then
echo "Warning comment added to server file"
echo "warning-added=true" >> $GITHUB_OUTPUT
else
echo "warning-added=false" >> $GITHUB_OUTPUT
fi
fi
env:
SERVER_FILE: ${{ matrix.server }}
SERVER_NAME: ${{ steps.server-info.outputs.server-name }}
- name: Prepare changes for commit
if: (steps.update.outputs.changed == 'true' || steps.update.outputs.warning-added == 'true') && github.event_name == 'pull_request'
run: |
mkdir -p /tmp/commit-info
if [ "$UPDATE_CHANGED" = "true" ]; then
echo "update" > "/tmp/commit-info/${SERVER_KEY}.type"
echo "$SERVER_NAME" > "/tmp/commit-info/${SERVER_KEY}.name"
echo "$SERVER_FILE" > "/tmp/commit-info/${SERVER_KEY}.server"
else
echo "warning" > "/tmp/commit-info/${SERVER_KEY}.type"
echo "$SERVER_NAME" > "/tmp/commit-info/${SERVER_KEY}.name"
echo "$SERVER_FILE" > "/tmp/commit-info/${SERVER_KEY}.server"
fi
# Copy the modified server.json to the artifact directory
cp "$SERVER_FILE" "/tmp/commit-info/${SERVER_KEY}.server.json"
env:
SERVER_FILE: ${{ matrix.server }}
SERVER_NAME: ${{ steps.server-info.outputs.server-name }}
SERVER_KEY: ${{ steps.server-info.outputs.server-key }}
UPDATE_CHANGED: ${{ steps.update.outputs.changed }}
- name: Upload commit info
if: (steps.update.outputs.changed == 'true' || steps.update.outputs.warning-added == 'true') && github.event_name == 'pull_request'
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: commit-info-${{ steps.server-info.outputs.server-key }}
path: /tmp/commit-info/
- name: Output diff for workflow dispatch
if: github.event_name == 'workflow_dispatch' && (steps.update.outputs.changed == 'true' || steps.update.outputs.warning-added == 'true')
run: |
echo "## Tool List Update for $SERVER_NAME" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "$UPDATE_CHANGED" = "true" ]; then
echo "**Status**: Successfully updated tool list" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Changes Made:" >> $GITHUB_STEP_SUMMARY
echo '```diff' >> $GITHUB_STEP_SUMMARY
git diff "$SERVER_FILE" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Note**: Changes were not committed because this is a workflow dispatch run. To apply these changes:" >> $GITHUB_STEP_SUMMARY
echo "1. Create a new branch" >> $GITHUB_STEP_SUMMARY
echo "2. Apply the changes shown above" >> $GITHUB_STEP_SUMMARY
echo "3. Open a pull request" >> $GITHUB_STEP_SUMMARY
else
echo "**Status**: Tool list update failed, warning added" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Warning Added:" >> $GITHUB_STEP_SUMMARY
echo '```diff' >> $GITHUB_STEP_SUMMARY
git diff "$SERVER_FILE" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Server**: $SERVER_NAME" >> $GITHUB_STEP_SUMMARY
echo "**Server File**: \`$SERVER_FILE\`" >> $GITHUB_STEP_SUMMARY
echo "**Triggered by**: @$GH_ACTOR" >> $GITHUB_STEP_SUMMARY
env:
SERVER_FILE: ${{ matrix.server }}
SERVER_NAME: ${{ steps.server-info.outputs.server-name }}
UPDATE_CHANGED: ${{ steps.update.outputs.changed }}
GH_ACTOR: ${{ github.actor }}
commit-all-changes:
name: Commit All Tool Updates
needs: [detect-changes, update-tools]
if: always() && needs.detect-changes.outputs.has-changes == 'true' && github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.head_ref || github.ref }}
- name: Download all commit info artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
path: /tmp/artifacts/
pattern: commit-info-*
merge-multiple: true
- name: Check if any changes were made
id: check_changes
run: |
if [ -d "/tmp/artifacts" ] && [ "$(ls -A /tmp/artifacts 2>/dev/null)" ]; then
echo "changes=true" >> $GITHUB_OUTPUT
echo "Found commit info files:"
ls -la /tmp/artifacts/
else
echo "changes=false" >> $GITHUB_OUTPUT
echo "No changes to commit"
fi
- name: Commit and push all changes
if: steps.check_changes.outputs.changes == 'true'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
# Pull any remote changes first to avoid conflicts
git pull origin "$BRANCH_REF" --rebase
# Collect all the server names that were updated
UPDATED_SERVERS=""
WARNING_SERVERS=""
for file in /tmp/artifacts/*.type; do
if [ -f "$file" ]; then
SERVER_KEY=$(basename "$file" .type)
SERVER_NAME=$(cat "/tmp/artifacts/${SERVER_KEY}.name")
TYPE=$(cat "$file")
if [ "$TYPE" = "update" ]; then
UPDATED_SERVERS="$UPDATED_SERVERS $SERVER_NAME"
else
WARNING_SERVERS="$WARNING_SERVERS $SERVER_NAME"
fi
# Restore the modified server.json from the artifact
SERVER_FILE=$(cat "/tmp/artifacts/${SERVER_KEY}.server")
if [ -f "/tmp/artifacts/${SERVER_KEY}.server.json" ]; then
cp "/tmp/artifacts/${SERVER_KEY}.server.json" "$SERVER_FILE"
git add "$SERVER_FILE"
else
echo "Warning: Modified server.json not found in artifacts for $SERVER_KEY"
fi
fi
done
# Create commit message
COMMIT_MSG="chore: update tool lists for MCP servers (server.json)"
if [ -n "$UPDATED_SERVERS" ]; then
COMMIT_MSG="$COMMIT_MSG\n\nUpdated servers:$(echo $UPDATED_SERVERS | sed 's/ /\\n- /g' | sed 's/^/\\n- /')"
fi
if [ -n "$WARNING_SERVERS" ]; then
COMMIT_MSG="$COMMIT_MSG\n\nWarning added for servers:$(echo $WARNING_SERVERS | sed 's/ /\\n- /g' | sed 's/^/\\n- /')"
fi
COMMIT_MSG="$COMMIT_MSG\n\nAutomatically updated using 'catalog update-tools' command.\n\nCo-authored-by: $GH_ACTOR <${GH_ACTOR}@users.noreply.github.com>"
# Check if there are actually any changes to commit
if ! git diff --cached --quiet; then
git commit -m "$COMMIT_MSG"
git push
echo "Successfully committed and pushed all tool updates"
else
echo "No changes to commit (files may have been identical)"
fi
env:
BRANCH_REF: ${{ github.head_ref || github.ref_name }}
GH_ACTOR: ${{ github.actor }}
comment-summary:
name: Post Summary Comment
needs: [detect-changes, update-tools]
if: always() && needs.detect-changes.outputs.has-changes == 'true'
runs-on: ubuntu-latest
steps:
- name: Download all commit info artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
path: /tmp/comment-artifacts/
pattern: commit-info-*
merge-multiple: true
- name: Post or update summary comment
if: github.event_name == 'pull_request'
run: |
# Build summary table from artifacts
SUMMARY=""
if [ -d "/tmp/comment-artifacts" ] && [ "$(ls -A /tmp/comment-artifacts 2>/dev/null)" ]; then
for file in /tmp/comment-artifacts/*.type; do
if [ -f "$file" ]; then
SERVER_KEY=$(basename "$file" .type)
SERVER_NAME=$(cat "/tmp/comment-artifacts/${SERVER_KEY}.name")
TYPE=$(cat "$file")
if [ "$TYPE" = "update" ]; then
SUMMARY="${SUMMARY}| ${SERVER_NAME} | Updated | Tool list refreshed |
"
else
SUMMARY="${SUMMARY}| ${SERVER_NAME} | Warning | Could not fetch tools, added warning comment |
"
fi
fi
done
fi
if [ -z "$SUMMARY" ]; then
SUMMARY="| _No changes detected_ | | |"
fi
COMMENT_BODY="## MCP Server Tool List Updates (server.json)
The tool lists for modified MCP server entries have been automatically updated using \`catalog update-tools\`.
### Summary
| Server | Status | Details |
|--------|--------|---------|
${SUMMARY}
---
_This comment is automatically generated and will be updated as the workflow progresses._"
# Find existing comment
COMMENT_ID=$(gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \
--jq '[.[] | select(.user.login == "github-actions[bot]") | select(.body | contains("## MCP Server Tool List Updates (server.json)"))][0].id' \
2>/dev/null || true)
if [ -n "$COMMENT_ID" ] && [ "$COMMENT_ID" != "null" ]; then
gh api "repos/${GITHUB_REPOSITORY}/issues/comments/${COMMENT_ID}" \
--method PATCH \
--field body="$COMMENT_BODY"
else
gh api "repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" \
--method POST \
--field body="$COMMENT_BODY"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
validate-after-update:
name: Validate Updated Servers
needs: update-tools
if: always()
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
ref: ${{ github.head_ref || github.ref }}
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6
with:
go-version-file: 'go.mod'
cache: true
- name: Build catalog
run: go build -o /tmp/catalog ./cmd/catalog
- name: Validate all server.json entries
run: |
echo "Validating all catalog entries after updates..."
/tmp/catalog validate -v