From 13732478a7db01048181ef4fbaf2cc52d7d6152a Mon Sep 17 00:00:00 2001 From: Siddharth Sathyam Date: Fri, 7 Aug 2026 12:07:08 -0500 Subject: [PATCH] Guard the MCP Registry entry in CI and document republishing [sc-146582] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Publishing server.json to the registry is a manual step that only lives in one person's shell history, and the first attempt failed on a schema limit that nothing checked for. Automating it in CI would mean storing the ifttt.com Ed25519 signing key as an Actions secret. This repository is public, and the com.ifttt namespace authenticates by domain rather than through GitHub, so there is no keyless way to publish from here — publishing stays a manual maintainer step, run from the key in 1Password. What CI can do without the key is catch the mistakes before they reach a publish attempt: server.json's description now fails validation past the registry's 100-character cap, and version must be semver. CONTRIBUTING.md documents the entry, the manual publish sequence, and why the key is deliberately not in CI. --- CONTRIBUTING.md | 6 ++++++ scripts/validate.mjs | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2230d43..19c7c18 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,12 @@ The MCP server itself is not developed here. Problems with tool behavior, the se `openclaw//` holds ClawHub-format skills for [OpenClaw](https://openclaw.ai), one folder per skill. Each folder needs a `SKILL.md` whose frontmatter declares `name` (matching the directory name, lowercase letters/numbers/hyphens), `description`, and `version` (semver). The validator checks all three. Keep the skill's guidance in sync with the Cursor plugin's skills and rules — it is the same content restructured into ClawHub's single-file format. Publishing is a manual maintainer step; see [openclaw/README.md](./openclaw/README.md). +## The MCP Registry entry + +[`server.json`](./server.json) is the server's listing in the [official MCP Registry](https://registry.modelcontextprotocol.io), published under the `com.ifttt` namespace. Changing the file does not change the listing — a maintainer has to republish, so bump `version` in the same PR as any change you want to go live. `node scripts/validate.mjs` checks the constraints that are easy to trip over, notably the registry's 100-character cap on `description`; `mcp-publisher validate` checks the file against the live schema. + +Publishing is a manual maintainer step. It authenticates by proving ownership of ifttt.com rather than through GitHub, which means signing a challenge with an Ed25519 private key — kept in 1Password (Engineering vault, "MCP Registry - ifttt.com DNS signing key"), deliberately not in this repo's CI, since this repository is public. Its public half is the `v=MCPv1` string in the ifttt.com apex TXT record, managed in `infra-misc`; rotating the key means updating both halves or publishing breaks. The item's notes carry the full sequence — in short, `mcp-publisher login dns --domain ifttt.com --private-key ` then `mcp-publisher publish` from the repo root. + ## Validation ``` diff --git a/scripts/validate.mjs b/scripts/validate.mjs index f374a59..63481e8 100644 --- a/scripts/validate.mjs +++ b/scripts/validate.mjs @@ -325,6 +325,16 @@ async function validateRegistryManifest() { } } + if (typeof manifest.description === "string" && manifest.description.length > 100) { + addError( + `server.json "description" is ${manifest.description.length} characters; the registry schema caps it at 100.`, + ); + } + + if (typeof manifest.version === "string" && !semverPattern.test(manifest.version)) { + addError(`server.json "version" ("${manifest.version}") must be semver (e.g. 1.0.0).`); + } + if (!Array.isArray(manifest.remotes) || manifest.remotes.length === 0) { addError('server.json "remotes" must be a non-empty array.'); }