Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/plugin-version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: plugin version

# Claude Code caches an installed plugin at a path keyed by its manifest version
# (~/.claude/plugins/cache/<marketplace>/<plugin>/<version>). If a change ships
# without bumping that version, the cache key is unchanged, the extracted copy is
# never refreshed, and users keep running the old code no matter how many times
# they update or reinstall. The change is invisible rather than broken, which is
# the worst way to fail, so this gate makes it loud.
on:
pull_request:
paths:
- "harbor-mcp/**"
- ".github/workflows/plugin-version.yml"

jobs:
version-bumped:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Require a version bump when plugin files change
env:
BASE: ${{ github.event.pull_request.base.sha }}
MANIFEST: harbor-mcp/.claude-plugin/plugin.json
run: |
set -euo pipefail

# Only the shipped plugin payload matters. Tests and evals are not
# copied into the plugin cache, so changing them cannot strand a user.
if ! git diff --name-only "$BASE"...HEAD -- harbor-mcp \
':(exclude)harbor-mcp/tests/**' \
':(exclude)harbor-mcp/evals/**' | grep -q .; then
echo "No shipped plugin files changed; version bump not required."
exit 0
fi

read_version() { python3 -c "import json,sys;print(json.load(sys.stdin)['version'])"; }
base_version="$(git show "$BASE:$MANIFEST" | read_version)"
head_version="$(read_version < "$MANIFEST")"

echo "base=$base_version head=$head_version"
if [ "$base_version" = "$head_version" ]; then
echo "::error file=$MANIFEST::Shipped plugin files changed but version is still $head_version. Bump it, or installed copies will never pick this up."
exit 1
fi
echo "Version bumped $base_version -> $head_version."
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ This repo is also a plugin marketplace. Run these as two separate commands, not

Plugins require [`uv`](https://docs.astral.sh/uv/) on your PATH. The first launch builds the server's environment, so give it a moment before the tools appear. See each server's README for credentials.

### Shipping a plugin change

**Bump `version` in the plugin's `.claude-plugin/plugin.json` in the same PR.** Claude Code extracts an installed plugin to a cache path keyed by that version, so if it does not change, the cache is never refreshed and users keep running the old code however many times they update or reinstall. The change is invisible rather than broken. The `plugin version` workflow enforces this.

## Design

These servers follow Honeycomb's [MCP, easy as 1-2-3](https://www.honeycomb.io/blog/mcp-easy-as-1-2-3) guidance: a few curated tools built around real questions rather than raw API endpoints, responses shaped for a model instead of a UI, and typed schemas that steer the model toward valid calls.
Expand Down
2 changes: 1 addition & 1 deletion harbor-mcp/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "harbor-mcp",
"version": "0.1.0",
"version": "0.2.0",
"description": "MCP server for the Harbor hub: inspect evaluation jobs, trials, and uploads; publish tasks and datasets when writes are enabled.",
"author": {
"name": "Walker Hughes"
Expand Down
6 changes: 6 additions & 0 deletions harbor-mcp/scripts/start-server.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ if ! UV="$(find_uv)"; then
exit 127
fi

# Drop any inherited VIRTUAL_ENV. uv already ignores a mismatched one, but it
# warns loudly on stderr about "does not match the project environment path",
# which reads like the cause of a failure and has already sent one debugging
# session down the wrong path.
unset VIRTUAL_ENV

# First launch builds the environment from the checked-in uv.lock, which takes a
# few seconds; later launches reuse it.
exec "$UV" run --project "$ROOT" harbor-mcp
Loading