From 25cda31f083272d45bb52d1c62017df773801914 Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Mon, 12 Jan 2026 00:59:30 +0000 Subject: [PATCH] Update test_mcp_tools.sh with dynamic tool discovery - Add discover_tools() function that calls tools/list on each endpoint - Store discovered tools in temp file to avoid bash associative array issues - Define all expected tools with test configurations - Only test tools that are discovered via tools/list - Add support for all 5 endpoints: config, query, admin, cache, observe - Add --list-only flag to show discovered tools without testing - Add --endpoint flag to test specific endpoint - Improve help output with endpoint descriptions --- scripts/mcp/test_mcp_tools.sh | 591 +++++++++++++++++----------------- 1 file changed, 294 insertions(+), 297 deletions(-) diff --git a/scripts/mcp/test_mcp_tools.sh b/scripts/mcp/test_mcp_tools.sh index 73196ca7f..fbaf7f3ac 100755 --- a/scripts/mcp/test_mcp_tools.sh +++ b/scripts/mcp/test_mcp_tools.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# test_mcp_tools.sh - Test all MCP tools via HTTPS/JSON-RPC +# test_mcp_tools.sh - Test MCP tools via HTTPS/JSON-RPC with dynamic tool discovery # # Usage: # ./test_mcp_tools.sh [options] @@ -8,8 +8,10 @@ # Options: # -v, --verbose Show verbose output # -q, --quiet Suppress progress messages +# --endpoint NAME Test only specific endpoint (config, query, admin, cache, observe) # --tool NAME Test only specific tool # --skip-tool NAME Skip specific tool +# --list-only Only list discovered tools without testing # -h, --help Show help # @@ -18,20 +20,24 @@ set -e # Configuration MCP_HOST="${MCP_HOST:-127.0.0.1}" MCP_PORT="${MCP_PORT:-6071}" -MCP_CONFIG_URL="https://${MCP_HOST}:${MCP_PORT}/mcp/config" -MCP_QUERY_URL="https://${MCP_HOST}:${MCP_PORT}/mcp/query" + +# Endpoints (will be used for discovery) +ENDPOINTS=("config" "query" "admin" "cache" "observe") # Test options VERBOSE=false QUIET=false +TEST_ENDPOINT="" TEST_TOOL="" SKIP_TOOLS=() +LIST_ONLY=false # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' +CYAN='\033[0;36m' NC='\033[0m' # Statistics @@ -40,6 +46,12 @@ PASSED_TESTS=0 FAILED_TESTS=0 SKIPPED_TESTS=0 +# Temp file for discovered tools +DISCOVERED_TOOLS_FILE=$(mktemp) + +# Cleanup on exit +trap "rm -f ${DISCOVERED_TOOLS_FILE}" EXIT + log_info() { if [ "${QUIET}" = "false" ]; then echo -e "${GREEN}[INFO]${NC} $1" @@ -66,6 +78,12 @@ log_test() { fi } +# Get endpoint URL +get_endpoint_url() { + local endpoint="$1" + echo "https://${MCP_HOST}:${MCP_PORT}/mcp/${endpoint}" +} + # Execute MCP request mcp_request() { local endpoint="$1" @@ -76,8 +94,10 @@ mcp_request() { -H "Content-Type: application/json" \ -d "${payload}" 2>/dev/null) - local body=$(echo "$response" | head -n -1) - local code=$(echo "$response" | tail -n 1) + local body + body=$(echo "$response" | head -n -1) + local code + code=$(echo "$response" | tail -n 1) if [ "${VERBOSE}" = "true" ]; then echo "Request: ${payload}" @@ -92,8 +112,10 @@ mcp_request() { check_mcp_server() { log_test "Checking MCP server accessibility..." + local config_url + config_url=$(get_endpoint_url "config") local response - response=$(mcp_request "${MCP_CONFIG_URL}" '{"jsonrpc":"2.0","method":"ping","id":1}') + response=$(mcp_request "${config_url}" '{"jsonrpc":"2.0","method":"ping","id":1}') if echo "${response}" | grep -q "result"; then log_info "MCP server is accessible" @@ -105,6 +127,64 @@ check_mcp_server() { fi } +# Discover tools from an endpoint +discover_tools() { + local endpoint="$1" + local url + url=$(get_endpoint_url "${endpoint}") + + log_verbose "Discovering tools from endpoint: ${endpoint}" + + local payload='{"jsonrpc":"2.0","method":"tools/list","id":1}' + local response + response=$(mcp_request "${url}" "${payload}") + + # Extract tool names from response + local tools_json="" + + if command -v jq >/dev/null 2>&1; then + # Use jq for reliable JSON parsing + tools_json=$(echo "${response}" | jq -r '.result.tools[].name' 2>/dev/null || echo "") + else + # Fallback to grep/sed + tools_json=$(echo "${response}" | grep -o '"name"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*: "\(.*\)"/\1/') + fi + + # Store discovered tools in temp file + # Format: endpoint:tool_name + while IFS= read -r tool_name; do + if [ -n "${tool_name}" ]; then + echo "${endpoint}:${tool_name}" >> "${DISCOVERED_TOOLS_FILE}" + fi + done <<< "${tools_json}" + + log_verbose "Discovered tools from ${endpoint}: ${tools_json}" +} + +# Check if a tool is discovered on an endpoint +is_tool_discovered() { + local endpoint="$1" + local tool="$2" + local key="${endpoint}:${tool}" + + if grep -q "^${key}$" "${DISCOVERED_TOOLS_FILE}" 2>/dev/null; then + return 0 + fi + return 1 +} + +# Get discovered tools for an endpoint +get_discovered_tools() { + local endpoint="$1" + grep "^${endpoint}:" "${DISCOVERED_TOOLS_FILE}" 2>/dev/null | sed "s/^${endpoint}://" || true +} + +# Count discovered tools for an endpoint +count_discovered_tools() { + local endpoint="$1" + get_discovered_tools "${endpoint}" | wc -l +} + # Assert that JSON contains expected value assert_json_contains() { local response="$1" @@ -116,7 +196,7 @@ assert_json_contains() { fi # Try with jq if available - if command -v jq &> /dev/null; then + if command -v jq >/dev/null 2>&1; then local actual actual=$(echo "${response}" | jq -r "${field}" 2>/dev/null) if [ "${actual}" = "${expected}" ]; then @@ -127,29 +207,20 @@ assert_json_contains() { return 1 } -# Assert that JSON array contains expected value -assert_json_array_contains() { - local response="$1" - local field="$2" - local expected="$3" - - if echo "${response}" | grep -q "${expected}"; then - return 0 - fi - - return 1 -} - # Test a tool test_tool() { - local tool_name="$1" - local arguments="$2" - local expected_field="$3" - local expected_value="$4" + local endpoint="$1" + local tool_name="$2" + local arguments="$3" + local expected_field="$4" + local expected_value="$5" TOTAL_TESTS=$((TOTAL_TESTS + 1)) - log_test "Testing tool: ${tool_name}" + log_test "Testing tool: ${tool_name} (endpoint: ${endpoint})" + + local url + url=$(get_endpoint_url "${endpoint}") local payload payload=$(cat </dev/null || echo "0") + echo "" + echo "Total tools discovered: ${total}" + echo "" } # Parse command line arguments @@ -421,6 +404,10 @@ parse_args() { QUIET=true shift ;; + --endpoint) + TEST_ENDPOINT="$2" + shift 2 + ;; --tool) TEST_TOOL="$2" shift 2 @@ -429,45 +416,47 @@ parse_args() { SKIP_TOOLS+=("$2") shift 2 ;; + --list-only) + LIST_ONLY=true + shift + ;; -h|--help) cat < "${DISCOVERED_TOOLS_FILE}" # Clear the file + + if [ -n "${TEST_ENDPOINT}" ]; then + discover_tools "${TEST_ENDPOINT}" + else + for endpoint in "${ENDPOINTS[@]}"; do + discover_tools "${endpoint}" + done + fi +} + # Run all tests run_all_tests() { echo "======================================" - echo "MCP Tools Test Suite" + echo "MCP Tools Test Suite (Dynamic Discovery)" echo "======================================" echo "" - echo "MCP Server: ${MCP_CONFIG_URL}" + echo "MCP Host: ${MCP_HOST}" + echo "MCP Port: ${MCP_PORT}" echo "" # Print environment variables if set @@ -522,63 +527,55 @@ run_all_tests() { exit 1 fi - echo "" + # Discover all tools + discover_all_tools - # Determine which tests to run - local tests_to_run=() + # Print discovery report + print_discovery_report - if [ -n "${TEST_TOOL}" ]; then - # Run only specific tool - tests_to_run=("${TEST_TOOL}") - else - # Run all tools - tests_to_run=( - "list_schemas" - "list_tables" - "describe_table" - "get_constraints" - "describe_view" - "table_profile" - "column_profile" - "sample_rows" - "sample_distinct" - "run_sql_readonly" - "explain_sql" - "catalog_upsert" - "catalog_get" - "catalog_search" - "catalog_delete" - ) + # Exit if list-only mode + if [ "${LIST_ONLY}" = "true" ]; then + exit 0 fi + echo "======================================" + echo "Running Tests" + echo "======================================" + echo "" + # Run tests - for tool in "${tests_to_run[@]}"; do - if should_skip_tool "${tool}"; then + local num_tests=${#TEST_ENDPOINTS[@]} + for ((i=0; i