mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-08-04 06:07:12 +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