AtlatestRepositoryfolio

folio / tree / testtest-mcp-error-isolation.sh

1#!/usr/bin/env bash
2# Regression test for MCP tool-dispatch error-isolation bug.
3#
4# Before the fix, a single tool-handler error poisoned in-process state so
5# subsequent responses serialised to the literal "#<object>" string and the
6# whole session was wedged. This test sends:
7#
8# 1. initialize + notifications/initialized
9# 2. tools/call folio/note-read with wrong arg key (path: instead of name:) → raises
10# 3. tools/call folio/status with valid empty args → should succeed
12# and asserts neither of the two tool-call responses contains the literal
13# "#<object>" text. Exit 0 on pass, non-zero on fail.
14set -u
16FOLIO=${FOLIO:-$(dirname "$0")/../build/release/bin/folio}
17if [ ! -x "$FOLIO" ]; then
18 FOLIO=$(dirname "$0")/../build/dev/bin/folio
19fi
20if [ ! -x "$FOLIO" ]; then
21 echo "ERROR: no folio binary found at build/release/bin/folio or build/dev/bin/folio" >&2
22 exit 2
23fi
25TMPDIR_ROOT=$(mktemp -d -t folio-err-iso.XXXXXX)
26export FOLIO_ROOT="$TMPDIR_ROOT"
27trap 'rm -rf "$TMPDIR_ROOT"' EXIT
29RESP_FILE=$(mktemp)
31 printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{}}}'
32 sleep 0.3
33 printf '%s\n' '{"jsonrpc":"2.0","method":"notifications/initialized"}'
34 sleep 0.3
35 printf '%s\n' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"folio/note-read","arguments":{"path":"whatever.md"}}}'
36 sleep 0.5
37 printf '%s\n' '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"folio/status","arguments":{}}}'
38 sleep 0.5
39) | "$FOLIO" 2>/dev/null > "$RESP_FILE"
41FAIL=0
42LINE2=$(sed -n '2p' "$RESP_FILE")
43LINE3=$(sed -n '3p' "$RESP_FILE")
45if [ -z "$LINE2" ] || [ -z "$LINE3" ]; then
46 echo "FAIL: expected 3 response lines; got $(wc -l < "$RESP_FILE")" >&2
47 cat "$RESP_FILE" >&2
48 rm -f "$RESP_FILE"
49 exit 1
50fi
52if echo "$LINE2" | grep -Fq '#<object>'; then
53 echo "FAIL: poisoned tool call response contains #<object>:" >&2
54 echo " $LINE2" >&2
55 FAIL=1
56fi
57if echo "$LINE3" | grep -Fq '#<object>'; then
58 echo "FAIL: follow-up valid call response contains #<object>:" >&2
59 echo " $LINE3" >&2
60 FAIL=1
61fi
62if ! echo "$LINE3" | grep -Fq 'Folio Status'; then
63 echo "FAIL: follow-up valid call did not contain 'Folio Status' marker:" >&2
64 echo " $LINE3" >&2
65 FAIL=1
66fi
68rm -f "$RESP_FILE"
70if [ $FAIL -eq 0 ]; then
71 echo "PASS: mcp tool-dispatch error isolation"
72 exit 0
73else
74 exit 1
75fi