mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-08-03 21:56:02 +08:00
Delete skills/check_mcp.sh
This commit is contained in:
parent
59d7edde88
commit
5e6352e8ca
@ -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 <token>".
|
||||
# ---------------------------------------------------------------------------
|
||||
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}"
|
||||
Loading…
Reference in New Issue
Block a user