#!/usr/bin/env bash # Drives the real MuseHub MCP stdio server for Episode 16 ("Muse + MCP"). # Unlike every other episode's demo script, this one does NOT build a # disposable `muse init` repo -- it requires the local MuseHub dev stack # (docker compose, `musehub` + `musehub_worker` containers) already running, # per ~/ecosystem/musehub/.museagent.md. Re-run any block independently; # nothing here is destructive except the throwaway `mcp-episode16-demo` repo # it creates on the LOCAL hub. set -euo pipefail cd ~/ecosystem/musehub echo "=== Part 1: the documented path -- DEBUG=true, corrupted stdout ===" echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{}}}' \ | docker exec -i musehub python3 -m musehub.mcp.stdio_server >/tmp/ep16-debugtrue-stdout.log 2>/tmp/ep16-debugtrue-stderr.log echo "stdout line count (should be ~1 for a clean transport): $(wc -l < /tmp/ep16-debugtrue-stdout.log)" echo "first 3 lines of stdout:" head -3 /tmp/ep16-debugtrue-stdout.log echo echo "=== Part 2: DEBUG=false -- the same call, clean ===" echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{}}}' \ | docker exec -i -e DEBUG=false musehub python3 -m musehub.mcp.stdio_server >/tmp/ep16-debugfalse-stdout.log 2>/tmp/ep16-debugfalse-stderr.log echo "stdout line count: $(wc -l < /tmp/ep16-debugfalse-stdout.log)" cat /tmp/ep16-debugfalse-stdout.log echo echo "=== Part 3: tools/resources/prompts -- real counts vs documented counts ===" printf '%s\n' \ '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{}}}' \ '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \ '{"jsonrpc":"2.0","id":3,"method":"resources/list"}' \ '{"jsonrpc":"2.0","id":4,"method":"prompts/list"}' \ | docker exec -i -e DEBUG=false musehub python3 -m musehub.mcp.stdio_server 2>/dev/null \ | python3 -c " import json, sys for line in sys.stdin: d = json.loads(line) if d.get('id') == 2: print('tools:', len(d['result']['tools']), '(docs claim 40)') if d.get('id') == 3: print('resources:', len(d['result']['resources']), '(docs claim 29)') if d.get('id') == 4: print('prompts:', len(d['result']['prompts']), '(docs claim 10)') " echo echo "=== Part 4: session context -- set_context, then the very next call ===" docker exec -i -e DEBUG=false musehub python3 -m musehub.mcp.stdio_server 2>/dev/null <<'EOF' {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{}}} {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"musehub_set_context","arguments":{"owner":"gabriel","slug":"build-with-muse"}}} {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"musehub_read_context","arguments":{}}} {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"musehub_read_context","arguments":{"owner":"gabriel","slug":"build-with-muse"}}} EOF echo echo "=== Part 5: a real write tool call against a throwaway repo ===" muse -C ~/ecosystem/musehub hub repo delete gabriel/mcp-episode16-demo --yes --json > /dev/null 2>&1 || true muse -C ~/ecosystem/musehub hub repo create --name mcp-episode16-demo --visibility public --json | python3 -m json.tool | head -6 docker exec -i -e DEBUG=false musehub python3 -m musehub.mcp.stdio_server 2>/dev/null <<'EOF' {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{}}} {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"musehub_create_issue","arguments":{"owner":"gabriel","slug":"mcp-episode16-demo","title":"Real issue filed by an LLM over MCP","body":"Created live during Episode 16 recording, via a real tools/call over the stdio JSON-RPC transport -- not simulated."}}} {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"musehub_list_issues","arguments":{"owner":"gabriel","slug":"mcp-episode16-demo"}}} EOF echo echo "Demo complete."