diff --git a/README.md b/README.md index d2d38c8f..faca35e2 100644 --- a/README.md +++ b/README.md @@ -156,14 +156,19 @@ When configuring a client manually, ensure the command includes the `mcp` subcom - Xcode 16.x or later - Node.js 18.x or later -## Skill +## Skills -XcodeBuildMCP now includes an optional agent skill. Some clients (e.g., Cursor, Claude Code) hide MCP tool schemas behind search/progressive disclosure, which can reduce tool discovery and usage. The skill provides a concise overview of available tools to counter that. If your client already exposes tools up front, you likely don’t need it; only use it if your agent isn’t reaching for XcodeBuildMCP tools. +XcodeBuildMCP now includes two optional agent skills: + +- **MCP Skill**: Primes the agent with instructions on how to use the MCP server's tools (optional when using the MCP server). + +- **CLI Skill**: Primes the agent with instructions on how to navigate the CLI (recommended when using the CLI). + + +To install, copy and paste the command below into a terminal and follow the on-screen instructions. -To install, download and run the installer in a terminal, then choose your client when prompted: ```bash -curl -fsSL https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/main/scripts/install-skill.sh -o install-skill.sh -bash install-skill.sh +curl -fsSL https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/main/scripts/install-skill.sh -o install-skill.sh && bash install-skill.sh ``` For further information on how to install the skill, see: [docs/SKILLS.md](docs/SKILLS.md) diff --git a/docs/SKILLS.md b/docs/SKILLS.md index 606ed88c..4a124e15 100644 --- a/docs/SKILLS.md +++ b/docs/SKILLS.md @@ -1,30 +1,54 @@ # XcodeBuildMCP Skill -This repository bundles a minimal skill that summarizes XcodeBuildMCP workflows and tools to help steer clients to use MCP tools, this is espeically important for clients that progressively load or hide MCP tools behind search interfaces (i.e. Cursor, Claude Code). +XcodeBuildMCP now includes two optional agent skills: -## Install (Claude Code) +- **MCP Skill**: Primes the agent with instructions on how to use the MCP server's tools (optional when using the MCP server). + +- **CLI Skill**: Primes the agent with instructions on how to navigate the CLI (recommended when using the CLI). + +## Easiest way to install + +Install via the interactive installer and follow the on-screen instructions. + +```bash +curl -fsSL https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/main/scripts/install-skill.sh -o install-skill.sh && bash install-skill.sh +``` + +## Automated installation + +Useful for CI/CD pipelines or for agentic installation. `--skill` should be set to either `mcp` or `cli` to install the appropriate skill. + +### Install (Claude Code) ```bash -curl -fsSL https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/main/scripts/install-skill.sh | bash -s -- --claude +curl -fsSL https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/main/scripts/install-skill.sh -o install-skill.sh && bash install-skill.sh --claude --remove-conflict --skill ``` -## Install (Cursor) +### Install (Cursor) ```bash -curl -fsSL https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/main/scripts/install-skill.sh | bash -s -- --cursor +curl -fsSL https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/main/scripts/install-skill.sh -o install-skill.sh && bash install-skill.sh --cursor --remove-conflict --skill ``` -## Install (Codex CLI) +### Install (Codex CLI) + +```bash +curl -fsSL https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/main/scripts/install-skill.sh -o install-skill.sh && bash install-skill.sh --codex --remove-conflict --skill +``` + +### Install (Other Clients) + +For other clients if you know the path to the skills directory you can pass the `--dest` flag. ```bash -curl -fsSL https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/main/scripts/install-skill.sh | bash -s -- --codex +curl -fsSL https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/main/scripts/install-skill.sh -o install-skill.sh && bash install-skill.sh --dest /path/to/skills --remove-conflict --skill ``` -## Install (Other Clients) +## Unsupporting Clients -Some MCP clients do not yet support skills. Use the skill content as a concise, static instruction block: +Some MCP clients that do not yet support skills. Use the skill content as a concise, static instruction prompt: -1. Open `skills/xcodebuildmcp/SKILL.md`. +1. Open `skills/xcodebuildmcp[-cli]/SKILL.md`. 2. Copy the body (everything below the YAML frontmatter). 3. Paste it into the client’s global or project-level instructions/rules area. diff --git a/scripts/install-skill.sh b/scripts/install-skill.sh index 87c3b3a8..fead38c1 100755 --- a/scripts/install-skill.sh +++ b/scripts/install-skill.sh @@ -1,16 +1,78 @@ #!/usr/bin/env bash set -euo pipefail +# Colors and formatting +if [[ -t 1 ]] && [[ "${TERM:-}" != "dumb" ]]; then + BOLD='\033[1m' + DIM='\033[2m' + RESET='\033[0m' + RED='\033[0;31m' + GREEN='\033[0;32m' + YELLOW='\033[0;33m' + BLUE='\033[0;34m' + CYAN='\033[0;36m' +else + BOLD='' + DIM='' + RESET='' + RED='' + GREEN='' + YELLOW='' + BLUE='' + CYAN='' +fi + +# Symbols +CHECK="${GREEN}✓${RESET}" +CROSS="${RED}✗${RESET}" +ARROW="${CYAN}→${RESET}" +WARN="${YELLOW}!${RESET}" + +print_header() { + printf "\n" + printf "${BOLD}${BLUE}╭──────────────────────────────────╮${RESET}\n" + printf "${BOLD}${BLUE}│${RESET} ${BOLD}XcodeBuildMCP Skill Installer${RESET} ${BOLD}${BLUE}│${RESET}\n" + printf "${BOLD}${BLUE}╰──────────────────────────────────╯${RESET}\n" +} + +print_success() { + printf " ${CHECK} ${GREEN}%s${RESET}\n" "$1" +} + +print_error() { + printf " ${CROSS} ${RED}%s${RESET}\n" "$1" >&2 +} + +print_warning() { + printf " ${WARN} ${YELLOW}%s${RESET}\n" "$1" +} + +print_info() { + printf " ${ARROW} %s\n" "$1" +} + +print_step() { + printf "\n${BOLD}%s${RESET}\n" "$1" +} + usage() { - cat <<'EOF' -Usage: install-skill.sh --codex|--claude|--cursor|--dest [--skill ] [--ref ] [--remove-conflict] + cat < [options] -Installs (or replaces) the XcodeBuildMCP skill. If --skill is omitted, the -installer will ask which skill to install. -If the script is run from a local checkout, it installs the local skill file. -Otherwise it downloads the skill from the provided --ref or from main. +${BOLD}Options:${RESET} + --codex Install to Codex skills directory + --claude Install to Claude skills directory + --cursor Install to Cursor skills directory + --dest Install to custom directory + --skill Skill to install (prompted if omitted) + --ref Git ref to download from (default: main) + --remove-conflict Auto-remove conflicting skill + -h, --help Show this help message -If no destination is provided, the installer will prompt for a client. +${BOLD}Description:${RESET} + Installs the XcodeBuildMCP skill for your AI coding assistant. + If run from a local checkout, installs the local skill file. + Otherwise downloads from GitHub. EOF } @@ -79,54 +141,70 @@ while [[ $# -gt 0 ]]; do done prompt_for_destination() { + print_step "Select Target Client" while true; do - printf "Which client should receive the skill?\n" - printf "1) Codex\n" - printf "2) Claude\n" - printf "3) Cursor\n" - read -r -p "Enter 1, 2, or 3: " selection + printf "\n" + printf " ${CYAN}[1]${RESET} Codex\n" + printf " ${CYAN}[2]${RESET} Claude\n" + printf " ${CYAN}[3]${RESET} Cursor\n" + printf "\n" + printf " ${DIM}Enter your choice${RESET} ${BOLD}[1-3]:${RESET} " + read -r selection case "${selection}" in 1) destination="${HOME}/.codex/skills/public" + print_success "Selected Codex" return 0 ;; 2) destination="${HOME}/.claude/skills" + print_success "Selected Claude" return 0 ;; 3) destination="${HOME}/.cursor/skills" + print_success "Selected Cursor" return 0 ;; *) - echo "Invalid selection. Please enter 1, 2, or 3." + print_error "Invalid selection. Please enter 1, 2, or 3." ;; esac done } prompt_for_skill() { + print_step "Select Skill Type" while true; do - printf "Which skill would you like to install?\n" - printf "1) XcodeBuildMCP (MCP server)\n" - printf "2) XcodeBuildMCP CLI\n" - read -r -p "Enter 1 or 2: " selection + printf "\n" + printf " ${CYAN}[1]${RESET} XcodeBuildMCP ${DIM}(MCP server)${RESET}\n" + printf " ${DIM}Full MCP integration with all tools${RESET}\n" + printf "\n" + printf " ${CYAN}[2]${RESET} XcodeBuildMCP CLI\n" + printf " ${DIM}Lightweight CLI-based commands${RESET}\n" + printf "\n" + printf " ${DIM}Enter your choice${RESET} ${BOLD}[1-2]:${RESET} " + read -r selection case "${selection}" in 1) skill_choice="mcp" + print_success "Selected MCP server skill" return 0 ;; 2) skill_choice="cli" + print_success "Selected CLI skill" return 0 ;; *) - echo "Invalid selection. Please enter 1 or 2." + print_error "Invalid selection. Please enter 1 or 2." ;; esac done } +print_header + if [[ -z "${destination}" ]]; then prompt_for_destination fi @@ -165,18 +243,28 @@ if [[ -n "${skill_ref_override}" ]]; then skill_ref="${skill_ref_override}" fi +print_step "Installing" + if [[ -e "${alt_dir}" ]]; then if [[ "${remove_conflict}" == "true" ]]; then rm -r "${alt_dir}" + print_info "Removed conflicting skill: ${alt_label}" else - printf "%s\n" "Only one skill can be installed at a time because the MCP and CLI skills conflict." - read -r -p "Found ${alt_label} at ${alt_dir}. Remove it to continue? [y/N]: " confirm + printf "\n" + print_warning "Conflict detected!" + printf " ${DIM}Only one skill can be installed at a time.${RESET}\n" + printf " ${DIM}Found:${RESET} ${alt_label}\n" + printf " ${DIM}Path:${RESET} ${alt_dir}\n" + printf "\n" + printf " ${BOLD}Remove existing skill to continue?${RESET} ${DIM}[y/N]:${RESET} " + read -r confirm case "${confirm}" in y|Y|yes|YES) rm -r "${alt_dir}" + print_success "Removed ${alt_label}" ;; *) - echo "Aborting to avoid installing both skills." + print_error "Installation cancelled" exit 1 ;; esac @@ -185,6 +273,7 @@ fi if [[ -e "${skill_dir}" ]]; then rm -r "${skill_dir}" + print_info "Replacing existing installation" fi mkdir -p "${skill_dir}" @@ -194,16 +283,28 @@ local_skill_path="${repo_root}/${skill_path}" if [[ -f "${local_skill_path}" ]]; then cp "${local_skill_path}" "${skill_dir}/SKILL.md" + print_info "Installed from local checkout" else - if ! curl -fsSL "${primary_url}" -o "${skill_dir}/SKILL.md"; then + print_info "Downloading from GitHub..." + if ! curl -fsSL "${primary_url}" -o "${skill_dir}/SKILL.md" 2>/dev/null; then if [[ "${skill_ref}" != "main" ]]; then - printf "%s\n" "Release tag ${skill_ref} not found. Falling back to main." - curl -fsSL "${fallback_url}" -o "${skill_dir}/SKILL.md" + print_warning "Tag ${skill_ref} not found, falling back to main" + if ! curl -fsSL "${fallback_url}" -o "${skill_dir}/SKILL.md" 2>/dev/null; then + print_error "Failed to download skill" + exit 1 + fi else - printf "%s\n" "Failed to download ${primary_url}." >&2 + print_error "Failed to download skill" exit 1 fi fi fi -printf 'Installed %s to %s\n' "${skill_label}" "${skill_dir}" +printf "\n" +printf "${BOLD}${GREEN}╭─────────────────────────────────────╮${RESET}\n" +printf "${BOLD}${GREEN}│${RESET} ${CHECK} ${BOLD}Installation Complete${RESET} ${BOLD}${GREEN}│${RESET}\n" +printf "${BOLD}${GREEN}╰─────────────────────────────────────╯${RESET}\n" +printf "\n" +printf " ${BOLD}Skill:${RESET} %s\n" "${skill_label}" +printf " ${BOLD}Location:${RESET} %s\n" "${skill_dir}" +printf "\n" diff --git a/scripts/release.sh b/scripts/release.sh index f229ddef..dd223c6e 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -318,6 +318,14 @@ if [[ "$SKIP_VERSION_UPDATE" == "false" ]]; then README_SKILL_INSTALL_URL_REGEX='https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/[^/]+/scripts/install-skill.sh' run sed_inplace "s#${README_SKILL_INSTALL_URL_REGEX}#https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/v${VERSION}/scripts/install-skill.sh#g" README.md + # Update skill installer URL in docs/SKILLS.md + if [[ -f docs/SKILLS.md ]]; then + echo "📝 Updating skill installer URL in docs/SKILLS.md..." + run sed_inplace "s#${README_SKILL_INSTALL_URL_REGEX}#https://raw.githubusercontent.com/cameroncooke/XcodeBuildMCP/v${VERSION}/scripts/install-skill.sh#g" docs/SKILLS.md + else + echo "⚠️ docs/SKILLS.md not found; skipping update" + fi + # server.json update echo "" if [[ -f server.json ]]; then @@ -331,9 +339,9 @@ if [[ "$SKIP_VERSION_UPDATE" == "false" ]]; then echo "" echo "📦 Committing version changes..." if [[ -f server.json ]]; then - run git add package.json package-lock.json README.md server.json + run git add package.json package-lock.json README.md docs/SKILLS.md server.json else - run git add package.json package-lock.json README.md + run git add package.json package-lock.json README.md docs/SKILLS.md fi run git commit -m "Release v$VERSION" else