|
| 1 | +#!/usr/bin/env bash |
| 2 | +# E2E Test: Docker → MCP Protocol → Full Flow Validation |
| 3 | +# |
| 4 | +# Builds the greeter MCP server as a Docker image, runs it, |
| 5 | +# and validates the full MCP protocol: initialize, tools/list, |
| 6 | +# tools/call, resources/list, resources/read, prompts/list, prompts/get. |
| 7 | +# |
| 8 | +# Usage: ./test/e2e-docker.sh |
| 9 | + |
| 10 | +set -euo pipefail |
| 11 | +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" |
| 12 | +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" |
| 13 | +IMAGE="go-mcp-greeter:e2e" |
| 14 | + |
| 15 | +echo "═══ Building greeter Docker image ═══" |
| 16 | +docker build -t "$IMAGE" -f "$PROJECT_DIR/Dockerfile" "$PROJECT_DIR" |
| 17 | +echo "" |
| 18 | + |
| 19 | +PASS=0 |
| 20 | +FAIL=0 |
| 21 | + |
| 22 | +send_jsonrpc() { |
| 23 | + local method="$1" id="$2" params="$3" |
| 24 | + echo "{\"jsonrpc\":\"2.0\",\"id\":$id,\"method\":\"$method\",\"params\":$params}" |
| 25 | +} |
| 26 | + |
| 27 | +assert_contains() { |
| 28 | + local desc="$1" response="$2" expected="$3" |
| 29 | + if echo "$response" | grep -q "$expected"; then |
| 30 | + echo " ✅ PASS: $desc" |
| 31 | + PASS=$((PASS + 1)) |
| 32 | + else |
| 33 | + echo " ❌ FAIL: $desc" |
| 34 | + echo " Expected: $expected" |
| 35 | + echo " Got: $response" |
| 36 | + FAIL=$((FAIL + 1)) |
| 37 | + fi |
| 38 | +} |
| 39 | + |
| 40 | +echo "═══ Running greeter MCP server ═══" |
| 41 | + |
| 42 | +# Send all MCP requests via stdin, capture all responses from stdout |
| 43 | +RESPONSE=$( |
| 44 | + ( |
| 45 | + # 1. Initialize |
| 46 | + send_jsonrpc "initialize" 1 '{"protocolVersion":"2024-11-05","capabilities":{}}' |
| 47 | + # 2. Initialized notification (should be silently consumed) |
| 48 | + echo '{"jsonrpc":"2.0","method":"notifications/initialized"}' |
| 49 | + # 3. List tools |
| 50 | + send_jsonrpc "tools/list" 2 '{}' |
| 51 | + # 4. Call the greet tool |
| 52 | + send_jsonrpc "tools/call" 3 '{"name":"greet","arguments":{"name":"OpenCode"}}' |
| 53 | + # 5. List resources |
| 54 | + send_jsonrpc "resources/list" 4 '{}' |
| 55 | + # 6. Read the greeting resource |
| 56 | + send_jsonrpc "resources/read" 5 '{"uri":"greeting://world"}' |
| 57 | + # 7. List prompts |
| 58 | + send_jsonrpc "prompts/list" 6 '{}' |
| 59 | + # 8. Get the polite-greeting prompt |
| 60 | + send_jsonrpc "prompts/get" 7 '{"name":"polite-greeting","arguments":{"name":"OpenCode"}}' |
| 61 | + ) | docker run -i --rm "$IMAGE" 2>/dev/null |
| 62 | +) |
| 63 | + |
| 64 | +echo "" |
| 65 | +echo "═══ Validating MCP responses ═══" |
| 66 | +echo "" |
| 67 | + |
| 68 | +# Extract individual responses by JSON-RPC id |
| 69 | +RESP_1=$(echo "$RESPONSE" | grep '"id":1' || echo "") |
| 70 | +RESP_2=$(echo "$RESPONSE" | grep '"id":2' || echo "") |
| 71 | +RESP_3=$(echo "$RESPONSE" | grep '"id":3' || echo "") |
| 72 | +RESP_4=$(echo "$RESPONSE" | grep '"id":4' || echo "") |
| 73 | +RESP_5=$(echo "$RESPONSE" | grep '"id":5' || echo "") |
| 74 | +RESP_6=$(echo "$RESPONSE" | grep '"id":6' || echo "") |
| 75 | +RESP_7=$(echo "$RESPONSE" | grep '"id":7' || echo "") |
| 76 | + |
| 77 | +echo "─── initialize ───" |
| 78 | +assert_contains "Protocol version" "$RESP_1" "2024-11-05" |
| 79 | +assert_contains "Server name" "$RESP_1" "greeter" |
| 80 | +assert_contains "Capabilities include tools" "$RESP_1" "tools" |
| 81 | +assert_contains "Capabilities include resources" "$RESP_1" "resources" |
| 82 | +assert_contains "Capabilities include prompts" "$RESP_1" "prompts" |
| 83 | +echo "" |
| 84 | + |
| 85 | +echo "─── tools/list ───" |
| 86 | +assert_contains "Returns greet tool" "$RESP_2" "greet" |
| 87 | +assert_contains "Has description" "$RESP_2" "Greet a person by name" |
| 88 | +assert_contains "Has input schema" "$RESP_2" "inputSchema" |
| 89 | +echo "" |
| 90 | + |
| 91 | +echo "─── tools/call ───" |
| 92 | +assert_contains "Returns greeting text" "$RESP_3" "Hello, OpenCode!" |
| 93 | +assert_contains "Content type is text" "$RESP_3" "text" |
| 94 | +assert_contains "No error field" "$RESP_3" "result" |
| 95 | +echo "" |
| 96 | + |
| 97 | +echo "─── resources/list ───" |
| 98 | +assert_contains "Returns greeting resource" "$RESP_4" "greeting://world" |
| 99 | +assert_contains "Has resource name" "$RESP_4" "World Greeting" |
| 100 | +echo "" |
| 101 | + |
| 102 | +echo "─── resources/read ───" |
| 103 | +assert_contains "Returns resource content" "$RESP_5" "Hello, World!" |
| 104 | +assert_contains "Has uri field" "$RESP_5" "greeting://world" |
| 105 | +echo "" |
| 106 | + |
| 107 | +echo "─── prompts/list ───" |
| 108 | +assert_contains "Returns polite-greeting prompt" "$RESP_6" "polite-greeting" |
| 109 | +echo "" |
| 110 | + |
| 111 | +echo "─── prompts/get ───" |
| 112 | +assert_contains "Returns prompt messages" "$RESP_7" "messages" |
| 113 | +assert_contains "Message references OpenCode" "$RESP_7" "OpenCode" |
| 114 | +echo "" |
| 115 | + |
| 116 | +echo "═══════════════════════════════════════" |
| 117 | +echo " Results: $PASS passed, $FAIL failed" |
| 118 | +echo "═══════════════════════════════════════" |
| 119 | + |
| 120 | +if [ "$FAIL" -gt 0 ]; then |
| 121 | + echo "" |
| 122 | + echo "Full raw response for debugging:" |
| 123 | + echo "$RESPONSE" |
| 124 | + exit 1 |
| 125 | +fi |
| 126 | + |
| 127 | +echo "" |
| 128 | +echo "✅ All MCP protocol validations passed in Docker!" |
0 commit comments