23 tests covering the full JSON-RPC 2.0 protocol surface: initialize handshake, silent notifications/initialized, tools/list schema, tools/call with and without args, unknown tool error, unknown method error, and invalid JSON resilience. Fixed assert helpers to use grep -qF -- to prevent leading-dash patterns (like -32601) from being parsed as grep flags. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
107 lines
4.8 KiB
Bash
Executable File
107 lines
4.8 KiB
Bash
Executable File
#!/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
|