kotlin-sdk/conformance-test/run-conformance.sh
Pavel Gorgulov fdecf6bdf5
feat: add URL mode elicitation and typed schema definitions per MCP (#660)
Add URL mode elicitation support and typed `PrimitiveSchemaDefinition`
hierarchy to align with MCP specification 2025-11-25

closes #540 

## How Has This Been Tested?
unit/integration/conformance

## Breaking Changes
- `ElicitRequestParams` changed from `data class` to `sealed interface`.
A deprecated factory function preserves source compatibility for
`ElicitRequestParams(message, requestedSchema)`.
- `RequestedSchema.properties` changed from `JsonObject` to `Map<String,
PrimitiveSchemaDefinition>`.
- `ElicitRequest.requestedSchema` is deprecated, use `(params as
ElicitRequestFormParams).requestedSchema`.

## Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed
2026-04-01 12:20:12 +02:00

194 lines
5.8 KiB
Shell
Executable file

#!/bin/bash
# Script to run MCP conformance tests for the Kotlin SDK.
#
# Usage: ./conformance-test/run-conformance.sh <command> [extra-args...]
# Commands: server | client | client-auth | all
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1; pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." || exit 1; pwd)"
CONFORMANCE_VERSION="0.1.16"
PORT="${MCP_PORT:-3001}"
SERVER_URL="http://localhost:${PORT}/mcp"
RESULTS_DIR="$SCRIPT_DIR/results"
SERVER_DIST="$SCRIPT_DIR/build/install/conformance-test/bin/conformance-test"
CLIENT_DIST="$SCRIPT_DIR/build/install/conformance-test/bin/conformance-client"
SERVER_PID=""
# shellcheck disable=SC2317
cleanup() {
if [ -n "$SERVER_PID" ] && kill -0 "$SERVER_PID" 2>/dev/null; then
echo "Stopping server (PID: $SERVER_PID)..."
kill "$SERVER_PID" 2>/dev/null || true
wait "$SERVER_PID" 2>/dev/null || true
fi
}
trap cleanup EXIT
build() {
echo "Building conformance-test distributions..."
cd "$PROJECT_ROOT" || return 1
./gradlew :conformance-test:installDist --quiet
cd "$SCRIPT_DIR" || return 1
echo "Build complete."
}
start_server() {
echo "Starting conformance server on port $PORT..."
MCP_PORT="$PORT" "$SERVER_DIST" &
SERVER_PID=$!
echo "Waiting for server to be ready..."
local retries=0
local max_retries=30
while ! curl -sf "$SERVER_URL" > /dev/null 2>&1; do
retries=$((retries + 1))
if [ "$retries" -ge "$max_retries" ]; then
echo "ERROR: Server failed to start after $max_retries attempts"
return 1
fi
sleep 0.5
done
echo "Server is ready (PID: $SERVER_PID)."
}
stop_server() {
if [ -n "$SERVER_PID" ] && kill -0 "$SERVER_PID" 2>/dev/null; then
echo "Stopping server (PID: $SERVER_PID)..."
kill "$SERVER_PID" 2>/dev/null || true
wait "$SERVER_PID" 2>/dev/null || true
SERVER_PID=""
fi
}
run_list_scenarios() {
local output_dir="$RESULTS_DIR/list"
mkdir -p "$output_dir"
echo ""
echo "=========================================="
echo " List Available Scenarios"
echo "=========================================="
local rc=0
npx "@modelcontextprotocol/conformance@$CONFORMANCE_VERSION" list \
"$@" > "$output_dir/scenarios.txt" || rc=$?
cat "$output_dir/scenarios.txt"
return $rc
}
run_server_suite() {
local output_dir="$RESULTS_DIR/server"
mkdir -p "$output_dir"
echo ""
echo "=========================================="
echo " Running SERVER conformance tests"
echo "=========================================="
start_server || return 1
local rc=0
npx "@modelcontextprotocol/conformance@$CONFORMANCE_VERSION" server \
--url "$SERVER_URL" \
--output-dir "$output_dir" \
--expected-failures "$SCRIPT_DIR/conformance-baseline.yml" \
"$@" || rc=$?
stop_server
return $rc
}
run_client_suite() {
local output_dir="$RESULTS_DIR/client"
mkdir -p "$output_dir"
echo ""
echo "=========================================="
echo " Running CLIENT conformance tests"
echo "=========================================="
local scenarios=("initialize" "tools_call" "elicitation-sep1034-client-defaults" "sse-retry")
local rc=0
for scenario in "${scenarios[@]}"; do
npx "@modelcontextprotocol/conformance@$CONFORMANCE_VERSION" client \
--command "$CLIENT_DIST" \
--scenario "$scenario" \
--output-dir "$output_dir" \
--expected-failures "$SCRIPT_DIR/conformance-baseline.yml" \
"$@" || rc=$?
done
return $rc
}
run_client_auth_suite() {
local output_dir="$RESULTS_DIR/client-auth"
mkdir -p "$output_dir"
echo ""
echo "=========================================="
echo " Running CLIENT (auth) conformance tests"
echo "=========================================="
local rc=0
npx "@modelcontextprotocol/conformance@$CONFORMANCE_VERSION" client \
--command "$CLIENT_DIST" \
--suite auth \
--output-dir "$output_dir" \
--expected-failures "$SCRIPT_DIR/conformance-baseline.yml" \
"$@" || rc=$?
local extra_scenarios=("auth/client-credentials-jwt" "auth/client-credentials-basic" "auth/cross-app-access-complete-flow")
for scenario in "${extra_scenarios[@]}"; do
npx "@modelcontextprotocol/conformance@$CONFORMANCE_VERSION" client \
--command "$CLIENT_DIST" \
--scenario "$scenario" \
--output-dir "$output_dir" \
--expected-failures "$SCRIPT_DIR/conformance-baseline.yml" \
"$@" || rc=$?
done
return $rc
}
# ============================================================================
# Main
# ============================================================================
COMMAND="${1:-}"
shift 2>/dev/null || true
if [ -z "$COMMAND" ]; then
echo "Usage: $0 <command> [extra-args...]"
echo "Commands: list | server | client | client-auth | all"
exit 1
fi
build
EXIT_CODE=0
case "$COMMAND" in
list)
run_list_scenarios "$@" || EXIT_CODE=1
;;
server)
run_server_suite "$@" || EXIT_CODE=1
;;
client)
run_client_suite "$@" || EXIT_CODE=1
;;
client-auth)
run_client_auth_suite "$@" || EXIT_CODE=1
;;
all)
run_server_suite "$@" || EXIT_CODE=1
run_client_suite "$@" || EXIT_CODE=1
run_client_auth_suite "$@" || EXIT_CODE=1
;;
*)
echo "Unknown command: $COMMAND"
echo "Commands: list | server | client | client-auth | all"
exit 1
;;
esac
echo ""
echo "=========================================="
echo " Results saved to: $RESULTS_DIR"
echo "=========================================="
exit $EXIT_CODE