Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ The MCP server itself is not developed here. Problems with tool behavior, the se

`openclaw/<name>/` 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 <key>` then `mcp-publisher publish` from the repo root.

## Validation

```
Expand Down
10 changes: 10 additions & 0 deletions scripts/validate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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.`,
);
}
Comment on lines +328 to +332

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

node <<'NODE'
const description = "😀".repeat(100);
const codePoints = Array.from(description).length;

if (description.length !== 200 || codePoints !== 100) {
  throw new Error(`Unexpected counts: ${description.length}/${codePoints}`);
}

console.log({ codeUnits: description.length, codePoints });
NODE

Repository: IFTTT/ifttt-plugins

Length of output: 193


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- validator context ---'
sed -n '300,345p' scripts/validate.mjs

printf '%s\n' '--- description schema references ---'
rg -n -C 3 '"description"|maxLength|server\.schema|2025-12-11' . \
  -g '!node_modules' -g '!dist' -g '!build' | head -200

printf '%s\n' '--- referenced schema ---'
curl -fsSL https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json |
  node -e '
    let data = "";
    process.stdin.on("data", chunk => data += chunk);
    process.stdin.on("end", () => {
      const schema = JSON.parse(data);
      console.log(JSON.stringify({
        description: schema.properties?.description,
        serverDescription: schema.properties?.server?.properties?.description
      }, null, 2));
    });
  '

Repository: IFTTT/ifttt-plugins

Length of output: 5425


🏁 Script executed:

#!/bin/bash
set -euo pipefail

curl -fsSL https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json |
  python3 -c '
import json, sys
schema = json.load(sys.stdin)

def walk(value, path=()):
    if isinstance(value, dict):
        if "maxLength" in value or "description" in value:
            print(json.dumps({"path": ".".join(path), "value": value}, ensure_ascii=False))
        for key, child in value.items():
            walk(child, path + (str(key),))
    elif isinstance(value, list):
        for index, child in enumerate(value):
            walk(child, path + (str(index),))

walk(schema)
'

Repository: IFTTT/ifttt-plugins

Length of output: 30025


🌐 Web query:

JSON Schema validation maxLength Unicode code points UTF-16 code units official specification

💡 Result:

In the official JSON Schema specification, the validation keywords maxLength and minLength are defined based on the number of Unicode code points in a string [1][2][3]. While older drafts of the specification referred to the "number of its characters" as defined by relevant IETF RFCs for JSON (such as RFC 8259) [4][5][6], current specifications explicitly clarify this as the count of Unicode code points [1]. It is important to note that this is distinct from UTF-16 code units [7]. Because many programming environments (such as JavaScript/Node.js) count length by UTF-16 code units, a discrepancy can arise when handling characters outside the Basic Multilingual Plane (BMP), such as certain emojis or complex symbols [7]. For example, a single character consisting of a surrogate pair in UTF-16 counts as two code units but only one Unicode code point [7]. Consequently, developers should be aware that implementation-specific string length properties—often based on UTF-16 code units—may not align with the JSON Schema requirement of counting Unicode code points [7].

Citations:


Count Unicode code points for the 100-character cap.

String.prototype.length counts UTF-16 code units. Use Array.from(manifest.description).length for both the comparison and the error message.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/validate.mjs` around lines 328 - 332, Update the description-length
validation to count Unicode code points with
Array.from(manifest.description).length for both the 100-character comparison
and the error message, instead of using manifest.description.length.


if (typeof manifest.version === "string" && !semverPattern.test(manifest.version)) {
addError(`server.json "version" ("${manifest.version}") must be semver (e.g. 1.0.0).`);
}
Comment on lines +334 to +336

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

schema_url='https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json'

curl -fsSL "$schema_url" |
  jq -e '.definitions.ServerDetail.properties.version.description
    | contains("Non-semantic versions are allowed")'

Repository: IFTTT/ifttt-plugins

Length of output: 162


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- validator context ---'
sed -n '300,355p' scripts/validate.mjs

printf '%s\n' '--- repository policy references ---'
rg -n -i --glob '!node_modules' --glob '!dist' \
  'semver|semantic version|non-semantic|version.*policy|version.*format|contribut|server\.json' \
  README.md CONTRIBUTING.md .github scripts package.json 2>/dev/null || true

printf '%s\n' '--- version declarations and validator usage ---'
rg -n --glob '!node_modules' \
  '"version"\s*:|semverPattern|manifest\.version|validate\.mjs' . 2>/dev/null | head -250

Repository: IFTTT/ifttt-plugins

Length of output: 6703


Document the server.json SemVer policy.

CONTRIBUTING.md documents SemVer for OpenClaw skill frontmatter but not for server.json. The validator rejects non-SemVer versions, while the MCP Registry schema permits them. Document this repository-specific requirement and the stricter local validation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/validate.mjs` around lines 334 - 336, Update CONTRIBUTING.md to
document that server.json version values must use SemVer, including the
repository’s stricter local validation despite the MCP Registry schema
permitting non-SemVer values. Place this guidance alongside the existing
OpenClaw skill frontmatter SemVer policy.


if (!Array.isArray(manifest.remotes) || manifest.remotes.length === 0) {
addError('server.json "remotes" must be a non-empty array.');
}
Expand Down
Loading