diff --git a/skills/check_mcp.sh b/skills/check_mcp.sh deleted file mode 100644 index fb7f94d..0000000 --- a/skills/check_mcp.sh +++ /dev/null @@ -1,448 +0,0 @@ -#!/bin/bash - -# Check MCP Content Server Availability and Tools -# -# Returns JSON with availability status for each media source: -# { -# "cms_search": true|false, -# "data_cloud": true|false, -# "unsplash": true|false -# } - -set -e - -TIMEOUT=5 - -# URL patterns that identify the content MCP endpoint (name-agnostic) -CONTENT_ENDPOINT_PATTERN="platform/content" -CONTENT_READONLY_PATTERN="content-readonly" - -# Args pattern that identifies the Unsplash MCP server (name-agnostic) -UNSPLASH_MCP_ARGS_PATTERN="unsplash-mcp-server" - - -# --------------------------------------------------------------------------- -# Platform detection and settings path -# --------------------------------------------------------------------------- -get_ide_config_root() { - if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" || "$OSTYPE" == "cygwin" ]]; then - local appdata="${APPDATA:-$HOME/AppData/Roaming}" - echo "$appdata/Code" - elif [[ "$OSTYPE" == "darwin"* ]]; then - echo "$HOME/Library/Application Support/Code" - else - local xdg="${XDG_CONFIG_HOME:-$HOME/.config}" - echo "$xdg/Code" - fi -} - -SETTINGS_PATH="$(get_ide_config_root)/User/globalStorage/salesforce.salesforcedx-einstein-gpt/settings/a4d_mcp_settings.json" - -# --------------------------------------------------------------------------- -# JSON helpers — jq preferred, grep/sed fallback -# --------------------------------------------------------------------------- - -_has_jq() { command -v jq &> /dev/null; } - -# Get the full raw settings as a string (only useful with jq) -_settings_exists() { [[ -f "$SETTINGS_PATH" ]]; } - -# --------------------------------------------------------------------------- -# Name-agnostic content server detection -# Scans ALL mcpServers entries for args containing CONTENT_ENDPOINT_PATTERN -# or CONTENT_READONLY_PATTERN. Returns the server key (name) or empty. -# --------------------------------------------------------------------------- -get_content_server_key() { - if ! _settings_exists; then echo ""; return; fi - - if _has_jq; then - local key - key=$(jq -r ' - .mcpServers // {} | to_entries[] | - select(.value.args? // [] | map(select(type == "string")) | - any(contains("'"$CONTENT_ENDPOINT_PATTERN"'") or contains("'"$CONTENT_READONLY_PATTERN"'"))) - | .key' "$SETTINGS_PATH" 2>/dev/null | head -n 1) - echo "$key" - else - # grep fallback: look for any args line containing the patterns - local key - key=$(grep -B 20 "$CONTENT_ENDPOINT_PATTERN\|$CONTENT_READONLY_PATTERN" "$SETTINGS_PATH" 2>/dev/null \ - | grep -o '"[^"]*": *{' | tail -n 1 | sed 's/[": {]//g') - echo "$key" - fi -} - -# --------------------------------------------------------------------------- -# Content server config queries (all name-agnostic via get_content_server_key) -# --------------------------------------------------------------------------- -is_content_server_disabled() { - local key - key=$(get_content_server_key) - [[ -z "$key" ]] && return 0 # no server found → treat as disabled - - if _has_jq; then - local disabled - disabled=$(jq -r ".mcpServers[\"$key\"].disabled // false" "$SETTINGS_PATH" 2>/dev/null) - [[ "$disabled" == "true" ]] && return 0 - return 1 - else - if grep -A 5 "\"$key\"" "$SETTINGS_PATH" 2>/dev/null | grep -q '"disabled": *true'; then - return 0 - fi - return 1 - fi -} - -is_contentmcp_enabled() { - if ! _settings_exists; then return 1; fi - - local key - key=$(get_content_server_key) - [[ -z "$key" ]] && return 1 - - if is_content_server_disabled; then return 1; fi - return 0 -} - -is_stdio_type() { - if ! _settings_exists; then return 1; fi - - local key - key=$(get_content_server_key) - [[ -z "$key" ]] && return 1 - - if _has_jq; then - local stype - stype=$(jq -r ".mcpServers[\"$key\"].type // empty" "$SETTINGS_PATH" 2>/dev/null) - [[ "$stype" == "stdio" ]] && return 0 - else - if grep -A 10 "\"$key\"" "$SETTINGS_PATH" 2>/dev/null | grep -q '"type": *"stdio"'; then - return 0 - fi - fi - return 1 -} - -# --------------------------------------------------------------------------- -# Extract the MCP content endpoint URL from settings args (name-agnostic). -# Returns empty if not found — no localhost or env var fallback. -# --------------------------------------------------------------------------- -get_contentmcp_url() { - local key - key=$(get_content_server_key) - [[ -z "$key" ]] && { echo ""; return; } - - if _has_jq; then - local url - url=$(jq -r " - .mcpServers[\"$key\"].args // [] | map(select(type == \"string\")) | - map(select(contains(\"$CONTENT_ENDPOINT_PATTERN\") or contains(\"$CONTENT_READONLY_PATTERN\"))) - | .[0] // empty" "$SETTINGS_PATH" 2>/dev/null) - if [[ -n "$url" ]]; then echo "$url"; return; fi - else - local url - url=$(grep -o 'http[s]*://[^"]*' "$SETTINGS_PATH" 2>/dev/null \ - | grep -E "$CONTENT_ENDPOINT_PATTERN|$CONTENT_READONLY_PATTERN" | head -n 1) - if [[ -n "$url" ]]; then echo "$url"; return; fi - fi - - echo "" -} - -# --------------------------------------------------------------------------- -# Name-agnostic Unsplash detection. -# Checks (1) root-level "unsplash" key and (2) any mcpServers entry whose -# args contain "unsplash-mcp-server". -# --------------------------------------------------------------------------- -get_unsplash_server_key() { - if ! _settings_exists; then echo ""; return; fi - - if _has_jq; then - # Check root-level "unsplash" key first - local root_unsplash - root_unsplash=$(jq -r '.unsplash // empty' "$SETTINGS_PATH" 2>/dev/null) - if [[ -n "$root_unsplash" && "$root_unsplash" != "null" ]]; then - echo "__root__" - return - fi - - # Scan mcpServers for any server with unsplash-mcp-server in args - local key - key=$(jq -r ' - .mcpServers // {} | to_entries[] | - select(.value.args? // [] | map(select(type == "string")) | - any(contains("'"$UNSPLASH_MCP_ARGS_PATTERN"'"))) - | .key' "$SETTINGS_PATH" 2>/dev/null | head -n 1) - echo "$key" - else - # grep fallback: check root "unsplash" or args containing the pattern - if grep -q "\"unsplash\"" "$SETTINGS_PATH" 2>/dev/null; then - echo "unsplash" - return - fi - if grep -q "$UNSPLASH_MCP_ARGS_PATTERN" "$SETTINGS_PATH" 2>/dev/null; then - local key - key=$(grep -B 20 "$UNSPLASH_MCP_ARGS_PATTERN" "$SETTINGS_PATH" 2>/dev/null \ - | grep -o '"[^"]*": *{' | tail -n 1 | sed 's/[": {]//g') - echo "$key" - fi - fi -} - -is_unsplash_mcp_enabled() { - if ! _settings_exists; then return 1; fi - - local key - key=$(get_unsplash_server_key) - [[ -z "$key" ]] && return 1 - - if [[ "$key" == "__root__" ]]; then - # Root-level unsplash: check disabled - if _has_jq; then - local disabled - disabled=$(jq -r '.unsplash.disabled // false' "$SETTINGS_PATH" 2>/dev/null) - [[ "$disabled" == "true" ]] && return 1 - fi - return 0 - fi - - # mcpServers entry - if _has_jq; then - local disabled - disabled=$(jq -r ".mcpServers[\"$key\"].disabled // false" "$SETTINGS_PATH" 2>/dev/null) - [[ "$disabled" == "true" ]] && return 1 - return 0 - else - if grep -A 5 "\"$key\"" "$SETTINGS_PATH" 2>/dev/null | grep -q '"disabled": *true'; then - return 1 - fi - return 0 - fi -} - -# --------------------------------------------------------------------------- -# Bearer token extraction (name-agnostic: from the matched content server) -# Looks for --header arg followed by "Authorization: Bearer ". -# --------------------------------------------------------------------------- -get_bearer_token() { - if ! _settings_exists; then echo ""; return; fi - - local key - key=$(get_content_server_key) - [[ -z "$key" ]] && { echo ""; return; } - - if _has_jq; then - # Find the arg after "--header" that starts with "Authorization: Bearer " - local token - token=$(jq -r " - .mcpServers[\"$key\"].args // [] | to_entries | - map(select(.value == \"--header\")) | - .[0].key as \$idx | - if \$idx then - .mcpServers[\"$key\"].args[\$idx + 1] // empty - else empty end - " "$SETTINGS_PATH" 2>/dev/null) - - # jq path above is tricky; simpler approach: iterate pairs - token=$(jq -r " - [.mcpServers[\"$key\"].args // []] | .[0] | . as \$args | - [range(0; length - 1)] | - map(select(\$args[.] == \"--header\" and (\$args[. + 1] | startswith(\"Authorization: Bearer \")))) | - .[0] as \$i | - if \$i then \$args[\$i + 1] | sub(\"Authorization: Bearer \"; \"\") else empty end - " "$SETTINGS_PATH" 2>/dev/null) - echo "$token" - else - local token - token=$(grep -o 'Authorization: Bearer [^"]*' "$SETTINGS_PATH" 2>/dev/null \ - | sed 's/Authorization: Bearer //' | head -n 1) - echo "$token" - fi -} - -# --------------------------------------------------------------------------- -# HTTP helpers -# --------------------------------------------------------------------------- -MCP_ENDPOINT="" -BEARER_TOKEN="" - -_curl_post() { - local url="$1" - local payload="$2" - local include_headers="${3:-false}" - - local -a curl_args=(-s -m "$TIMEOUT") - - if [[ "$include_headers" == "true" ]]; then - curl_args+=(-i) - fi - - if [[ -n "$BEARER_TOKEN" ]]; then - curl_args+=(-H "Authorization: Bearer $BEARER_TOKEN") - fi - curl_args+=(-H "Content-Type: application/json") - curl_args+=(-H "Accept: application/json, text/event-stream") - - if [[ -n "${SESSION_ID:-}" ]]; then - curl_args+=(-H "Mcp-Session-Id: $SESSION_ID") - fi - - curl_args+=(-X POST -d "$payload" "$url") - curl "${curl_args[@]}" 2>/dev/null -} - -_curl_post_status() { - local url="$1" - local payload="$2" - - local -a curl_args=(-s -o /dev/null -w "%{http_code}" -m "$TIMEOUT") - - if [[ -n "$BEARER_TOKEN" ]]; then - curl_args+=(-H "Authorization: Bearer $BEARER_TOKEN") - fi - curl_args+=(-H "Content-Type: application/json") - curl_args+=(-H "Accept: application/json, text/event-stream") - - if [[ -n "${SESSION_ID:-}" ]]; then - curl_args+=(-H "Mcp-Session-Id: $SESSION_ID") - fi - - curl_args+=(-X POST -d "$payload" "$url") - curl "${curl_args[@]}" 2>/dev/null -} - -# --------------------------------------------------------------------------- -# MCP JSON-RPC session flow -# --------------------------------------------------------------------------- -SESSION_ID="" - -initialize_mcp_session() { - if ! command -v curl &> /dev/null; then echo ""; return 1; fi - - local payload='{"jsonrpc":"2.0","method":"initialize","id":"0","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"CheckMCPScript","version":"1.0.0"}}}' - - local response - response=$(_curl_post "$MCP_ENDPOINT" "$payload" "true") - - # Try Mcp-Session-Id from response headers - local sid - sid=$(echo "$response" | grep -i "^Mcp-Session-Id:" | sed 's/^[^:]*: *//' | tr -d '\r\n ') - if [[ -n "$sid" ]]; then echo "$sid"; return 0; fi - - # Try from response body: result.sessionId or result.session_id - local body - body=$(echo "$response" | sed -n '/^\r*$/,$p' | tail -n +2) - if [[ -n "$body" ]] && _has_jq; then - sid=$(echo "$body" | jq -r '.result.sessionId // .result.session_id // empty' 2>/dev/null) - if [[ -n "$sid" ]]; then echo "$sid"; return 0; fi - elif [[ -n "$body" ]]; then - sid=$(echo "$body" | grep -o '"sessionId":"[^"]*"' | sed 's/"sessionId":"//;s/"//' | head -n 1) - if [[ -z "$sid" ]]; then - sid=$(echo "$body" | grep -o '"session_id":"[^"]*"' | sed 's/"session_id":"//;s/"//' | head -n 1) - fi - if [[ -n "$sid" ]]; then echo "$sid"; return 0; fi - fi - - echo "" - return 1 -} - -send_initialized_notification() { - local sid="$1" - if ! command -v curl &> /dev/null; then return 1; fi - - SESSION_ID="$sid" - local payload='{"jsonrpc":"2.0","method":"notifications/initialized"}' - - local status_code - status_code=$(_curl_post_status "$MCP_ENDPOINT" "$payload") - - # Accept both 200 and 202 (matching Python) - if [[ "$status_code" == "200" || "$status_code" == "202" ]]; then - return 0 - fi - return 1 -} - -list_available_tools() { - if ! command -v curl &> /dev/null; then echo ""; return 1; fi - - local sid - sid=$(initialize_mcp_session) - if [[ -z "$sid" ]]; then echo ""; return 1; fi - - if ! send_initialized_notification "$sid"; then echo ""; return 1; fi - - SESSION_ID="$sid" - local payload='{"jsonrpc":"2.0","method":"tools/list","id":"1","params":{}}' - - local response - response=$(_curl_post "$MCP_ENDPOINT" "$payload") - - if [[ -n "$response" ]]; then - echo "$response" - return 0 - fi - echo "" - return 1 -} - -check_mcp_health() { - local response - response=$(list_available_tools) - if [[ -n "$response" ]] && echo "$response" | grep -q '"tools"'; then - return 0 - fi - return 1 -} - -check_tool_available() { - local tool_name="$1" - local tools_response - tools_response=$(list_available_tools) - - if [[ -n "$tools_response" ]]; then - if echo "$tools_response" | grep -q "\"name\": *\"$tool_name\""; then - return 0 - fi - if echo "$tools_response" | grep -q "\"name\":\"$tool_name\""; then - return 0 - fi - fi - return 1 -} - -# =========================================================================== -# Main -# =========================================================================== -cms_search=false -data_cloud=false -unsplash=false - -if ! is_contentmcp_enabled; then - echo '{"cms_search": false, "data_cloud": false, "unsplash": false}' - exit 0 -fi - -if is_stdio_type; then - cms_search=true - data_cloud=true -else - MCP_ENDPOINT=$(get_contentmcp_url) - BEARER_TOKEN=$(get_bearer_token) - - if check_mcp_health; then - if check_tool_available "search_media_cms_channels"; then - cms_search=true - fi - if check_tool_available "search_electronic_media"; then - data_cloud=true - fi - fi -fi - -if is_unsplash_mcp_enabled; then - unsplash=true -fi - -echo "{\"cms_search\": $cms_search, \"data_cloud\": $data_cloud, \"unsplash\": $unsplash}"