From 67cb1b72b50361b9a5d7e4af5cac3bbf4a61681e Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Mon, 16 Feb 2026 19:43:17 +0000 Subject: [PATCH] MCP TAP: pass target_id explicitly in query-rules test payloads This commit updates MCP TAP query-rules tests to always include `target_id` in tool call payloads where query execution is expected. Details: - Added explicit `target_id` arguments to MCP `/mcp/query` tool invocations in rule evaluation tests. - Removed implicit dependence on server-selected defaults during test execution. Why this change is important: - Query-rules behavior is now route-aware and can depend on logical target selection. - Explicit routing in tests prevents non-determinism and ensures assertions are tied to the intended backend target. Result: - More deterministic TAP behavior and clearer validation of rule evaluation under target-based routing. --- test/tap/tests/mcp_rules_testing/mcp_test_helpers.sh | 1 + .../mcp_rules_testing/test_mcp_query_rules_block.sh | 6 +++--- test/tap/tests/mcp_rules_testing/test_phase4_stats.sh | 6 +++--- test/tap/tests/mcp_rules_testing/test_phase5_digest.sh | 4 ++-- .../tests/mcp_rules_testing/test_phase6_eval_block.sh | 4 ++-- .../mcp_rules_testing/test_phase7_eval_rewrite.sh | 2 +- .../mcp_rules_testing/test_phase8_eval_timeout.sh | 4 ++-- .../tests/mcp_rules_testing/test_phase9_eval_okmsg.sh | 10 +++++----- .../test_run_sql_readonly_validation.sh | 6 ++++-- 9 files changed, 23 insertions(+), 20 deletions(-) diff --git a/test/tap/tests/mcp_rules_testing/mcp_test_helpers.sh b/test/tap/tests/mcp_rules_testing/mcp_test_helpers.sh index ceb5d51cf..ca4fda8f7 100755 --- a/test/tap/tests/mcp_rules_testing/mcp_test_helpers.sh +++ b/test/tap/tests/mcp_rules_testing/mcp_test_helpers.sh @@ -22,6 +22,7 @@ MYSQL_DATABASE="${TEST_DB_NAME:-${MYSQL_DATABASE:-testdb}}" # MCP server configuration MCP_HOST="${TAP_ADMINHOST:-${MCP_HOST:-127.0.0.1}}" MCP_PORT="${TAP_MCPPORT:-${MCP_PORT:-6071}}" +MCP_TARGET_ID="${MCP_TARGET_ID:-tap_mysql_default}" # Colors RED='\033[0;31m' diff --git a/test/tap/tests/mcp_rules_testing/test_mcp_query_rules_block.sh b/test/tap/tests/mcp_rules_testing/test_mcp_query_rules_block.sh index 81937fe66..441a34a76 100755 --- a/test/tap/tests/mcp_rules_testing/test_mcp_query_rules_block.sh +++ b/test/tap/tests/mcp_rules_testing/test_mcp_query_rules_block.sh @@ -450,7 +450,7 @@ main() { "Test 1: Block DROP TABLE statement" \ "query" \ "run_sql_readonly" \ - '{"sql": "DROP TABLE IF EXISTS test_table;"}' \ + '{"sql": "DROP TABLE IF EXISTS test_table;", "target_id": "'"${MCP_TARGET_ID}"'"}' \ "DROP TABLE statements are not allowed" \ "100" @@ -459,7 +459,7 @@ main() { "Test 2: Block SELECT from customers table" \ "query" \ "run_sql_readonly" \ - '{"sql": "SELECT * FROM customers;"}' \ + '{"sql": "SELECT * FROM customers;", "target_id": "'"${MCP_TARGET_ID}"'"}' \ "customers table is restricted" \ "101" @@ -468,7 +468,7 @@ main() { "Test 3: Allow SELECT from other tables" \ "query" \ "run_sql_readonly" \ - '{"sql": "SELECT * FROM products;"}' + '{"sql": "SELECT * FROM products;", "target_id": "'"${MCP_TARGET_ID}"'"}' # Display final stats echo "" diff --git a/test/tap/tests/mcp_rules_testing/test_phase4_stats.sh b/test/tap/tests/mcp_rules_testing/test_phase4_stats.sh index 683160b4e..a5a223805 100755 --- a/test/tap/tests/mcp_rules_testing/test_phase4_stats.sh +++ b/test/tap/tests/mcp_rules_testing/test_phase4_stats.sh @@ -157,7 +157,7 @@ main() { # Test 4.12: Execute MCP query matching rule 100 and verify hit counter increments log_info "Executing query matching rule 100..." - PAYLOAD_100='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"SELECT * FROM test_table"}},"id":1}' + PAYLOAD_100='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"SELECT * FROM test_table","target_id":"'"${MCP_TARGET_ID}"'"}},"id":1}' mcp_request "query" "${PAYLOAD_100}" >/dev/null sleep 1 HITS_AFTER_100=$(get_hits 100) @@ -169,7 +169,7 @@ main() { # Test 4.13: Execute MCP query matching rule 101 and verify hit counter increments log_info "Executing query matching rule 101..." - PAYLOAD_101='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"DROP TABLE IF EXISTS dummy_table"}},"id":2}' + PAYLOAD_101='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"DROP TABLE IF EXISTS dummy_table","target_id":"'"${MCP_TARGET_ID}"'"}},"id":2}' mcp_request "query" "${PAYLOAD_101}" >/dev/null sleep 1 HITS_AFTER_101=$(get_hits 101) @@ -192,7 +192,7 @@ main() { # Test 4.15: Execute query NOT matching any rule and verify no test rule counter increments log_info "Executing query NOT matching any test rule..." - PAYLOAD_NO_MATCH='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"SELECT * FROM other_table"}},"id":3}' + PAYLOAD_NO_MATCH='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"SELECT * FROM other_table","target_id":"'"${MCP_TARGET_ID}"'"}},"id":3}' HITS_BEFORE_NO_MATCH_100=$(get_hits 100) HITS_BEFORE_NO_MATCH_101=$(get_hits 101) mcp_request "query" "${PAYLOAD_NO_MATCH}" >/dev/null diff --git a/test/tap/tests/mcp_rules_testing/test_phase5_digest.sh b/test/tap/tests/mcp_rules_testing/test_phase5_digest.sh index f78389a3a..775c518db 100755 --- a/test/tap/tests/mcp_rules_testing/test_phase5_digest.sh +++ b/test/tap/tests/mcp_rules_testing/test_phase5_digest.sh @@ -206,7 +206,7 @@ main() { # Test 5.16: Execute a query and verify it appears in digest log_info "Executing unique query: SELECT COUNT(*) FROM test_phase5_table" - PAYLOAD_1='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"SELECT COUNT(*) FROM test_phase5_table"}},"id":1}' + PAYLOAD_1='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"SELECT COUNT(*) FROM test_phase5_table","target_id":"'"${MCP_TARGET_ID}"'"}},"id":1}' mcp_request "query" "${PAYLOAD_1}" >/dev/null sleep 1 DIGEST_COUNT_AFTER_1=$(exec_admin_silent "SELECT COUNT(*) FROM stats_mcp_query_digest WHERE tool_name = 'run_sql_readonly';") @@ -233,7 +233,7 @@ main() { # Test 5.18: Execute different query and verify new digest entry log_info "Executing different query: SELECT * FROM another_phase5_table LIMIT 10" - PAYLOAD_2='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"SELECT * FROM another_phase5_table LIMIT 10"}},"id":2}' + PAYLOAD_2='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"SELECT * FROM another_phase5_table LIMIT 10","target_id":"'"${MCP_TARGET_ID}"'"}},"id":2}' DIGEST_COUNT_BEFORE_2=$(exec_admin_silent "SELECT COUNT(*) FROM stats_mcp_query_digest WHERE tool_name = 'run_sql_readonly';") log_verbose "Digest count before query 2: ${DIGEST_COUNT_BEFORE_2}" mcp_request "query" "${PAYLOAD_2}" >/dev/null diff --git a/test/tap/tests/mcp_rules_testing/test_phase6_eval_block.sh b/test/tap/tests/mcp_rules_testing/test_phase6_eval_block.sh index a195399ee..1dc934d59 100755 --- a/test/tap/tests/mcp_rules_testing/test_phase6_eval_block.sh +++ b/test/tap/tests/mcp_rules_testing/test_phase6_eval_block.sh @@ -74,7 +74,7 @@ test_is_allowed() { local payload payload=$(cat </dev/null 2>&1 @@ -105,7 +105,7 @@ test_returns_okmsg() { local expected_okmsg="$3" local payload - payload="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"${tool_name}\",\"arguments\":{\"sql\":\"${sql}\"}},\"id\":1}" + payload="{\"jsonrpc\":\"2.0\",\"method\":\"tools/call\",\"params\":{\"name\":\"${tool_name}\",\"arguments\":{\"sql\":\"${sql}\",\"target_id\":\"${MCP_TARGET_ID}\"}},\"id\":1}" local response response=$(mcp_request "query" "${payload}") @@ -212,7 +212,7 @@ main() { log_test "T9.1: Verify OK message response is successful (not error)" TOTAL_TESTS=$((TOTAL_TESTS + 1)) - payload='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"PING"}},"id":1}' + payload='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"PING","target_id":"'"${MCP_TARGET_ID}"'"}},"id":1}' response=$(mcp_request "query" "$payload") log_verbose "Response: ${response}" @@ -239,7 +239,7 @@ main() { TOTAL_TESTS=$((TOTAL_TESTS + 1)) # Execute a PING query (should be intercepted by OK_msg rule) - payload='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"PING"}},"id":1}' + payload='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"PING","target_id":"'"${MCP_TARGET_ID}"'"}},"id":1}' response=$(mcp_request "query" "$payload") log_verbose "Response: ${response}" @@ -268,7 +268,7 @@ main() { log_test "T9.2: Verify health_check queries are not tracked" TOTAL_TESTS=$((TOTAL_TESTS + 1)) - payload='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"SELECT * FROM health_check;"}},"id":1}' + payload='{"jsonrpc":"2.0","method":"tools/call","params":{"name":"run_sql_readonly","arguments":{"sql":"SELECT * FROM health_check;","target_id":"'"${MCP_TARGET_ID}"'"}},"id":1}' response=$(mcp_request "query" "$payload") log_verbose "Response: ${response}" diff --git a/test/tap/tests/mcp_rules_testing/test_run_sql_readonly_validation.sh b/test/tap/tests/mcp_rules_testing/test_run_sql_readonly_validation.sh index a267b116e..52b50c5bd 100755 --- a/test/tap/tests/mcp_rules_testing/test_run_sql_readonly_validation.sh +++ b/test/tap/tests/mcp_rules_testing/test_run_sql_readonly_validation.sh @@ -135,7 +135,8 @@ test_rejected_query() { "params": { "name": "run_sql_readonly", "arguments": { - "sql": ${sql_query} + "sql": ${sql_query}, + "target_id": "${MCP_TARGET_ID}" } }, "id": ${TOTAL_TESTS} @@ -205,7 +206,8 @@ test_allowed_query() { "params": { "name": "run_sql_readonly", "arguments": { - "sql": ${sql_query} + "sql": ${sql_query}, + "target_id": "${MCP_TARGET_ID}" } }, "id": ${TOTAL_TESTS}