diff --git a/.github/workflows/release-mcp-registry.yml b/.github/workflows/release-mcp-registry.yml index a774bcd..f1d694d 100644 --- a/.github/workflows/release-mcp-registry.yml +++ b/.github/workflows/release-mcp-registry.yml @@ -31,12 +31,21 @@ jobs: echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV" - - name: Check the server name is consistent across packages + - name: Check the server metadata is consistent shell: bash run: | server_name="$(jq -r '.name' server.json)" echo "Server name: ${server_name}" + remote_url="https://api.smbcloud.xyz/v1/mcp" + if ! jq -e --arg url "${remote_url}" \ + 'any(.remotes[]?; .type == "streamable-http" and .url == $url)' \ + server.json >/dev/null; then + echo "server.json is missing the Streamable HTTP remote ${remote_url}." >&2 + exit 1 + fi + echo "MCP_REMOTE_URL=${remote_url}" >> "$GITHUB_ENV" + # npm proves ownership through `mcpName` in the published package.json, # which is generated by this script at release time. grep -q "mcpName: \"${server_name}\"" npm/scripts/render-main-package.cjs @@ -47,6 +56,59 @@ jobs: xcrs_server_name="$(jq -r '.name' server-xcrs.json)" grep -q "mcp-name: ${xcrs_server_name}" crates/xcrs/README.md + - name: Verify the hosted MCP endpoint + shell: bash + run: | + remote_url="${MCP_REMOTE_URL}" + response_headers="$(mktemp)" + response_body="$(mktemp)" + trap 'rm -f "${response_headers}" "${response_body}"' EXIT + + request_body='{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smbcloud-registry-release-check","version":"1"}}}' + if ! http_status="$(curl --http1.1 --silent --show-error \ + --connect-timeout 10 \ + --max-time 20 \ + --retry 2 \ + --retry-all-errors \ + --retry-delay 2 \ + --dump-header "${response_headers}" \ + --output "${response_body}" \ + --write-out '%{http_code}' \ + --header 'Accept: application/json, text/event-stream' \ + --header 'Content-Type: application/json' \ + --data "${request_body}" \ + "${remote_url}")"; then + echo "Failed to reach the hosted MCP endpoint ${remote_url}." >&2 + exit 1 + fi + + if [ "${http_status}" = "401" ]; then + if ! grep -Eiq '^www-authenticate:[[:space:]]*Bearer([[:space:]]|$)' "${response_headers}"; then + echo "The hosted MCP endpoint returned 401 without a Bearer challenge." >&2 + cat "${response_headers}" >&2 + exit 1 + fi + echo "The hosted MCP endpoint returned the expected authentication challenge." + elif [ "${http_status}" = "200" ]; then + if jq -e \ + '.jsonrpc == "2.0" and .id == 1 and (has("result") or has("error"))' \ + "${response_body}" >/dev/null 2>&1 || \ + sed -n 's/^data:[[:space:]]*//p' "${response_body}" | \ + jq -se 'any(.[]; .jsonrpc == "2.0" and .id == 1 and (has("result") or has("error")))' \ + >/dev/null; then + echo "The hosted MCP endpoint returned a valid initialize response." + else + echo "The hosted MCP endpoint returned HTTP 200 without a valid MCP response." >&2 + cat "${response_body}" >&2 + exit 1 + fi + else + echo "The hosted MCP endpoint returned unexpected HTTP status ${http_status}." >&2 + cat "${response_headers}" >&2 + cat "${response_body}" >&2 + exit 1 + fi + - name: Set release versions in server metadata shell: bash run: | diff --git a/docs/mcp-registry.md b/docs/mcp-registry.md index bf28d1a..c43552a 100644 --- a/docs/mcp-registry.md +++ b/docs/mcp-registry.md @@ -6,8 +6,9 @@ The repository publishes two MCP servers to the [official MCP Registry](https:// - **`io.github.smbcloudXYZ/xcrs`** — **XCRS Mobile & TV Automation**, available through `xcrs --mcp` or `smb --mcp --scope automation` for Xcode, ControlKit, CoreDevice, and adb workflows. The registry is a metadata index — it doesn't host binaries. The smbCloud -listing points at packages published to npm and NuGet, while the standalone -XCRS listing points at the `xcrs` crate on crates.io. +listing offers the hosted Streamable HTTP server as well as packages published +to npm and NuGet, while the standalone XCRS listing points at the `xcrs` crate +on crates.io. For running and configuring the server itself, see [MCP Server](./mcp.md). @@ -48,7 +49,9 @@ Publishing under `smbcloud.xyz` plus an Ed25519 private key stored as a repo secret. OIDC needs no secret at all, so that's what we use. -### Which packages are listed +### Available connections + +- **Hosted** — Streamable HTTP at `https://api.smbcloud.xyz/v1/mcp`. - **npm** — `@smbcloud/cli`, launched as `npx @smbcloud/cli --mcp`. The package declares a single binary (`smb`), so `npx` resolves it despite the name diff --git a/server.json b/server.json index 03d1637..b89d59d 100644 --- a/server.json +++ b/server.json @@ -19,6 +19,12 @@ "source": "github", "id": "597171611" }, + "remotes": [ + { + "type": "streamable-http", + "url": "https://api.smbcloud.xyz/v1/mcp" + } + ], "packages": [ { "registryType": "npm",