From 2b9c20d22bf229b5ea688f833c50b0345766b17d Mon Sep 17 00:00:00 2001 From: KHA Entertaiment Date: Thu, 16 Apr 2026 19:15:53 -0700 Subject: [PATCH] fix: make Claude plugin MCP startup portable --- .claude-plugin/marketplace.json | 2 +- CHANGELOG.md | 9 ++ CLAWHUB.md | 2 +- VERSION | 2 +- package-lock.json | 4 +- package.json | 2 +- platforms/claude/.claude-plugin/plugin.json | 2 +- platforms/claude/.claude-plugin/setup.sh | 86 +++---------------- platforms/claude/.mcp.json | 12 +-- platforms/claude/commands/setup.sh | 3 +- platforms/claude/scripts/bootstrap-runtime.sh | 81 +++++++++++++++++ platforms/claude/scripts/mcp-server.sh | 9 ++ platforms/claude/skills/grok-swarm/SKILL.md | 2 +- platforms/claude/src/mcp/grok_server.py | 2 +- pyproject.toml | 2 +- scripts/test.js | 14 +++ scripts/verify-release.js | 26 ++++++ src/mcp/grok_server.py | 2 +- 18 files changed, 173 insertions(+), 89 deletions(-) create mode 100755 platforms/claude/scripts/bootstrap-runtime.sh create mode 100755 platforms/claude/scripts/mcp-server.sh diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 74c4ba7..ef2762b 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -17,7 +17,7 @@ "ref": "master" }, "description": "Multi-agent intelligence powered by Grok 4.20 via OpenRouter. 4-agent swarm with ~2M token context for code analysis, refactoring, and reasoning.", - "version": "1.3.5", + "version": "1.3.6", "author": { "name": "Billy Brenner & Claude" }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 1213d50..e583a1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to the Grok Swarm tool. +## [1.3.6] - 2026-04-16 + +### Fixed + +- Replaced the non-portable Claude plugin MCP config with a `${CLAUDE_PLUGIN_ROOT}` wrapper entrypoint +- Added first-start MCP runtime bootstrapping so plugin MCP can create/use the plugin-local `.venv` +- Stopped setup from creating duplicate manual `grok-swarm` MCP entries when Claude manages the plugin-scoped server +- Added release checks that block machine-local absolute paths and `${PLUGIN_ROOT}` from shipping in Claude MCP config + ## [1.3.3] - 2026-04-08 ### Fixed diff --git a/CLAWHUB.md b/CLAWHUB.md index 16e8c1b..dbce79f 100644 --- a/CLAWHUB.md +++ b/CLAWHUB.md @@ -5,7 +5,7 @@ | Field | Value | |-------|-------| | **Name** | `grok-swarm` | -| **Version** | `1.3.5` | +| **Version** | `1.3.6` | | **Min OpenClaw** | `2026.3.0` | ## Installation diff --git a/VERSION b/VERSION index aaf8be7..95b25ae 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.5 \ No newline at end of file +1.3.6 diff --git a/package-lock.json b/package-lock.json index 5579e4d..01c450f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@khaentertainment/grok-swarm", - "version": "1.3.4", + "version": "1.3.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@khaentertainment/grok-swarm", - "version": "1.3.4", + "version": "1.3.6", "hasInstallScript": true, "license": "MIT", "os": [ diff --git a/package.json b/package.json index 54c3406..81dbc5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@khaentertainment/grok-swarm", - "version": "1.3.5", + "version": "1.3.6", "description": "Multi-agent intelligence powered by Grok 4.20 via OpenRouter. Give any AI coding agent access to a 4-agent swarm with ~2M token context.", "keywords": [ "grok", diff --git a/platforms/claude/.claude-plugin/plugin.json b/platforms/claude/.claude-plugin/plugin.json index 194289c..4c51281 100644 --- a/platforms/claude/.claude-plugin/plugin.json +++ b/platforms/claude/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "manifestVersion": 1, "name": "grok-swarm", - "version": "1.3.5", + "version": "1.3.6", "displayName": "Grok Swarm", "description": "Multi-agent intelligence powered by Grok 4.20 via OpenRouter. Use for codebase analysis, refactoring, code generation, and complex reasoning.", "author": { diff --git a/platforms/claude/.claude-plugin/setup.sh b/platforms/claude/.claude-plugin/setup.sh index dacbf2e..ce4b90a 100755 --- a/platforms/claude/.claude-plugin/setup.sh +++ b/platforms/claude/.claude-plugin/setup.sh @@ -7,13 +7,9 @@ set -euo pipefail PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}" CONFIG_DIR="${HOME}/.config/grok-swarm" CONFIG_FILE="${CONFIG_DIR}/config.json" -VENV_DIR="${PLUGIN_ROOT}/.venv" -REQUIREMENTS_FILE="${PLUGIN_ROOT}/src/requirements.txt" -MCP_SERVER="${PLUGIN_ROOT}/src/mcp/grok_server.py" OAUTH_SCRIPT="${PLUGIN_ROOT}/src/bridge/oauth_setup.py" +BOOTSTRAP_SCRIPT="${PLUGIN_ROOT}/scripts/bootstrap-runtime.sh" PYTHON_BIN="" -SYSTEM_PYTHON="" -STAMP_FILE="${VENV_DIR}/.grok-swarm-requirements.sha256" # Colors RED='\033[0;31m' @@ -25,73 +21,19 @@ log() { echo -e "${GREEN}[+]${NC} $1"; } warn() { echo -e "${YELLOW}[!]${NC} $1" >&2; } error() { echo -e "${RED}[✗]${NC} $1" >&2; } -resolve_system_python() { - if command -v python3 >/dev/null 2>&1; then - SYSTEM_PYTHON="$(command -v python3)" - elif command -v python >/dev/null 2>&1; then - SYSTEM_PYTHON="$(command -v python)" - else - error "Python 3 is required. Install Python 3.8+ and re-run setup." - exit 1 - fi -} - -requirements_hash() { - "$SYSTEM_PYTHON" - <<'PY' "$REQUIREMENTS_FILE" -import hashlib -import pathlib -import sys - -path = pathlib.Path(sys.argv[1]) -print(hashlib.sha256(path.read_bytes()).hexdigest()) -PY -} - ensure_runtime() { - resolve_system_python - - if [ ! -f "$REQUIREMENTS_FILE" ]; then - error "Plugin runtime is incomplete: missing ${REQUIREMENTS_FILE}." - error "Reinstall the Grok Swarm Claude plugin so the bundled runtime is present." - exit 1 - fi - - if [ ! -f "$OAUTH_SCRIPT" ] || [ ! -f "$MCP_SERVER" ]; then - error "Plugin runtime files are missing from ${PLUGIN_ROOT}/src." + if [ ! -f "$BOOTSTRAP_SCRIPT" ]; then + error "Plugin runtime is incomplete: missing ${BOOTSTRAP_SCRIPT}." error "Reinstall the Grok Swarm Claude plugin and try again." exit 1 fi - if [ ! -d "$VENV_DIR" ]; then - log "Creating plugin-local Python environment..." - "$SYSTEM_PYTHON" -m venv "$VENV_DIR" - fi - - PYTHON_BIN="${VENV_DIR}/bin/python3" - if [ ! -x "$PYTHON_BIN" ]; then - PYTHON_BIN="${VENV_DIR}/bin/python" - fi - + PYTHON_BIN="$("$BOOTSTRAP_SCRIPT")" if [ ! -x "$PYTHON_BIN" ]; then - error "Failed to create a usable Python interpreter in ${VENV_DIR}." + error "Bootstrap did not return a usable Python interpreter." exit 1 fi - - local wanted_hash="" - local current_hash="" - wanted_hash="$(requirements_hash)" - if [ -f "$STAMP_FILE" ]; then - current_hash="$(cat "$STAMP_FILE" 2>/dev/null || true)" - fi - - if [ "$wanted_hash" != "$current_hash" ] || ! "$PYTHON_BIN" -c "import openai" >/dev/null 2>&1; then - log "Installing Grok Swarm Python dependencies into ${VENV_DIR}..." - "$PYTHON_BIN" -m pip install --quiet --upgrade pip - "$PYTHON_BIN" -m pip install --quiet -r "$REQUIREMENTS_FILE" - printf '%s\n' "$wanted_hash" > "$STAMP_FILE" - else - log "Plugin-local Python dependencies already installed" - fi + log "Plugin-local Python runtime ready at ${PYTHON_BIN}" } echo "==========================================" @@ -128,19 +70,19 @@ if [ "$HAVE_KEY" -eq 0 ]; then fi fi -# Register MCP server for native tool integration +# Claude Code starts plugin MCP servers automatically from .mcp.json. +# Remove the legacy manual entry created by older setup flows when the plugin +# scoped server is visible, otherwise users see duplicate Grok MCP servers. if command -v claude >/dev/null 2>&1; then echo - log "Registering Grok Swarm MCP server..." - claude mcp remove grok-swarm >/dev/null 2>&1 || true - if claude mcp add grok-swarm -- "$PYTHON_BIN" "$MCP_SERVER" 2>/dev/null; then - log "MCP server registered — grok_query, grok_session_start/continue, grok_agent tools available" + if claude mcp list 2>/dev/null | grep -q '^plugin:grok-swarm:grok-swarm:'; then + claude mcp remove grok-swarm >/dev/null 2>&1 || true + log "Plugin MCP server is managed by Claude Code" else - warn "MCP registration failed (non-fatal). Register manually:" - warn " claude mcp add grok-swarm -- $PYTHON_BIN $MCP_SERVER" + warn "Plugin MCP server is not visible yet. Restart Claude Code or re-enable the plugin if MCP tools do not appear." fi else - warn "Claude CLI not found, skipping MCP registration." + warn "Claude CLI not found; plugin MCP will be managed by Claude Code when available." fi echo diff --git a/platforms/claude/.mcp.json b/platforms/claude/.mcp.json index 44f7193..3473181 100644 --- a/platforms/claude/.mcp.json +++ b/platforms/claude/.mcp.json @@ -1,9 +1,11 @@ { - "grok-swarm": { - "command": "python3", - "args": ["${PLUGIN_ROOT}/src/mcp/grok_server.py"], - "env": { - "PYTHONPATH": "${PLUGIN_ROOT}/src" + "mcpServers": { + "grok-swarm": { + "command": "bash", + "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/mcp-server.sh"], + "env": { + "PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/src" + } } } } diff --git a/platforms/claude/commands/setup.sh b/platforms/claude/commands/setup.sh index b704191..f442b98 100755 --- a/platforms/claude/commands/setup.sh +++ b/platforms/claude/commands/setup.sh @@ -30,7 +30,8 @@ if [ "$NEEDS_SETUP" -eq 0 ] && ! "$PYTHON_BIN" -c "import openai" >/dev/null 2>& fi if command -v claude >/dev/null 2>&1; then - if ! claude mcp list 2>/dev/null | grep -q '^grok-swarm:'; then + if ! claude mcp list 2>/dev/null | grep -Eq '^(plugin:grok-swarm:grok-swarm|grok-swarm):'; then + log "Grok Swarm MCP server is not visible yet; setup will verify runtime and credentials." NEEDS_SETUP=1 fi fi diff --git a/platforms/claude/scripts/bootstrap-runtime.sh b/platforms/claude/scripts/bootstrap-runtime.sh new file mode 100755 index 0000000..33a6101 --- /dev/null +++ b/platforms/claude/scripts/bootstrap-runtime.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# Bootstrap the plugin-local Python runtime and print the interpreter path. + +set -euo pipefail + +PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}" +VENV_DIR="${PLUGIN_ROOT}/.venv" +REQUIREMENTS_FILE="${PLUGIN_ROOT}/src/requirements.txt" +OAUTH_SCRIPT="${PLUGIN_ROOT}/src/bridge/oauth_setup.py" +MCP_SERVER="${PLUGIN_ROOT}/src/mcp/grok_server.py" +STAMP_FILE="${VENV_DIR}/.grok-swarm-requirements.sha256" +SYSTEM_PYTHON="" +PYTHON_BIN="" + +log() { printf '%s\n' "$*" >&2; } + +resolve_system_python() { + if command -v python3 >/dev/null 2>&1; then + SYSTEM_PYTHON="$(command -v python3)" + elif command -v python >/dev/null 2>&1; then + SYSTEM_PYTHON="$(command -v python)" + else + log "ERROR: Python 3 is required. Install Python 3.8+ and re-run /grok-swarm-setup." + exit 1 + fi +} + +requirements_hash() { + "$SYSTEM_PYTHON" - <<'PY' "$REQUIREMENTS_FILE" +import hashlib +import pathlib +import sys + +path = pathlib.Path(sys.argv[1]) +print(hashlib.sha256(path.read_bytes()).hexdigest()) +PY +} + +if [ ! -f "$REQUIREMENTS_FILE" ]; then + log "ERROR: Plugin runtime is incomplete: missing ${REQUIREMENTS_FILE}." + log "Reinstall the Grok Swarm Claude plugin so the bundled runtime is present." + exit 1 +fi + +if [ ! -f "$OAUTH_SCRIPT" ] || [ ! -f "$MCP_SERVER" ]; then + log "ERROR: Plugin runtime files are missing from ${PLUGIN_ROOT}/src." + log "Reinstall the Grok Swarm Claude plugin and try again." + exit 1 +fi + +resolve_system_python + +if [ ! -d "$VENV_DIR" ]; then + log "Creating Grok Swarm plugin-local Python environment..." + "$SYSTEM_PYTHON" -m venv "$VENV_DIR" +fi + +PYTHON_BIN="${VENV_DIR}/bin/python3" +if [ ! -x "$PYTHON_BIN" ]; then + PYTHON_BIN="${VENV_DIR}/bin/python" +fi + +if [ ! -x "$PYTHON_BIN" ]; then + log "ERROR: Failed to create a usable Python interpreter in ${VENV_DIR}." + exit 1 +fi + +wanted_hash="$(requirements_hash)" +current_hash="" +if [ -f "$STAMP_FILE" ]; then + current_hash="$(cat "$STAMP_FILE" 2>/dev/null || true)" +fi + +if [ "$wanted_hash" != "$current_hash" ] || ! "$PYTHON_BIN" -c "import openai" >/dev/null 2>&1; then + log "Installing Grok Swarm Python dependencies into ${VENV_DIR}..." + "$PYTHON_BIN" -m pip install --quiet --upgrade pip + "$PYTHON_BIN" -m pip install --quiet -r "$REQUIREMENTS_FILE" + printf '%s\n' "$wanted_hash" > "$STAMP_FILE" +fi + +printf '%s\n' "$PYTHON_BIN" diff --git a/platforms/claude/scripts/mcp-server.sh b/platforms/claude/scripts/mcp-server.sh new file mode 100755 index 0000000..c4dc33a --- /dev/null +++ b/platforms/claude/scripts/mcp-server.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Claude plugin MCP entrypoint. Bootstraps runtime before execing the server. + +set -euo pipefail + +PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}" +PYTHON_BIN="$("$PLUGIN_ROOT/scripts/bootstrap-runtime.sh")" + +exec "$PYTHON_BIN" "$PLUGIN_ROOT/src/mcp/grok_server.py" diff --git a/platforms/claude/skills/grok-swarm/SKILL.md b/platforms/claude/skills/grok-swarm/SKILL.md index b25e021..4a10959 100644 --- a/platforms/claude/skills/grok-swarm/SKILL.md +++ b/platforms/claude/skills/grok-swarm/SKILL.md @@ -2,7 +2,7 @@ name: grok-swarm description: Multi-agent intelligence powered by Grok 4.20 via OpenRouter. Use for codebase analysis, refactoring, code generation, and complex reasoning. Triggers: "use grok swarm", "grok 4.20", "multi-agent analysis", "codebase audit", "grok refactor", "16 agent mode" author: OpenClaw -version: 1.3.4 +version: 1.3.6 --- # Grok Swarm diff --git a/platforms/claude/src/mcp/grok_server.py b/platforms/claude/src/mcp/grok_server.py index 56070b3..8beff82 100755 --- a/platforms/claude/src/mcp/grok_server.py +++ b/platforms/claude/src/mcp/grok_server.py @@ -58,7 +58,7 @@ # --------------------------------------------------------------------------- SERVER_NAME = "grok-swarm" -SERVER_VERSION = "1.3.4" +SERVER_VERSION = "1.3.6" PROTOCOL_VERSION = "2024-11-05" # --------------------------------------------------------------------------- diff --git a/pyproject.toml b/pyproject.toml index a59b9ce..b9e5b16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "grok-swarm" -version = "1.3.5" +version = "1.3.6" description = "Multi-agent intelligence powered by Grok 4.20 via OpenRouter" readme = "README.md" requires-python = ">=3.8" diff --git a/scripts/test.js b/scripts/test.js index 0e986d7..f4ea865 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -18,6 +18,8 @@ const requiredClaudeCommands = [ 'platforms/claude/commands/grok-swarm-stats.md', 'platforms/claude/commands/grok-swarm-set-key.md', 'platforms/claude/commands/setup.sh', + 'platforms/claude/scripts/bootstrap-runtime.sh', + 'platforms/claude/scripts/mcp-server.sh', ]; console.log('Running Grok Swarm CLI tests...\n'); @@ -34,6 +36,18 @@ if (missingFiles.length > 0) { console.log(`✓ Claude bundle command files present (${requiredClaudeCommands.length})`); +const mcpConfigPath = path.join(root, 'platforms/claude/.mcp.json'); +const mcpConfig = fs.readFileSync(mcpConfigPath, 'utf8'); +if (!mcpConfig.includes('${CLAUDE_PLUGIN_ROOT}/scripts/mcp-server.sh')) { + console.log('✗ Claude MCP config does not use the plugin-local wrapper'); + process.exit(1); +} +if (mcpConfig.includes('${PLUGIN_ROOT}') || /\/Users\/|\/home\/|[A-Za-z]:\\/.test(mcpConfig)) { + console.log('✗ Claude MCP config contains non-portable paths'); + process.exit(1); +} +console.log('✓ Claude MCP config is portable'); + // Test: grok-swarm --help const help = spawn('node', [grokBin, '--help'], { stdio: 'pipe' }); diff --git a/scripts/verify-release.js b/scripts/verify-release.js index f8d0a59..da57c24 100644 --- a/scripts/verify-release.js +++ b/scripts/verify-release.js @@ -16,10 +16,33 @@ function assertExists(relativePath) { } } +function assertPortableClaudeMcpConfig() { + const mcpPath = path.join(root, 'platforms/claude/.mcp.json'); + const raw = fs.readFileSync(mcpPath, 'utf8'); + const parsed = JSON.parse(raw); + + if (!parsed.mcpServers || !parsed.mcpServers['grok-swarm']) { + throw new Error('Claude MCP config must use standard mcpServers.grok-swarm shape'); + } + + if (raw.includes('${PLUGIN_ROOT}')) { + throw new Error('Claude MCP config must use ${CLAUDE_PLUGIN_ROOT}, not ${PLUGIN_ROOT}'); + } + + if (/\/Users\/|\/home\/|[A-Za-z]:\\/.test(raw)) { + throw new Error('Claude MCP config contains a machine-local absolute path'); + } + + if (!raw.includes('${CLAUDE_PLUGIN_ROOT}/scripts/mcp-server.sh')) { + throw new Error('Claude MCP config must launch the plugin-local MCP wrapper'); + } +} + function main() { const requiredClaudeFiles = [ 'platforms/claude/.claude-plugin/plugin.json', 'platforms/claude/.claude-plugin/setup.sh', + 'platforms/claude/.mcp.json', 'platforms/claude/commands/analyze.md', 'platforms/claude/commands/code.md', 'platforms/claude/commands/grok-swarm.md', @@ -36,6 +59,8 @@ function main() { 'platforms/claude/commands/setup.md', 'platforms/claude/commands/setup.sh', 'platforms/claude/commands/stats.md', + 'platforms/claude/scripts/bootstrap-runtime.sh', + 'platforms/claude/scripts/mcp-server.sh', 'platforms/claude/src/requirements.txt', 'platforms/claude/src/agent/grok_agent.py', 'platforms/claude/src/bridge/cli.py', @@ -45,6 +70,7 @@ function main() { ]; requiredClaudeFiles.forEach(assertExists); + assertPortableClaudeMcpConfig(); const packJson = execFileSync('npm', ['pack', '--dry-run', '--json'], { cwd: root, diff --git a/src/mcp/grok_server.py b/src/mcp/grok_server.py index 56070b3..8beff82 100755 --- a/src/mcp/grok_server.py +++ b/src/mcp/grok_server.py @@ -58,7 +58,7 @@ # --------------------------------------------------------------------------- SERVER_NAME = "grok-swarm" -SERVER_VERSION = "1.3.4" +SERVER_VERSION = "1.3.6" PROTOCOL_VERSION = "2024-11-05" # ---------------------------------------------------------------------------