Skip to content

Commit 4b506b6

Browse files
abueideclaude
andauthored
Fix MCP Search Tool (#1)
* refactor(ci): support multiple scoped tags in release workflow Update release workflow and bump script to handle multiple plugin releases in a single commit. Changes: - release.yml: Parse multiple scoped tags (e.g., android/v0.0.3, devbox-mcp/v0.1.3) from commit message - release.yml: Create multiple git tags and use first tag for GitHub Release title - release.yml: Detect devbox-mcp version bumps from tag in commit message instead of git diff - bump.sh: Use scoped tags in commit messages instead of generic v* tags - bump.sh: Find last release tag by creation date across all scoped tags - devbox-mcp README: Add detailed GitHub token setup instructions for docs_search tool - devbox-mcp index.js: Improve docs_search description with authentication troubleshooting steps - devbox-mcp index.js: Remove unnecessary path filters from GitHub search query Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * chore(release): devbox-mcp/v0.1.3 ## What changed Patch release improving CI release workflow with support for multiple scoped tags. ### Plugins bumped | Plugin | Version | |--------|---------| | devbox-mcp | 0.1.2 -> 0.1.3 | ### Changes #### Other - Refactored CI release workflow to support multiple scoped tags - Moved tag creation from bump.sh script to release.yml workflow - Migrated to GitHub plugin references and simplified release workflow * update treefmt --------- Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 265a1f2 commit 4b506b6

6 files changed

Lines changed: 129 additions & 49 deletions

File tree

.github/workflows/release.yml

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ jobs:
1010
contents: write
1111
outputs:
1212
is_release: ${{ steps.check.outputs.is_release }}
13-
tag: ${{ steps.check.outputs.tag }}
13+
tags: ${{ steps.check.outputs.tags }}
14+
first_tag: ${{ steps.check.outputs.first_tag }}
15+
title: ${{ steps.check.outputs.title }}
1416
mcp_bumped: ${{ steps.check-mcp.outputs.mcp_bumped }}
1517
mcp_version: ${{ steps.check-mcp.outputs.mcp_version }}
1618
steps:
@@ -24,8 +26,14 @@ jobs:
2426
MSG=$(git log -1 --format=%s)
2527
if echo "$MSG" | grep -qE '^chore\(release\):'; then
2628
echo "is_release=true" >> "$GITHUB_OUTPUT"
27-
TAG=$(echo "$MSG" | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+')
28-
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
29+
TAGS=$(echo "$MSG" | grep -oE '[a-z][-a-z]*/v[0-9]+\.[0-9]+\.[0-9]+')
30+
echo "tags<<EOF" >> "$GITHUB_OUTPUT"
31+
echo "$TAGS" >> "$GITHUB_OUTPUT"
32+
echo "EOF" >> "$GITHUB_OUTPUT"
33+
FIRST_TAG=$(echo "$TAGS" | head -1)
34+
echo "first_tag=$FIRST_TAG" >> "$GITHUB_OUTPUT"
35+
TITLE=$(echo "$MSG" | sed 's/^chore(release): //')
36+
echo "title=$TITLE" >> "$GITHUB_OUTPUT"
2937
BODY=$(git log -1 --format=%b)
3038
echo "body<<EOF" >> "$GITHUB_OUTPUT"
3139
echo "$BODY" >> "$GITHUB_OUTPUT"
@@ -38,8 +46,10 @@ jobs:
3846
id: check-mcp
3947
if: steps.check.outputs.is_release == 'true'
4048
run: |
41-
if git diff --name-only HEAD~1 HEAD | grep -q '^plugins/devbox-mcp/package.json$'; then
42-
VERSION=$(jq -r '.version' plugins/devbox-mcp/package.json)
49+
MSG=$(git log -1 --format=%s)
50+
MCP_TAG=$(echo "$MSG" | grep -oE 'devbox-mcp/v[0-9]+\.[0-9]+\.[0-9]+' || true)
51+
if [ -n "$MCP_TAG" ]; then
52+
VERSION=$(echo "$MCP_TAG" | sed 's|devbox-mcp/v||')
4353
echo "mcp_bumped=true" >> "$GITHUB_OUTPUT"
4454
echo "mcp_version=$VERSION" >> "$GITHUB_OUTPUT"
4555
echo "devbox-mcp version bumped to $VERSION"
@@ -48,19 +58,23 @@ jobs:
4858
echo "devbox-mcp not changed in this release"
4959
fi
5060
51-
- name: Create git tag
52-
if: steps.check.outputs.is_release == 'true' && steps.check.outputs.tag != ''
61+
- name: Create git tags
62+
if: steps.check.outputs.is_release == 'true' && steps.check.outputs.tags != ''
5363
run: |
54-
git tag "${{ steps.check.outputs.tag }}"
55-
git push origin "${{ steps.check.outputs.tag }}"
64+
echo "${{ steps.check.outputs.tags }}" | while read -r TAG; do
65+
[ -z "$TAG" ] && continue
66+
echo "Creating tag: $TAG"
67+
git tag "$TAG"
68+
git push origin "$TAG"
69+
done
5670
5771
- name: Create GitHub Release
58-
if: steps.check.outputs.is_release == 'true' && steps.check.outputs.tag != ''
72+
if: steps.check.outputs.is_release == 'true' && steps.check.outputs.first_tag != ''
5973
env:
6074
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6175
run: |
62-
gh release create "${{ steps.check.outputs.tag }}" \
63-
--title "${{ steps.check.outputs.tag }}" \
76+
gh release create "${{ steps.check.outputs.first_tag }}" \
77+
--title "${{ steps.check.outputs.title }}" \
6478
--notes "${{ steps.check.outputs.body }}"
6579
6680
npm-publish:

plugins/devbox-mcp/README.md

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,19 @@ Model Context Protocol server for [Jetify's devbox](https://www.jetify.com/devbo
2424

2525
The `.devbox/virtenv/` directory is automatically regenerated on `devbox shell` or `devbox run`. Any manual changes will be lost.
2626

27+
## Environment Variables
28+
29+
The devbox-mcp server supports the following optional environment variables:
30+
31+
- **`GITHUB_TOKEN`** or **`GITHUB_PAT`**: Required for `devbox_docs_search` tool. GitHub Personal Access Token with `public_repo` read access. Without this, the docs search tool will fail with authentication errors.
32+
33+
See the Installation section below for how to configure environment variables.
34+
2735
## Installation
2836

2937
### For Claude Code
3038

39+
Basic installation (without GitHub token):
3140
```bash
3241
# Install via npx (recommended)
3342
claude mcp add devbox -- npx -y devbox-mcp-server
@@ -37,10 +46,18 @@ npm install -g devbox-mcp-server
3746
claude mcp add devbox -- devbox-mcp-server
3847
```
3948

40-
### For Claude Desktop
49+
With GitHub token for `devbox_docs_search` (recommended):
50+
```bash
51+
# User-wide configuration
52+
claude mcp add devbox-mcp -s user -e GITHUB_TOKEN="your_token_here" -- npx -y devbox-mcp-server
4153

42-
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
54+
# Or for local development
55+
claude mcp add devbox-mcp -s user -e GITHUB_TOKEN="your_token_here" -- node /path/to/devbox-mcp/src/index.js
56+
```
57+
58+
### For Claude Desktop
4359

60+
Without GitHub token:
4461
```json
4562
{
4663
"mcpServers": {
@@ -52,6 +69,21 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
5269
}
5370
```
5471

72+
With GitHub token (recommended):
73+
```json
74+
{
75+
"mcpServers": {
76+
"devbox": {
77+
"command": "npx",
78+
"args": ["-y", "devbox-mcp-server"],
79+
"env": {
80+
"GITHUB_TOKEN": "your_token_here"
81+
}
82+
}
83+
}
84+
}
85+
```
86+
5587
## Development
5688

5789
This plugin includes its own devbox environment for development:
@@ -125,16 +157,40 @@ Initialize a new devbox.json file in the specified directory.
125157
### `devbox_docs_search`
126158
Search the devbox documentation for relevant information.
127159

128-
**Requires GitHub Authentication:** This tool uses GitHub's code search API which requires a Personal Access Token (PAT). Set one of these environment variables:
129-
- `GITHUB_TOKEN=your_token_here`
130-
- `GITHUB_PAT=your_token_here`
131-
132-
To create a token:
133-
1. Visit https://github.com/settings/tokens
134-
2. Create a fine-grained token with `public_repo` read access
135-
3. Set it in your environment
136-
137-
If authentication isn't available, use `devbox_docs_list` to browse files, then `devbox_docs_read` to read specific docs.
160+
**Requires GitHub Authentication:** This tool uses GitHub's code search API which requires authentication.
161+
162+
**Setup Instructions:**
163+
164+
1. Create a GitHub Personal Access Token (PAT):
165+
- Visit https://github.com/settings/tokens
166+
- Click "Generate new token" (fine-grained or classic)
167+
- Grant `public_repo` or `repo` read access
168+
- Copy the token
169+
170+
2. Configure the MCP server with your token:
171+
172+
For Claude Code (user-wide):
173+
```bash
174+
claude mcp remove devbox-mcp -s user # Remove existing config
175+
claude mcp add devbox-mcp -s user -e GITHUB_TOKEN="your_token_here" -- node /path/to/devbox-mcp/src/index.js
176+
```
177+
178+
For Claude Desktop, add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
179+
```json
180+
{
181+
"mcpServers": {
182+
"devbox": {
183+
"command": "node",
184+
"args": ["/path/to/devbox-mcp/src/index.js"],
185+
"env": {
186+
"GITHUB_TOKEN": "your_token_here"
187+
}
188+
}
189+
}
190+
}
191+
```
192+
193+
**Alternative (no auth required):** Use `devbox_docs_list` to browse files, then `devbox_docs_read` to read specific docs.
138194

139195
```typescript
140196
devbox_docs_search({
@@ -166,7 +222,10 @@ devbox_docs_read({
166222

167223
- Node.js 18+ (for native fetch support)
168224
- devbox CLI installed and in PATH (for devbox commands)
169-
- GitHub Personal Access Token (optional, required for `devbox_docs_search`)
225+
- GitHub Personal Access Token (optional, but required for `devbox_docs_search` tool)
226+
- Create at: https://github.com/settings/tokens
227+
- Requires: `public_repo` or `repo` read access
228+
- Configure via `GITHUB_TOKEN` environment variable in MCP config
170229

171230
## License
172231

plugins/devbox-mcp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "devbox-mcp",
3-
"version": "0.1.2",
3+
"version": "0.1.3",
44
"description": "Model Context Protocol server for Jetify's devbox development environment tool",
55
"type": "module",
66
"main": "src/index.js",

plugins/devbox-mcp/src/index.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ async function searchDocs(query, options = {}) {
110110

111111
try {
112112
// Use GitHub's code search API
113-
const searchQuery = `${query} repo:jetify-com/docs path:*.md path:*.mdx`;
113+
// Search in the docs repo - most files are markdown anyway
114+
const searchQuery = `${query} repo:jetify-com/docs`;
114115
const url = new URL("https://api.github.com/search/code");
115116
url.searchParams.set("q", searchQuery);
116117
url.searchParams.set("per_page", String(maxResults));
@@ -320,11 +321,19 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
320321
{
321322
name: "devbox_docs_search",
322323
description:
323-
"Search devbox documentation for a keyword or phrase. " +
324-
"Returns matching lines from the official devbox docs repository.\n\n" +
325-
"Requires: GitHub Personal Access Token (PAT) set as GITHUB_TOKEN or GITHUB_PAT environment variable. " +
326-
"Create a token at https://github.com/settings/tokens with public_repo read access.\n\n" +
327-
"Alternative: Use devbox_docs_list to browse files, then devbox_docs_read to read specific docs.",
324+
"Search devbox documentation for a keyword or phrase. Returns matching lines from the official devbox docs repository.\n\n" +
325+
"IMPORTANT - Authentication Required:\n" +
326+
"This tool requires a GitHub Personal Access Token (PAT) configured in the MCP server environment. " +
327+
"If the user hasn't configured their GITHUB_TOKEN, this tool will fail with a 403 error. " +
328+
"When this happens, inform the user they need to reconfigure their MCP server:\n\n" +
329+
" claude mcp remove devbox-mcp -s user\n" +
330+
" claude mcp add devbox-mcp -s user -e GITHUB_TOKEN=\"your_token\" -- node /path/to/devbox-mcp/src/index.js\n\n" +
331+
"To create a GitHub PAT:\n" +
332+
"1. Visit https://github.com/settings/tokens\n" +
333+
"2. Create a fine-grained token or classic token\n" +
334+
"3. Grant 'public_repo' or 'repo' read access\n" +
335+
"4. Set it as GITHUB_TOKEN environment variable in MCP config\n\n" +
336+
"Alternative: Use devbox_docs_list (no auth required) to browse files, then devbox_docs_read to read specific docs.",
328337
inputSchema: {
329338
type: "object",
330339
properties: {

scripts/bump.sh

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ fi
6868
# Step 2: Find last release tag
6969
# ---------------------------------------------------------------------------
7070

71-
LAST_TAG=$(git tag -l 'v*' --sort=-v:refname | head -1 || true)
71+
LAST_TAG=$(git tag -l --sort=-creatordate | grep -E '(^v[0-9]|/v[0-9])' | head -1 || true)
7272
if [ -z "$LAST_TAG" ]; then
7373
LAST_TAG=$(git rev-list --max-parents=0 HEAD)
7474
echo "No release tags found, using initial commit: ${LAST_TAG:0:8}"
@@ -173,10 +173,6 @@ BUMPED_LIST=$(printf '%s\n' "${BUMPED_SUMMARY[@]}")
173173
LOG_OUTPUT=$(git log --oneline "$LAST_TAG"..HEAD -- "${CHANGED_DIRS[@]}")
174174
TEMPLATE=$(cat "$REPO_ROOT/scripts/bump-template.md")
175175

176-
# Determine the representative new version (use the first bumped plugin's new version)
177-
IFS=':' read -r _ first_file first_path <<< "${CHANGED_PLUGINS[0]}"
178-
NEW_VERSION=$(jq -r "$first_path" "$first_file")
179-
180176
echo "Generating release summary with Claude..."
181177

182178
RELEASE_SUMMARY=$(claude -p --model sonnet <<PROMPT
@@ -205,33 +201,33 @@ echo ""
205201
# Step 7: Stage, commit, and tag
206202
# ---------------------------------------------------------------------------
207203

208-
# Build plugin name list for commit message
209-
PLUGIN_NAMES=""
204+
# Build scoped tag list for commit message (e.g. android/v0.0.3, devbox-mcp/v0.1.3)
205+
SCOPED_TAGS=""
210206
for entry in "${CHANGED_PLUGINS[@]}"; do
211-
IFS=':' read -r plugin_dir _ _ <<< "$entry"
207+
IFS=':' read -r plugin_dir version_file jq_path <<< "$entry"
212208
name=$(basename "$plugin_dir")
213-
if [ -z "$PLUGIN_NAMES" ]; then
214-
PLUGIN_NAMES="$name"
209+
version=$(jq -r "$jq_path" "$version_file")
210+
tag="${name}/v${version}"
211+
if [ -z "$SCOPED_TAGS" ]; then
212+
SCOPED_TAGS="$tag"
215213
else
216-
PLUGIN_NAMES="$PLUGIN_NAMES, $name"
214+
SCOPED_TAGS="$SCOPED_TAGS, $tag"
217215
fi
218216
done
219217

220218
git add "${CHANGED_FILES[@]}"
221219

222220
git commit -m "$(cat <<EOF
223-
chore(release): bump ${PLUGIN_NAMES} to v${NEW_VERSION}
221+
chore(release): ${SCOPED_TAGS}
224222
225223
${RELEASE_SUMMARY}
226224
EOF
227225
)"
228226

229-
TAG="v${NEW_VERSION}"
230-
231-
echo "Committed: $TAG"
227+
echo "Committed: ${SCOPED_TAGS}"
232228
echo ""
233229
echo "To publish this release:"
234230
echo " 1. Push your branch and open a PR:"
235231
echo " git push -u origin HEAD"
236-
echo " gh pr create --title 'chore(release): bump ${PLUGIN_NAMES} to ${TAG}'"
237-
echo " 2. After CI passes and the PR is merged, release.yml will create the tag and GitHub Release."
232+
echo " gh pr create --title 'chore(release): ${SCOPED_TAGS}'"
233+
echo " 2. After CI passes and the PR is merged, release.yml will create the tags and GitHub Release."

treefmt.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
# exec treefmt --fail-on-change
1818

1919
[global]
20+
# Use git to walk files, which respects .gitignore
21+
walk = "git"
2022
excludes = [
2123
"*.md",
2224
"*.lock",

0 commit comments

Comments
 (0)