chore: shadow systemd unit and parity smoke script
Add deploy/verae-mcp-timestamping-go.service (PORT=8001, NATS :4223, REQUIRE_BEARER=0). Add scripts/parity_smoke.sh for tools/list against :8000 and :8001. Does not install on ns1.
This commit is contained in:
parent
30b5df6757
commit
16eb5a6009
2 changed files with 170 additions and 0 deletions
27
deploy/verae-mcp-timestamping-go.service
Normal file
27
deploy/verae-mcp-timestamping-go.service
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Verae MCP timestamping server (Go shadow)
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=verae-mcp
|
||||||
|
Group=verae-mcp
|
||||||
|
WorkingDirectory=/opt/verae/verae-mcp-timestamping-server-go
|
||||||
|
Environment=HOME=/var/lib/verae-mcp
|
||||||
|
Environment=VERAE_MCP_TRANSPORT=streamable-http
|
||||||
|
Environment=VERAE_MCP_HOST=127.0.0.1
|
||||||
|
Environment=VERAE_MCP_PORT=8001
|
||||||
|
Environment=VERAE_NATS_LISTEN=127.0.0.1:4223
|
||||||
|
Environment=VERAE_MCP_REQUIRE_BEARER=0
|
||||||
|
ExecStart=/opt/verae/verae-mcp-timestamping-server-go/bin/verae-mcp-timestamping-server
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=2
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ProtectHome=true
|
||||||
|
ReadWritePaths=/var/lib/verae-mcp
|
||||||
|
PrivateTmp=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
143
scripts/parity_smoke.sh
Executable file
143
scripts/parity_smoke.sh
Executable file
|
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Compare MCP tools/list on Python :8000 and Go :8001 when both are up.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PY_URL="${PY_URL:-http://127.0.0.1:8000/mcp}"
|
||||||
|
GO_URL="${GO_URL:-http://127.0.0.1:8001/mcp}"
|
||||||
|
WANT_TOOLS="${WANT_TOOLS:-stamp verify hash_report signup login session create_user}"
|
||||||
|
|
||||||
|
need() { command -v "$1" >/dev/null 2>&1 || { echo "parity_smoke: need $1" >&2; exit 2; }; }
|
||||||
|
need curl
|
||||||
|
need python3
|
||||||
|
|
||||||
|
port_up() {
|
||||||
|
local hostport="$1"
|
||||||
|
python3 - "$hostport" <<'PY'
|
||||||
|
import socket, sys
|
||||||
|
host, _, port = sys.argv[1].rpartition(":")
|
||||||
|
s = socket.socket()
|
||||||
|
s.settimeout(0.5)
|
||||||
|
try:
|
||||||
|
s.connect((host, int(port)))
|
||||||
|
except OSError:
|
||||||
|
sys.exit(1)
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print sorted tool names (space-separated) for one MCP Streamable HTTP endpoint.
|
||||||
|
mcp_tools_list() {
|
||||||
|
local url="$1"
|
||||||
|
local label="$2"
|
||||||
|
local hdr body code session
|
||||||
|
|
||||||
|
hdr="$(mktemp)"
|
||||||
|
body="$(mktemp)"
|
||||||
|
trap 'rm -f "$hdr" "$body"' RETURN
|
||||||
|
|
||||||
|
code="$(curl -sS -D "$hdr" -o "$body" -w '%{http_code}' \
|
||||||
|
-X POST "$url" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Accept: application/json, text/event-stream' \
|
||||||
|
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"parity-smoke","version":"0.0.1"}}}')" || true
|
||||||
|
|
||||||
|
if [[ "$code" != "200" && "$code" != "202" ]]; then
|
||||||
|
echo "parity_smoke: $label initialize HTTP $code at $url" >&2
|
||||||
|
cat "$body" >&2 || true
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
session="$(python3 - "$hdr" <<'PY'
|
||||||
|
import sys
|
||||||
|
session = ""
|
||||||
|
for line in open(sys.argv[1], encoding="utf-8", errors="replace"):
|
||||||
|
if ":" not in line:
|
||||||
|
continue
|
||||||
|
k, v = line.split(":", 1)
|
||||||
|
if k.strip().lower() == "mcp-session-id":
|
||||||
|
session = v.strip()
|
||||||
|
print(session)
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
|
||||||
|
local -a headers=(
|
||||||
|
-H 'Content-Type: application/json'
|
||||||
|
-H 'Accept: application/json, text/event-stream'
|
||||||
|
)
|
||||||
|
if [[ -n "$session" ]]; then
|
||||||
|
headers+=(-H "Mcp-Session-Id: $session")
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -sS -o /dev/null \
|
||||||
|
-X POST "$url" \
|
||||||
|
"${headers[@]}" \
|
||||||
|
--data '{"jsonrpc":"2.0","method":"notifications/initialized"}' || true
|
||||||
|
|
||||||
|
code="$(curl -sS -o "$body" -w '%{http_code}' \
|
||||||
|
-X POST "$url" \
|
||||||
|
"${headers[@]}" \
|
||||||
|
--data '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}')" || true
|
||||||
|
|
||||||
|
if [[ "$code" != "200" ]]; then
|
||||||
|
echo "parity_smoke: $label tools/list HTTP $code at $url" >&2
|
||||||
|
cat "$body" >&2 || true
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 - "$body" <<'PY'
|
||||||
|
import json, sys
|
||||||
|
raw = open(sys.argv[1], encoding="utf-8", errors="replace").read().strip()
|
||||||
|
text = raw
|
||||||
|
if raw and not raw.lstrip().startswith("{") and "data:" in raw:
|
||||||
|
parts = [line[5:].strip() for line in raw.splitlines() if line.startswith("data:")]
|
||||||
|
text = parts[-1] if parts else raw
|
||||||
|
doc = json.loads(text)
|
||||||
|
result = doc.get("result") or doc
|
||||||
|
tools = result.get("tools") or []
|
||||||
|
names = sorted({t.get("name") for t in tools if isinstance(t, dict) and t.get("name")})
|
||||||
|
print(" ".join(names))
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
sorted_words() {
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
printf '%s\n' $1 | sed '/^$/d' | sort -u | tr '\n' ' ' | sed 's/ *$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! port_up 127.0.0.1:8000; then
|
||||||
|
echo "parity_smoke: Python MCP not listening on 127.0.0.1:8000" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! port_up 127.0.0.1:8001; then
|
||||||
|
echo "parity_smoke: Go MCP not listening on 127.0.0.1:8001" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "parity_smoke: listing tools on Python $PY_URL"
|
||||||
|
py_tools="$(mcp_tools_list "$PY_URL" python)"
|
||||||
|
echo " python: $py_tools"
|
||||||
|
|
||||||
|
echo "parity_smoke: listing tools on Go $GO_URL"
|
||||||
|
go_tools="$(mcp_tools_list "$GO_URL" go)"
|
||||||
|
echo " go: $go_tools"
|
||||||
|
|
||||||
|
py_n="$(sorted_words "$py_tools")"
|
||||||
|
go_n="$(sorted_words "$go_tools")"
|
||||||
|
want_n="$(sorted_words "$WANT_TOOLS")"
|
||||||
|
|
||||||
|
if [[ "$py_n" != "$go_n" ]]; then
|
||||||
|
echo "parity_smoke: FAIL tools/list mismatch" >&2
|
||||||
|
echo " python: $py_n" >&2
|
||||||
|
echo " go: $go_n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for t in $WANT_TOOLS; do
|
||||||
|
if ! printf '%s\n' $go_tools | grep -qx "$t"; then
|
||||||
|
echo "parity_smoke: FAIL missing expected tool $t (want $want_n)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "parity_smoke: OK tools/list match ($go_n)"
|
||||||
Loading…
Reference in a new issue