Skip to main content
Glama

Chroma MCP Server

by djm81
release.sh15.1 kB
#!/bin/bash # Wrapper script to automate the release process for chroma-mcp-server # Exit immediately if a command exits with a non-zero status. set -e # --- Configuration --- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" PACKAGE_NAME="chroma-mcp-server" PYPI_URL="https://pypi.org/pypi" TESTPYPI_URL="https://test.pypi.org/pypi" PYPROJECT_PATH="${PROJECT_ROOT}/pyproject.toml" # --- Dependency Check --- if ! command -v curl &> /dev/null; then echo "❌ ERROR: curl is required but not found. Please install curl." >&2 exit 1 fi if ! command -v jq &> /dev/null; then echo "❌ ERROR: jq is required but not found. Please install jq (e.g., brew install jq)." >&2 exit 1 fi if ! command -v sed &> /dev/null; then echo "❌ ERROR: sed is required but not found." >&2 exit 1 fi if ! command -v grep &> /dev/null; then echo "❌ ERROR: grep is required but not found." >&2 exit 1 fi # --- Argument Parsing --- VERSION="" SKIP_TESTPYPI=false TEST_ONLY=false YES_FLAG=false UPDATE_TARGET="prod" # Default # Flags to track if options were set via command line VERSION_SET=false SKIP_TESTPYPI_SET=false TEST_ONLY_SET=false UPDATE_TARGET_SET=false usage() { echo "Usage: $0 [-h] [-y] [--skip-testpypi] [--test-only] [--update-target <prod|test>] [--version VERSION]" echo "" echo "Automates the release process: TestPyPI build & test -> Prod PyPI build & publish -> Update Cursor Config." echo "" echo "Options:" echo " -h, --help Show this help message and exit." echo " -y, --yes Automatically answer yes to confirmation prompts (non-interactive)." echo " --skip-testpypi Skip the TestPyPI build and local install test steps." echo " --test-only Only perform the TestPyPI build and local install test, then exit." echo " --update-target <prod|test> Install version from prod (PyPI) or test (TestPyPI) for Cursor use (default: prod)." echo " --version VERSION Specify the version number to release directly." echo "" echo "If --version is not provided in interactive mode, you will be prompted." exit 0 } # --- Helper Functions --- check_if_version_exists() { local pkg_name="$1" local version_to_check="$2" local index_url="$3" local index_name="$4" echo " Checking if version $version_to_check exists on $index_name..." # Use curl to get package info, jq to check if version exists in releases if curl -s "$index_url/$pkg_name/$version_to_check/json" | jq -e '(.info.version == "'"$version_to_check"'")' > /dev/null; then echo " ❌ ERROR: Version $version_to_check already exists on $index_name!" >&2 return 1 # Indicate failure (version exists) else # Check if the overall package fetch failed (e.g., 404), indicating version likely doesn't exist if ! curl -s -f "$index_url/$pkg_name/json" > /dev/null; then echo " Package $pkg_name not found on $index_name (or network error). Assuming version $version_to_check does not exist." return 0 # Indicate success (version likely doesn't exist) fi echo " Version $version_to_check does not appear to exist on $index_name. Proceeding." return 0 # Indicate success (version does not exist) fi } get_current_version() { if [ ! -f "$PYPROJECT_PATH" ]; then echo "❌ ERROR: pyproject.toml not found at $PYPROJECT_PATH" >&2 return 1 fi # Extract version using grep -E and the user's corrected sed -E command current_ver=$(grep -E '^version\s*=\s*\".+\"' "$PYPROJECT_PATH" | sed -E 's/^version[\ ]*=[\ ]*\"([0-9.]+)\"$/\1/') if [ -z "$current_ver" ]; then echo "❌ ERROR: Could not extract current version from $PYPROJECT_PATH using grep/sed." >&2 return 1 fi echo "$current_ver" return 0 } suggest_next_patch_version() { local current_version="$1" # Basic suggestion: increments the last number after the last dot local prefix=$(echo "$current_version" | sed -E 's/\.[0-9]+$//') local patch=$(echo "$current_version" | sed -E 's/^.*\.(.*)/\1/') # Check if patch is purely numeric if [[ "$patch" =~ ^[0-9]+$ ]]; then local next_patch=$((patch + 1)) echo "${prefix}.${next_patch}" else # Cannot auto-increment non-numeric patch (e.g., pre-releases) echo "$current_version" # Suggest current as fallback fi } is_version_greater() { local ver1="$1" # New version local ver2="$2" # Old version # Returns 0 if ver1 > ver2, 1 otherwise if [ "$ver1" == "$ver2" ]; then return 1 # Not greater if equal fi # Use sort -V: If the sorted list's last element is ver1, then ver1 > ver2 if [ "$(printf '%s\n' "$ver1" "$ver2" | sort -V | tail -n 1)" == "$ver1" ]; then return 0 # ver1 is greater else return 1 # ver1 is not greater fi } validate_version_format() { local ver="$1" # Basic X.Y.Z format check, allows for suffixes like -alpha, .rc1 etc. if ! [[ "$ver" =~ ^[0-9]+\.[0-9]+\.[0-9]+([a-zA-Z0-9.-]*)?$ ]]; then echo " ⚠️ Warning: Version format '$ver' seems unusual. Expected X.Y.Z or similar." # Allow proceeding but warn fi return 0 } # --- Main Script Logic --- # Change to the project root directory to ensure paths are correct cd "$PROJECT_ROOT" echo "ℹ️ Changed working directory to project root: $PROJECT_ROOT" # CHANGELOG.md Reminder echo "🔔 REMINDER: Before proceeding with the release, ensure you have:" echo " 1. Verified all tests are passing with adequate coverage" echo " 2. Updated CHANGELOG.md with all notable changes in this version" echo " 3. Update of version number in pyproject.toml will be done automatically" echo "" # Argument parsing loop while [[ $# -gt 0 ]]; do key="$1" case $key in -h|--help) usage ;; -y|--yes) YES_FLAG=true shift # past argument ;; --skip-testpypi) SKIP_TESTPYPI=true SKIP_TESTPYPI_SET=true # Track that it was set shift # past argument ;; --test-only) TEST_ONLY=true TEST_ONLY_SET=true # Track that it was set shift # past argument ;; --update-target) if [[ "$2" == "prod" || "$2" == "test" ]]; then UPDATE_TARGET="$2" UPDATE_TARGET_SET=true # Track that it was set shift # past argument shift # past value else echo "❌ ERROR: --update-target must be 'prod' or 'test'" >&2 usage fi ;; --version) if [ -n "$2" ]; then VERSION="$2" VERSION_SET=true # Track that it was set shift # past argument shift # past value else echo "❌ ERROR: --version requires an argument." >&2 usage fi ;; *) # unknown option echo "❌ ERROR: Unknown option: $1" >&2 usage ;; esac done # --- Interactive Prompts (if not -y and flags not set) --- if [ "$YES_FLAG" = false ]; then echo "🔧 Entering interactive configuration mode (options not set via flags)..." # Prompt for Update Target if [ "$UPDATE_TARGET_SET" = false ]; then read -p " Update target for local UVX installation? (prod/test) [prod]: " target_choice UPDATE_TARGET=${target_choice:-$UPDATE_TARGET} # Default to prod if empty if [[ "$UPDATE_TARGET" != "prod" && "$UPDATE_TARGET" != "test" ]]; then echo " ❌ ERROR: Invalid target. Please enter 'prod' or 'test'." >&2 exit 1 fi echo " Using update target: $UPDATE_TARGET" fi # Prompt for Test-Only (only if target is test) if [ "$TEST_ONLY_SET" = false ] && [ "$UPDATE_TARGET" = "test" ]; then read -p " Run TestPyPI phase ONLY (--test-only)? (y/n) [n]: " test_only_choice if [[ ${test_only_choice:-\"n\"} =~ ^[Yy]$ ]]; then TEST_ONLY=true else TEST_ONLY=false fi echo " Run TestPyPI only: $TEST_ONLY" fi # Prompt for Skip-TestPyPI (only if target is prod) if [ "$SKIP_TESTPYPI_SET" = false ] && [ "$UPDATE_TARGET" = "prod" ]; then read -p " Skip TestPyPI build/test phase (--skip-testpypi)? (y/n) [n]: " skip_testpypi_choice if [[ ${skip_testpypi_choice:-\"n\"} =~ ^[Yy]$ ]]; then SKIP_TESTPYPI=true else SKIP_TESTPYPI=false fi echo " Skip TestPyPI phase: $SKIP_TESTPYPI" fi # Prompt for Version (if not set via flag) if [ "$VERSION_SET" = false ]; then CURRENT_VERSION=$(get_current_version) if [ $? -ne 0 ]; then exit 1; fi SUGGESTED_VERSION=$(suggest_next_patch_version "$CURRENT_VERSION") echo " Current version in pyproject.toml: $CURRENT_VERSION" while true; do read -p " Enter the new version number (suggested: $SUGGESTED_VERSION): " entered_version if [ -z "$entered_version" ]; then entered_version="$SUGGESTED_VERSION" echo " Using suggested version: $entered_version" fi validate_version_format "$entered_version" if is_version_greater "$entered_version" "$CURRENT_VERSION"; then read -p " Confirm release version $entered_version? (y/n) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then VERSION="$entered_version" break else echo " Version not confirmed. Please try again." fi else echo " ❌ ERROR: New version '$entered_version' must be greater than current version '$CURRENT_VERSION'." >&2 fi done fi fi # --- Version Validation (if provided via flag) --- if [ "$VERSION_SET" = true ]; then validate_version_format "$VERSION" # Add check against current version if needed, though less critical if flag is used explicitly # CURRENT_VERSION=$(get_current_version) # if ! is_version_greater "$VERSION" "$CURRENT_VERSION"; then # echo "❌ ERROR: Specified version $VERSION is not greater than current version $CURRENT_VERSION." >&2 # exit 1 # fi fi # Final check: Ensure VERSION is determined if [ -z "$VERSION" ]; then echo "❌ ERROR: Release version could not be determined." >&2 exit 1 fi echo "" echo "🚀 Starting Release Process for Version: $VERSION" echo "--------------------------------------------------" echo "Configuration:" echo " Skip TestPyPI Build/Test: $SKIP_TESTPYPI" echo " TestPyPI Only: $TEST_ONLY" echo " Update Target for Cursor: $UPDATE_TARGET" echo " Non-interactive: $YES_FLAG" echo "--------------------------------------------------" # Confirmation prompt if [ "$YES_FLAG" = false ]; then read -p "Proceed with this release plan? (y/n) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "Release cancelled by user." exit 1 fi fi # --- TestPyPI Phase --- if [ "$SKIP_TESTPYPI" = false ]; then echo "" echo "📦 Phase 1: Building and Publishing to TestPyPI..." # Check if version already exists on TestPyPI BEFORE publishing check_if_version_exists "$PACKAGE_NAME" "$VERSION" "$TESTPYPI_URL" "TestPyPI" if [ $? -ne 0 ]; then exit 1; fi # Exit if version exists # Call publish script (which updates pyproject.toml) echo " Calling publish.sh to build and publish to TestPyPI..." "${SCRIPT_DIR}/publish.sh" -t -y -v "$VERSION" if [ $? -ne 0 ]; then echo "❌ ERROR: Failed to publish to TestPyPI."; exit 1; fi echo "✅ Successfully published to TestPyPI." echo "" echo "🔧 Phase 2: Testing Local Installation..." "${SCRIPT_DIR}/test_uvx_install.sh" if [ $? -ne 0 ]; then echo "❌ ERROR: Local installation test failed."; exit 1; fi echo "✅ Local installation test successful." if [ "$TEST_ONLY" = true ]; then echo "" echo "✅ TestPyPI phase complete (--test-only specified). Exiting." exit 0 fi else echo "⏩ Skipping TestPyPI build and test phases." fi # --- Production Phase --- echo "" echo "📦 Phase 3: Building and Publishing to Production PyPI..." # Check if version already exists on Production PyPI BEFORE publishing check_if_version_exists "$PACKAGE_NAME" "$VERSION" "$PYPI_URL" "Production PyPI" if [ $? -ne 0 ]; then exit 1; fi # Exit if version exists # Extra confirmation for production unless -y is set if [ "$YES_FLAG" = false ]; then read -p "🚨 REALLY publish version $VERSION to Production PyPI? (y/n) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "Production release cancelled by user." exit 1 fi fi # Call publish script (which updates pyproject.toml again if needed, harmless) "${SCRIPT_DIR}/publish.sh" -p -y -v "$VERSION" if [ $? -ne 0 ]; then echo "❌ ERROR: Failed to publish to Production PyPI."; exit 1; fi echo "✅ Successfully published to Production PyPI." # --- Update Phase --- echo "" echo "🔧 Phase 4: Installing Release Version for Local UVX (Target: $UPDATE_TARGET)..." INSTALL_ARGS="" STRATEGY_ARG="" PACKAGE_SPEC="$PACKAGE_NAME@$VERSION" if [ "$UPDATE_TARGET" == "test" ]; then echo " Installing version $VERSION from TestPyPI for local uvx command..." INSTALL_ARGS="--default-index $TESTPYPI_URL --index $PYPI_URL" STRATEGY_ARG="--index-strategy unsafe-best-match" else echo " Installing version $VERSION from PyPI for local uvx command..." # INSTALL_ARGS="--refresh --default-index $PYPI_URL" # Explicitly use PyPI INSTALL_ARGS="--refresh" # Avoid using default-index for pypi as this does not work fi install_command="uvx ${INSTALL_ARGS} ${STRATEGY_ARG} ${PACKAGE_SPEC}" echo " Running: $install_command" eval $install_command # Use eval to handle args correctly if [ $? -ne 0 ]; then echo "❌ ERROR: Failed to install $UPDATE_TARGET version $VERSION locally via uvx."; exit 1; fi echo " ✅ $UPDATE_TARGET version $VERSION installed for local uvx command." echo " Refreshing local UVX cache (may not be necessary with direct install)..." if command -v uvx &> /dev/null; then # Refresh might still help ensure internal links are updated uvx --refresh $PACKAGE_NAME --version echo " ✅ UVX cache refreshed (or attempted)." else echo " ⚠️ UVX command not found, skipping cache refresh." fi echo "" echo "🎉 Release process for $VERSION completed successfully!" echo "ℹ️ Remember to commit and push the updated pyproject.toml and potentially tag the release in Git." echo "ℹ️ Restart Cursor or the MCP Server if needed to pick up the new version." exit 0

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/djm81/chroma_mcp_server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server