From e27519b77e6d058ef5e58cb4ef0921f3c818e682 Mon Sep 17 00:00:00 2001 From: Walker Hughes <74113220+walkerhughes@users.noreply.github.com> Date: Fri, 24 Jul 2026 23:40:46 -0700 Subject: [PATCH 1/2] fix: drop inherited VIRTUAL_ENV in the launcher uv already ignores a VIRTUAL_ENV that does not match the project, but it warns loudly on stderr. That warning reads like a cause of failure and already sent one debugging session chasing it instead of the real PATH problem. Verified: with a foreign VIRTUAL_ENV set, the warning count on stderr is now 0 and the server still lists all 15 tools. The minimal-PATH case that produced -32000 still starts. --- harbor-mcp/scripts/start-server.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/harbor-mcp/scripts/start-server.sh b/harbor-mcp/scripts/start-server.sh index 5ab1fc0..5d4d3c2 100755 --- a/harbor-mcp/scripts/start-server.sh +++ b/harbor-mcp/scripts/start-server.sh @@ -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 From c2c398e5cbc5a69132cce3bd27b340b90b39ee55 Mon Sep 17 00:00:00 2001 From: Walker Hughes <74113220+walkerhughes@users.noreply.github.com> Date: Fri, 24 Jul 2026 23:45:30 -0700 Subject: [PATCH 2/2] fix: bump plugin version to 0.2.0 so installed copies pick up the launcher The launcher fix in #3 never reached anyone. Claude Code extracts an installed plugin to a cache path keyed by the manifest version (~/.claude/plugins/cache///), and #3 left that at 0.1.0. The marketplace git clone advanced to 0637d00 and carries the launcher, but the extracted copy under cache/.../harbor-mcp/0.1.0 still has "command": "uv" and no scripts/ directory, so the -32000 persisted through marketplace updates and reinstalls alike. Confirmed on a live install: installed_plugins.json still records version 0.1.0 with gitCommitSha 2c1dfc2, the commit from #2. - Bumps the version to 0.2.0, which changes the cache key and forces a fresh extraction. - Recovers the VIRTUAL_ENV fix that was pushed to #3's branch after it merged and was therefore orphaned. - Adds a plugin-version workflow that fails a PR touching shipped plugin files without a version bump. Tests and evals are excluded, since they are not copied into the plugin cache and cannot strand a user. Verified both ways: it passes with the bump and blocks when the version is left unchanged. - Documents the requirement in the root README. --- .github/workflows/plugin-version.yml | 48 +++++++++++++++++++++++++++ README.md | 4 +++ harbor-mcp/.claude-plugin/plugin.json | 2 +- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/plugin-version.yml diff --git a/.github/workflows/plugin-version.yml b/.github/workflows/plugin-version.yml new file mode 100644 index 0000000..ede00a8 --- /dev/null +++ b/.github/workflows/plugin-version.yml @@ -0,0 +1,48 @@ +name: plugin version + +# Claude Code caches an installed plugin at a path keyed by its manifest version +# (~/.claude/plugins/cache///). 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." diff --git a/README.md b/README.md index 2c0b2c4..406ea09 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/harbor-mcp/.claude-plugin/plugin.json b/harbor-mcp/.claude-plugin/plugin.json index b0b0c0d..f947c17 100644 --- a/harbor-mcp/.claude-plugin/plugin.json +++ b/harbor-mcp/.claude-plugin/plugin.json @@ -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"