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
84 changes: 84 additions & 0 deletions .github/scripts/server-json-validator/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .github/scripts/server-json-validator/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "cudly-mcp-server-json-validator",
"private": true,
"dependencies": {
"ajv": "8.20.0",
"ajv-formats": "3.0.1"
}
}
22 changes: 22 additions & 0 deletions .github/scripts/server-json-validator/validate.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const fs = require("fs");
const Ajv = require("ajv");
const addFormats = require("ajv-formats");

const [schemaPath, dataPath] = process.argv.slice(2);
if (!schemaPath || !dataPath) {
console.error("usage: node .github/scripts/server-json-validator/validate.cjs <schema.json> <server.json>");
process.exit(2);
}

const schema = JSON.parse(fs.readFileSync(schemaPath, "utf8"));
const data = JSON.parse(fs.readFileSync(dataPath, "utf8"));
const ajv = new Ajv({ strict: false, allErrors: true });
addFormats(ajv);

const valid = ajv.validate(schema, data);
if (!valid) {
console.error(JSON.stringify(ajv.errors, null, 2));
process.exit(1);
}

console.log(`${dataPath} valid`);
80 changes: 80 additions & 0 deletions .github/workflows/mcp-server-json.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: MCP server.json

# Validates server.json (the MCP Registry listing manifest) on every PR that
# touches it, and gates tag pushes on server.json's version matching the tag.
# The registry rejects republishing a version, so a mismatch here must fail
# loud rather than let release automation publish the wrong metadata.

on:
pull_request:
paths:
- "server.json"
- ".github/workflows/mcp-server-json.yml"
- ".github/scripts/server-json-validator/**"
push:
tags: ["v*"]
workflow_dispatch:

permissions:
contents: read

jobs:
validate-schema:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
with:
persist-credentials: false

- name: Fetch the MCP Registry server.json schema
run: |
set -euo pipefail
expected_schema_url="https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json"
expected_registry_name="io.github.LeanerCloud/cudly-mcp"
if ! jq -e --arg expected "$expected_schema_url" \
'.["$schema"] | type == "string" and . == $expected' server.json >/dev/null; then
echo "::error::server.json must declare the official MCP Registry \$schema URL"
exit 1
fi
if ! jq -e --arg expected "$expected_registry_name" \
'.name | type == "string" and . == $expected' server.json >/dev/null; then
echo "::error::server.json name must be $expected_registry_name"
exit 1
fi
curl -sSfL --connect-timeout 10 --max-time 30 \
"$expected_schema_url" -o /tmp/server.schema.json

- name: Install server.json validator dependencies
working-directory: .github/scripts/server-json-validator
run: npm ci --ignore-scripts --no-audit --no-fund

- name: Validate server.json against the schema
run: node .github/scripts/server-json-validator/validate.cjs /tmp/server.schema.json server.json

assert-version-matches-tag:
if: startsWith(github.ref, 'refs/tags/v')
needs: validate-schema
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
with:
persist-credentials: false

- name: Assert server.json version matches the pushed tag
run: |
set -euo pipefail
tag="${GITHUB_REF#refs/tags/v}"
server_version=$(jq -r '.version' server.json)
if [[ "$tag" != "$server_version" ]]; then
echo "::error::server.json version ($server_version) does not match tag v$tag." \
"Correct server.json.version in the release commit before creating or recreating the tag;" \
"this workflow never rewrites the file."
exit 1
fi
echo "server.json version ($server_version) matches tag v$tag"
30 changes: 30 additions & 0 deletions server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.LeanerCloud/cudly-mcp",
"description": "Search and buy AWS/Azure/GCP reserved capacity (RIs, Savings Plans, CUDs) via any MCP client.",
"repository": {
"url": "https://github.com/LeanerCloud/CUDly",
"source": "github"
},
"version": "0.1.0",
"websiteUrl": "https://cudly.io/mcp/",
"packages": [
{
"registryType": "mcpb",
"identifier": "https://github.com/LeanerCloud/CUDly/releases/download/v0.1.0/cudly-mcp-full.mcpb",
"fileSha256": "0000000000000000000000000000000000000000000000000000000000000000",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"transport": {
"type": "stdio"
},
"environmentVariables": [
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{
"name": "CUDLY_MCP_ENABLE_REAL_PURCHASES",
"description": "Set to 1 (or true) to let purchase tools execute real, money-spending purchases. Unset (the default) refuses every dry_run=false call before any provider or credential is touched -- see mcp/README.md 'Safety model'.",
"isRequired": false,
"isSecret": false,
"format": "string"
}
]
}
]
}
Loading