#!/usr/bin/env bash # Tests for plugins/hello-world/bin/mcp-server.js # Protocol: JSON-RPC 2.0 over stdio. Tests send input lines and assert on stdout. set -euo pipefail SERVER="$(cd "$(dirname "$0")/../bin" && pwd)/mcp-server.js" PASS=0; FAIL=0 # ── helpers ────────────────────────────────────────────────────────────────── assert_contains() { local label="$1" expected="$2" actual="$3" if echo "$actual" | grep -qF -- "$expected"; then echo " PASS: $label" PASS=$((PASS+1)) else echo " FAIL: $label" echo " expected to contain: $expected" echo " got: $actual" FAIL=$((FAIL+1)) fi } assert_not_contains() { local label="$1" unexpected="$2" actual="$3" if echo "$actual" | grep -qF -- "$unexpected"; then echo " FAIL: $label" echo " expected NOT to contain: $unexpected" echo " got: $actual" FAIL=$((FAIL+1)) else echo " PASS: $label" PASS=$((PASS+1)) fi } # Send newline-separated JSON lines to the server, capture stdout run_server() { printf '%s\n' "$@" | node "$SERVER" 2>/dev/null } # ── tests ──────────────────────────────────────────────────────────────────── echo "initialize" OUT=$(run_server '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{}},"id":1}') assert_contains "returns protocolVersion" '"protocolVersion":"2024-11-05"' "$OUT" assert_contains "returns capabilities" '"capabilities"' "$OUT" assert_contains "returns serverInfo name" '"name":"hello-world"' "$OUT" assert_contains "returns serverInfo version" '"version":"1.0.0"' "$OUT" assert_contains "echoes id" '"id":1' "$OUT" echo "notifications/initialized" OUT=$(run_server '{"jsonrpc":"2.0","method":"notifications/initialized"}') assert_not_contains "no response for notification" '"jsonrpc"' "$OUT" echo "tools/list" OUT=$(run_server \ '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}' \ '{"jsonrpc":"2.0","method":"tools/list","id":2}') assert_contains "lists say_hello tool" '"name":"say_hello"' "$OUT" assert_contains "tool has description" '"description"' "$OUT" assert_contains "tool has inputSchema" '"inputSchema"' "$OUT" assert_contains "schema has name property" '"name"' "$OUT" assert_contains "echoes id 2" '"id":2' "$OUT" echo "tools/call say_hello — no args" OUT=$(run_server \ '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}' \ '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"say_hello","arguments":{}},"id":3}') assert_contains "generic greeting content" 'Hello from the holocron' "$OUT" assert_contains "response has content array" '"content"' "$OUT" assert_contains "content type is text" '"type":"text"' "$OUT" echo "tools/call say_hello — with name" OUT=$(run_server \ '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}' \ '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"say_hello","arguments":{"name":"Obi-Wan"}},"id":4}') assert_contains "personalised greeting" 'Hello, Obi-Wan!' "$OUT" assert_not_contains "not generic greeting" 'Hello from the holocron' "$OUT" echo "tools/call — unknown tool" OUT=$(run_server \ '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}' \ '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"does_not_exist","arguments":{}},"id":5}') assert_contains "error code -32601" '"code":-32601' "$OUT" assert_contains "error field present" '"error"' "$OUT" echo "unknown method with id" OUT=$(run_server \ '{"jsonrpc":"2.0","method":"no_such_method","id":6}') assert_contains "error returned" '"error"' "$OUT" assert_contains "method not found code" '"code":-32601' "$OUT" assert_contains "echoes id 6" '"id":6' "$OUT" echo "invalid JSON — no crash, process continues" OUT=$(run_server \ 'this is not json' \ '{"jsonrpc":"2.0","method":"tools/list","id":7}') assert_contains "valid request after bad input succeeds" '"id":7' "$OUT" assert_not_contains "no error for bad json line" '"error"' "$OUT" # ── summary ────────────────────────────────────────────────────────────────── echo "" echo "Results: $PASS passed, $FAIL failed" [[ $FAIL -eq 0 ]] && exit 0 || exit 1