Skip to content

Commit 162bcd0

Browse files
committed
feat: add automatic MCP server tool list updates
- Add update-tools command to fetch and update tool lists from MCP servers - Create GitHub Actions workflow to automatically update tools on PR changes - Implement toolhive package with modular components: - Client for running MCP servers and querying tools - Parser for JSON/text output formats - Builder for constructing thv commands - Spec operations for updating YAML files - Support for handling errors with warning comments - Preserve existing tools when fetch fails - Automatically commit updates back to PRs This enables automatic maintenance of accurate tool lists whenever MCP server images are updated in the registry.
1 parent f2cb2d3 commit 162bcd0

File tree

6 files changed

+930
-0
lines changed

6 files changed

+930
-0
lines changed

.github/workflows/update-tools.yml

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
name: Update MCP Server Tool Lists
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'registry/**/spec.yaml'
7+
- 'registry/**/spec.yml'
8+
workflow_dispatch:
9+
inputs:
10+
server:
11+
description: 'Specific server to update (leave empty for all changed)'
12+
required: false
13+
type: string
14+
15+
permissions:
16+
contents: write
17+
pull-requests: write
18+
19+
jobs:
20+
detect-changes:
21+
name: Detect Changed Specs
22+
runs-on: ubuntu-latest
23+
outputs:
24+
matrix: ${{ steps.set-matrix.outputs.matrix }}
25+
has-changes: ${{ steps.set-matrix.outputs.has-changes }}
26+
steps:
27+
- name: Checkout code
28+
uses: actions/checkout@v5
29+
with:
30+
fetch-depth: 0
31+
32+
- name: Get changed files
33+
id: changed-files
34+
uses: tj-actions/changed-files@v45
35+
with:
36+
files: |
37+
registry/**/spec.yaml
38+
registry/**/spec.yml
39+
json: true
40+
json_raw_format: true
41+
42+
- name: Set matrix for changed specs
43+
id: set-matrix
44+
run: |
45+
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ inputs.server }}" ]; then
46+
# Manual run with specific server
47+
SPEC_FILE="registry/${{ inputs.server }}/spec.yaml"
48+
if [ ! -f "$SPEC_FILE" ]; then
49+
SPEC_FILE="registry/${{ inputs.server }}/spec.yml"
50+
fi
51+
if [ -f "$SPEC_FILE" ]; then
52+
echo "matrix={\"spec\":[\"$SPEC_FILE\"]}" >> $GITHUB_OUTPUT
53+
echo "has-changes=true" >> $GITHUB_OUTPUT
54+
else
55+
echo "Error: Server ${{ inputs.server }} not found"
56+
echo "has-changes=false" >> $GITHUB_OUTPUT
57+
exit 1
58+
fi
59+
else
60+
# PR or manual run without specific server
61+
CHANGED_FILES='${{ steps.changed-files.outputs.all_changed_files }}'
62+
63+
if [ "$CHANGED_FILES" = "[]" ]; then
64+
echo "No spec files changed"
65+
echo "has-changes=false" >> $GITHUB_OUTPUT
66+
else
67+
# Convert the JSON array to matrix format
68+
MATRIX=$(echo "$CHANGED_FILES" | jq -c '{spec: .}')
69+
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
70+
echo "has-changes=true" >> $GITHUB_OUTPUT
71+
72+
# Log the files that will be processed
73+
echo "Files to process:"
74+
echo "$CHANGED_FILES" | jq -r '.[]'
75+
fi
76+
fi
77+
78+
update-tools:
79+
name: Update Tools for ${{ matrix.spec }}
80+
needs: detect-changes
81+
if: needs.detect-changes.outputs.has-changes == 'true'
82+
runs-on: ubuntu-latest
83+
strategy:
84+
matrix: ${{ fromJson(needs.detect-changes.outputs.matrix) }}
85+
fail-fast: false
86+
steps:
87+
- name: Checkout code
88+
uses: actions/checkout@v5
89+
with:
90+
token: ${{ secrets.GITHUB_TOKEN }}
91+
92+
- name: Set up Go
93+
uses: actions/setup-go@v5
94+
with:
95+
go-version-file: 'go.mod'
96+
cache: true
97+
98+
- name: Install ToolHive
99+
uses: StacklokLabs/toolhive-actions@v1
100+
with:
101+
version: 'v0.2.9'
102+
103+
- name: Build update-tools
104+
run: |
105+
echo "Building update-tools..."
106+
go build -o update-tools ./cmd/update-tools
107+
108+
- name: Extract server name
109+
id: server-info
110+
run: |
111+
SERVER_DIR=$(dirname "${{ matrix.spec }}")
112+
SERVER_NAME=$(basename "$SERVER_DIR")
113+
echo "server-name=$SERVER_NAME" >> $GITHUB_OUTPUT
114+
echo "Processing server: $SERVER_NAME"
115+
116+
- name: Update tool list
117+
id: update
118+
run: |
119+
echo "Updating tools for ${{ steps.server-info.outputs.server-name }}..."
120+
121+
# Run the update tool
122+
if ./update-tools "${{ matrix.spec }}" -v; then
123+
echo "update-status=success" >> $GITHUB_OUTPUT
124+
125+
# Check if file was modified
126+
if git diff --quiet "${{ matrix.spec }}"; then
127+
echo "No changes needed for ${{ matrix.spec }}"
128+
echo "changed=false" >> $GITHUB_OUTPUT
129+
else
130+
echo "Tools updated for ${{ matrix.spec }}"
131+
echo "changed=true" >> $GITHUB_OUTPUT
132+
133+
# Get the diff for the comment
134+
DIFF=$(git diff "${{ matrix.spec }}" | head -100)
135+
echo "diff<<EOF" >> $GITHUB_OUTPUT
136+
echo "$DIFF" >> $GITHUB_OUTPUT
137+
echo "EOF" >> $GITHUB_OUTPUT
138+
fi
139+
else
140+
echo "update-status=failed" >> $GITHUB_OUTPUT
141+
echo "changed=false" >> $GITHUB_OUTPUT
142+
143+
# Check if warning was added
144+
if git diff "${{ matrix.spec }}" | grep -q "WARNING"; then
145+
echo "Warning comment added to spec file"
146+
echo "warning-added=true" >> $GITHUB_OUTPUT
147+
else
148+
echo "warning-added=false" >> $GITHUB_OUTPUT
149+
fi
150+
fi
151+
152+
- name: Commit changes
153+
if: steps.update.outputs.changed == 'true' || steps.update.outputs.warning-added == 'true'
154+
run: |
155+
git config --local user.email "[email protected]"
156+
git config --local user.name "GitHub Action"
157+
158+
SERVER_NAME="${{ steps.server-info.outputs.server-name }}"
159+
160+
if [ "${{ steps.update.outputs.changed }}" = "true" ]; then
161+
git add "${{ matrix.spec }}"
162+
git commit -m "chore: update tool list for $SERVER_NAME
163+
164+
Automatically updated tool list using 'thv mcp list --server $SERVER_NAME'
165+
166+
Co-authored-by: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>"
167+
else
168+
git add "${{ matrix.spec }}"
169+
git commit -m "chore: add warning for $SERVER_NAME tool list update failure
170+
171+
Could not fetch tools from MCP server, added warning comment.
172+
173+
Co-authored-by: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>"
174+
fi
175+
176+
- name: Push changes
177+
if: steps.update.outputs.changed == 'true' || steps.update.outputs.warning-added == 'true'
178+
run: |
179+
git push
180+
181+
comment-summary:
182+
name: Post Summary Comment
183+
needs: [detect-changes, update-tools]
184+
if: always() && needs.detect-changes.outputs.has-changes == 'true'
185+
runs-on: ubuntu-latest
186+
steps:
187+
- name: Find existing comment
188+
if: github.event_name == 'pull_request'
189+
uses: peter-evans/find-comment@v3
190+
id: find-comment
191+
with:
192+
issue-number: ${{ github.event.pull_request.number }}
193+
comment-author: 'github-actions[bot]'
194+
body-includes: '## 🔧 MCP Server Tool List Updates'
195+
196+
- name: Create or update comment
197+
if: github.event_name == 'pull_request'
198+
uses: peter-evans/create-or-update-comment@v4
199+
with:
200+
comment-id: ${{ steps.find-comment.outputs.comment-id }}
201+
issue-number: ${{ github.event.pull_request.number }}
202+
body: |
203+
## 🔧 MCP Server Tool List Updates
204+
205+
The tool lists for modified MCP server specs have been automatically updated using `thv mcp list`.
206+
207+
### Summary
208+
209+
| Server | Status | Details |
210+
|--------|--------|---------|
211+
${{ needs.update-tools.outputs.summary || '| _Processing results..._ | | |' }}
212+
213+
---
214+
_This comment is automatically generated and will be updated as the workflow progresses._
215+
edit-mode: replace
216+
217+
validate-after-update:
218+
name: Validate Updated Specs
219+
needs: update-tools
220+
if: always()
221+
runs-on: ubuntu-latest
222+
steps:
223+
- name: Checkout code
224+
uses: actions/checkout@v5
225+
with:
226+
ref: ${{ github.head_ref || github.ref }}
227+
228+
- name: Set up Go
229+
uses: actions/setup-go@v5
230+
with:
231+
go-version-file: 'go.mod'
232+
cache: true
233+
234+
- name: Build registry-builder
235+
run: go build -o registry-builder ./cmd/registry-builder
236+
237+
- name: Validate all specs
238+
run: |
239+
echo "Validating all registry entries after updates..."
240+
./registry-builder validate -v

0 commit comments

Comments
 (0)