You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Every published Quarkus Agents MCP registration now pins the JDK: jbang --java 21+ io.quarkus:quarkus-agent-mcp:1.2.5:runner. The old command shipped no JDK hint, and §5 of the
setup skill justified that by saying the missing java-version: 21+ was "moot here, because
Phase A already requires JDK 25+". That reasoning was the bug: Phase A proves the machine has a
JDK 25, but JBang resolves its own JDK and falls back to its default — 17 on JBang 0.125.x —
whenever the spawning process exports no JAVA_HOME (GUI- and IDE-launched agents typically do
not) or points below 21. The server is compiled for Java 21, so it died at boot with UnsupportedClassVersionError: … class file version 65.0 … up to 61.0, the client retried and
gave up, and it read as "the MCP is broken". Verified by MCP initialize handshake against 1.2.5:
the old command fails with no JAVA_HOME and passes with JAVA_HOME=25 — so a
terminal-launched agent was passing by accident of its environment; --java 21+ passes in both.
The quarkus-agent-mcp@quarkusio alias is not an escape hatch: it does declare java-version: 21+, but JBang 0.125.x ignores that for a GAV script-ref and fails identically
(also verified). 21+ is a floor rather than a pin, so a machine already on 25 reuses it instead
of downloading JDK 21. Touches all five mcp add rows, the args line in §5, and the JSON snippet
in the setup skill, the Claude/Codex/Gemini/Bob commands and both snippets in README.md, and gemini-extension.json — 16 occurrences, now coupled by a gate (below) rather than by hand. The
Renovate pin still resolves — its matchStrings anchor on the GAV, which the flag precedes.
Bob's global MCP file was documented at a path Bob never reads. We published ~/.bob/mcp.json (with a hedge toward mcp_settings.json); Bob 2.0.0's own constants are MCP_WORKSPACE_FILENAME = "mcp.json" (→ <project>/.bob/mcp.json, correct), MCP_GLOBAL_FILENAME = "mcp.json" in the global settings directory (→ ~/.bob/settings/mcp.json), and MCP_LEGACY_GLOBAL_FILENAME = "mcp_settings.json", which Bob migrates only when mcp.json does
not yet exist. So on any machine that already has mcp.json, a registration written to the
legacy name is silently ignored — the setup reports success and Bob never loads the server. New
§5.1 in the setup skill documents the two real paths, the legacy trap, and the precedence rules,
and README.md's uninstall boundary now names the global file it keeps.
Bob registration switches from hand-written JSON to bob mcp add (Bob 2.0.0), verified against
the CLI.bob mcp add -s global <name> jbang -- --java 21+ <GAV> writes ~/.bob/settings/mcp.json, creating the file and directory when missing, and bob mcp list is a
real verification in the same style as the other agent rows. Two behaviors that cost a run if you
do not know them, both reproduced in a scratch workspace: the -- separator is mandatory
(without it Bob parses the server's flag as its own and exits error: unknown option '--java'),
and -s workspace does not create .bob/mcp.json — it exits Fatal error: ENOENT. Bob also
watches the file and restarts the servers whose entry changed (Restarting changed servers in ~/.bob/logs/shell/), so its "Live this session?" cell moves from "Reload in UI" to yes.
bob mcp add cannot repair a stale entry; add-json can. Verified: on a name that already
exists, add exits 1 with Error: MCP server "…" already exists in … and leaves the old entry
intact — so an idempotent re-run could not have replaced an unpinned registration through the route
this release recommends. §5.1 and the README now document bob mcp add-json -s <scope> quarkus-agent '{…}', which overwrites in place, with a
confirm-before-overwrite rule.
Registrations written by earlier releases of this skill sit one directory above where Bob looks.
Before v0.18.0 we pointed agents at ~/.bob/mcp.json / ~/.bob/mcp_settings.json; Bob reads
neither and migrates neither (its legacy migration only ever looks inside the settings directory),
so a machine set up by an earlier run can hold a registration that has never loaded. Both the skill
and the README now name those two orphan paths as things to check, not just the settings directory.
scripts/uninstall-bob-skill.sh's boundary comment and --help named the wrong files. They
listed a settings.json file where Bob 2.0.0 has a settings/ directory, and named only .bob/mcp.json as the MCP registration the uninstall must not touch — which under --global is
now ~/.bob/settings/mcp.json. Both scopes are spelled out, in the script and in the README's Bob
uninstall paragraph. Behavior unchanged: the script never touched those files.
New gate: ci/check-mcp-command-consistency.sh. The command is hand-maintained in 16 places;
the version gate couples the version and Renovate the GAV, but nothing coupled the command,
so --java 21+ could be present in one artifact and missing in another with every check green —
a class of drift this repo has already hit (9fdb9d2). The script normalizes each published
surface (markdown, CLI, JSON args, add-json payload) and fails unless every occurrence is
preceded by the pin and carries the same version. Wired into quality.yml; CHANGELOG.md and docs/ are exempt, since they quote older commands as a record. Proven to fail on a
single unpinned copy before being committed.
Verification now reads the stored command, not the server's name. Every Verify cell checked
only that something called quarkus-agent was listed — which an unpinned entry from an earlier
release or from the upstream Claude plugin satisfies, so no existing install was ever repaired and
all of them were reported verified. §5 requires comparing the printed command to the canonical
string and treating a mismatch as a repair (replace the entry: add-json for Bob, remove + re-add
elsewhere), and reporting both strings.
jbang itself may be unreachable, which no JDK flag can fix. A GUI- or IDE-launched client
starts from launchd/systemd with a minimal PATH (launchctl getenv PATH is empty on macOS → /usr/bin:/bin:/usr/sbin:/sbin), where none of SDKMAN, Homebrew, or the upstream installer put jbang; the symptom is spawn jbang ENOENT. "jbang must be on PATH — that is Phase A's job"
was the same category error this release fixes for JAVA_HOME: Phase A probes the login shell,
not the spawn environment. Both files now say to register the absolute path from command -v jbang when a client fails that way.
Phase A installs a 21+ JDK for JBang instead of letting the first handshake do it. With no
JBang-managed 21+ and no visible JAVA_HOME, --java 21+ makes JBang download a JDK inside MCP
startup: initialize times out and reads as "the MCP is broken" on first run. Phase A now checks jbang jdk list and offers jbang jdk install 21 in the foreground.
Bob's route no longer hard-depends on the bob binary, and its handoff is honest. §5.1 probes command -v bob and keeps a hand-write path (read-modify-write, both real paths, verified in the
UI's MCP tab) for IDE-only machines. And while Bob restarts changed servers by itself, it loads
skills and the conventions file once per conversation — §5.2 now closes a Bob run by telling the
user to start a new conversation before /scaffold-project.
The upstream Claude plugin carries the same JDK trap, and the README now says so — with the
right reason. quarkus-agent@quarkus-tools launches jbang quarkus-agent-mcp@quarkusio: the
alias does declare java-version: 21+ and JBang 0.125.x ignores it for a GAV script-ref, and RELEASE resolution means two machines run different code. The Claude manual fallback leads with
the pinned claude mcp add (both servers at -s user), and the plugin is presented as the
alternative with the name-collision warning the repo already gives for Gemini.
ci/test-uninstall-bob-skill.sh now covers the --global half of the MCP boundary. Case 6
redirects HOME but never fixtured ~/.bob/settings/mcp.json, so the file this release promises
to preserve under --global — where BASE="$HOME" — was asserted nowhere. Two asserts close it.