From d801c9ba4df056d9acc7daee2c83785a2e72f4e6 Mon Sep 17 00:00:00 2001 From: Jan Szumiec Date: Fri, 12 Jun 2026 22:03:55 +0200 Subject: [PATCH] Warn at session start when uv is missing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The genealogy MCP server is launched via `uv run` (.mcp.json). If uv is not on PATH the server fails to start and its tools silently never load — a confusing failure mode with no actionable message. Add a SessionStart hook that checks for uv and, when missing, shows the user install instructions and tells Claude the tools are unavailable (stays silent on the happy path). Ships in two shell-pinned flavours so it runs whichever shell Claude Code selects: - hooks/check-uv.sh — bash (macOS, Linux, Windows + Git Bash) - hooks/check-uv.ps1 — PowerShell (Windows without Git Bash); the command sets a process-scoped Bypass execution policy so the .ps1 can run - hooks/hooks.json — registers both on SessionStart (startup + resume), each pinned via the `shell` field Document the uv requirement (macOS/Linux + Windows install) in README and note the hook in CLAUDE.md. The .ps1 path is not yet verified on a real Windows host — cross-platform `shell`-field behaviour is undocumented. Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 12 ++++++++++++ README.md | 22 ++++++++++++++++++++++ hooks/check-uv.ps1 | 40 ++++++++++++++++++++++++++++++++++++++++ hooks/check-uv.sh | 27 +++++++++++++++++++++++++++ hooks/hooks.json | 36 ++++++++++++++++++++++++++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 hooks/check-uv.ps1 create mode 100755 hooks/check-uv.sh create mode 100644 hooks/hooks.json diff --git a/CLAUDE.md b/CLAUDE.md index 301485c..e59b61d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,6 +50,18 @@ To add a new source: create `sources//` with a `tools.py` that exposes `register(mcp, ...)`, then call it from `server.build_server`. Keep tool names prefixed with the source so they don't collide. +The server is launched via `uv run` (see `.mcp.json`), so `uv` must be on the +user's PATH. A `SessionStart` hook (`hooks/hooks.json`) checks for uv at +session start and, when missing, prints install instructions to the user (and +tells Claude the tools are unavailable) instead of letting the server fail +silently. It ships in two shell-pinned flavours so it runs whichever shell +Claude Code picks: `hooks/check-uv.sh` (bash; macOS/Linux/Windows+Git Bash) +and `hooks/check-uv.ps1` (PowerShell; Windows without Git Bash) — both emit +the same SessionStart JSON. Neither depends on uv itself, and both stay silent +on the happy path. The `.ps1` path has not been exercised on a real Windows +host yet (cross-platform `shell`-field behaviour is undocumented), so verify +there before relying on it. + ## Instructions * To determine if a change was successful, run the test suite. diff --git a/README.md b/README.md index 0bff534..7a14a43 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,28 @@ This repository ships as a Claude Code plugin (the `.claude-plugin/` directory and the `research-person` skill under `skills/`). You can also run the MCP server stand-alone against any MCP client. +## Requirements + +[**uv**](https://docs.astral.sh/uv/) must be installed and on your `PATH` — +the MCP server is launched with `uv run` (see `.mcp.json`), which also +installs the Python dependencies on first run. Without uv the server cannot +start and none of the tools load. Install it with: + +```bash +# macOS / Linux +curl -LsSf https://astral.sh/uv/install.sh | sh + +# Windows (PowerShell) +irm https://astral.sh/uv/install.ps1 | iex +``` + +then restart Claude Code. As a convenience the plugin runs a `SessionStart` +hook that detects a missing uv and prints these instructions instead of +failing silently. The check ships in two flavours so it works regardless of +the shell Claude Code uses: `hooks/check-uv.sh` (bash — macOS, Linux, and +Windows with Git Bash) and `hooks/check-uv.ps1` (PowerShell — Windows +without Git Bash); `hooks/hooks.json` pins each to its shell. + ## Configuration Every knob can be set three ways. Precedence, highest to lowest: diff --git a/hooks/check-uv.ps1 b/hooks/check-uv.ps1 new file mode 100644 index 0000000..9bacc2b --- /dev/null +++ b/hooks/check-uv.ps1 @@ -0,0 +1,40 @@ +# SessionStart hook (PowerShell variant) for the genealogy plugin. +# +# Mirrors check-uv.sh for Windows hosts where Claude Code runs hooks via +# PowerShell (i.e. Git Bash is not installed). The genealogy MCP server is +# launched with `uv run`; if `uv` is missing the server never starts and its +# tools silently fail to load. This warns the user instead. +# +# Stays silent (exit 0, no output) on the happy path. +$ErrorActionPreference = 'Stop' + +if (Get-Command uv -ErrorAction SilentlyContinue) { + exit 0 +} + +# uv not found. Emit the same SessionStart JSON shape as check-uv.sh: +# systemMessage -> shown to the user +# hookSpecificOutput.additionalContext -> injected into Claude's context +# ConvertTo-Json handles all escaping (newlines, non-ASCII) for us. +$userMsg = @" +⚠️ genealogy plugin: 'uv' was not found on your PATH. + +The genealogy MCP server is launched with 'uv run', so its tools (heredis_*, geneteka_*, basia_*, …) will not load until uv is installed. + +Install uv → https://docs.astral.sh/uv/getting-started/installation/ + irm https://astral.sh/uv/install.ps1 | iex +Then restart Claude Code. +"@ + +$ctx = "The 'uv' CLI is not installed on this machine. The genealogy MCP server runs via 'uv run', so all genealogy plugin tools (heredis_*, gedcom_*, geneteka_*, genbaza_*, lubgens_*, basia_*, genpod_*, genealogyindexer_*, familysearch_*) are unavailable until the user installs uv (https://docs.astral.sh/uv) and restarts Claude Code. If asked to use any of these tools, explain this rather than attempting to call them." + +$payload = [ordered]@{ + systemMessage = $userMsg + hookSpecificOutput = [ordered]@{ + hookEventName = 'SessionStart' + additionalContext = $ctx + } +} + +$payload | ConvertTo-Json -Compress -Depth 5 +exit 0 diff --git a/hooks/check-uv.sh b/hooks/check-uv.sh new file mode 100755 index 0000000..0f7c5cd --- /dev/null +++ b/hooks/check-uv.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env sh +# SessionStart hook for the genealogy plugin. +# +# The genealogy MCP server is launched via `uv run` (see .mcp.json). If `uv` +# is not on the user's PATH the server never starts and its tools silently +# fail to load — a confusing failure mode. This hook checks for uv at session +# start and, when it is missing, surfaces a clear, actionable message to the +# user and tells Claude the tools are unavailable. +# +# Stays silent (exit 0, no output) on the happy path so it never adds noise. +set -eu + +if command -v uv >/dev/null 2>&1; then + exit 0 +fi + +# uv not found. Emit SessionStart JSON: +# systemMessage -> shown to the user +# hookSpecificOutput.additionalContext -> injected into Claude's context +# Newlines are written as literal \n (valid JSON escapes); printf's %s passes +# the backslash-n through untouched. +user_msg="⚠️ genealogy plugin: 'uv' was not found on your PATH.\n\nThe genealogy MCP server is launched with 'uv run', so its tools (heredis_*, geneteka_*, basia_*, …) will not load until uv is installed.\n\nInstall uv → https://docs.astral.sh/uv/getting-started/installation/\n curl -LsSf https://astral.sh/uv/install.sh | sh\nThen restart Claude Code." + +ctx="The 'uv' CLI is not installed on this machine. The genealogy MCP server runs via 'uv run', so all genealogy plugin tools (heredis_*, gedcom_*, geneteka_*, genbaza_*, lubgens_*, basia_*, genpod_*, genealogyindexer_*, familysearch_*) are unavailable until the user installs uv (https://docs.astral.sh/uv) and restarts Claude Code. If asked to use any of these tools, explain this rather than attempting to call them." + +printf '{"systemMessage":"%s","hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"%s"}}\n' "$user_msg" "$ctx" +exit 0 diff --git a/hooks/hooks.json b/hooks/hooks.json new file mode 100644 index 0000000..ae8cdef --- /dev/null +++ b/hooks/hooks.json @@ -0,0 +1,36 @@ +{ + "hooks": { + "SessionStart": [ + { + "matcher": "startup", + "hooks": [ + { + "type": "command", + "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/check-uv.sh\"", + "shell": "bash" + }, + { + "type": "command", + "command": "Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force; & \"${CLAUDE_PLUGIN_ROOT}/hooks/check-uv.ps1\"", + "shell": "powershell" + } + ] + }, + { + "matcher": "resume", + "hooks": [ + { + "type": "command", + "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/check-uv.sh\"", + "shell": "bash" + }, + { + "type": "command", + "command": "Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force; & \"${CLAUDE_PLUGIN_ROOT}/hooks/check-uv.ps1\"", + "shell": "powershell" + } + ] + } + ] + } +}