diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index a2b8bd1a..d0f29b01 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -42,7 +42,7 @@ jobs: - name: Set Secrets uses: DevCycleHQ/aws-secrets-action@main with: - secrets_map: '{"CLI_NPMJS_TOKEN": "DEVCYCLE_GITHUB_CLI_NPM_TOKEN"}' + secrets_map: '{"CLI_NPMJS_TOKEN": "DEVCYCLE_GITHUB_CLI_NPM_TOKEN", "MCP_KEY": "DEVCYCLE_GITHUB_MCP_REGISTRY_PKEY"}' aws_account_id: '134377926370' - name: Set Git author run: | @@ -72,6 +72,13 @@ jobs: - name: Bump CLI version run: npm version ${{ inputs.npm-version }} --force + - name: Update server.json version (pre-commit) + run: | + VERSION=$(node -p "require('./package.json').version") + jq --arg v "$VERSION" '.version = $v' server.json > server.json.tmp + mv server.json.tmp server.json + git add server.json + - name: Get latest tag run: echo "LATEST_TAG=$(git describe --abbrev=0 --tags)" >> $GITHUB_ENV @@ -92,6 +99,29 @@ jobs: prerelease: ${{ inputs.prerelease }} node-auth-token: ${{ env.CLI_NPMJS_TOKEN }} + # --- Official MCP Registry (registry.modelcontextprotocol.io) Publish --- + - name: Install MCP Publisher (registry.modelcontextprotocol.io) + run: | + curl -L "https://github.com/modelcontextprotocol/registry/releases/download/v1.0.0/mcp-publisher_1.0.0_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher + chmod +x mcp-publisher + + - name: Sync server.json version to tag + run: | + VERSION=${LATEST_TAG#v} + jq --arg v "$VERSION" '.version = $v' server.json > server.json.tmp + mv server.json.tmp server.json + + - name: Validate server.json schema + run: yarn validate:server + + - name: Login to MCP Registry (DNS) + run: ./mcp-publisher login dns --domain devcycle.com --private-key "${MCP_KEY}" + env: + MCP_KEY: ${{ env.MCP_KEY }} + + - name: Publish to MCP Registry + run: ./mcp-publisher publish + - name: Update Doc uses: ./.github/actions/update-doc with: diff --git a/.gitignore b/.gitignore index 63b4edea..2afb3596 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +# MCP validation schema cache +.schema/ .DS_Store .idea .devcycle diff --git a/mcp-worker/README.md b/mcp-worker/README.md index 41595b59..9d583e50 100644 --- a/mcp-worker/README.md +++ b/mcp-worker/README.md @@ -115,7 +115,7 @@ All DevCycle CLI MCP tools are available. See [complete reference](../docs/mcp.m **Project**: `select_project`, `list_projects`, `get_current_project` -**Features**: `list_features`, `create_feature`, `update_feature`, `update_feature_status`, `delete_feature`, `fetch_feature_variations`, `create_feature_variation`, `update_feature_variation` +**Features**: `list_features`, `create_feature`, `update_feature`, `update_feature_status`, `delete_feature` **Targeting**: `set_feature_targeting`, `list_feature_targeting`, `update_feature_targeting` diff --git a/package.json b/package.json index 144ca35f..ab8881e4 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ }, "homepage": "https://github.com/DevCycleHQ/cli", "license": "MIT", + "mcpName": "io.github.DevCycleHQ/devcycle-mcp", "main": "dist/index.js", "repository": "DevCycleHQ/cli", "files": [ @@ -34,6 +35,7 @@ "pretest": "yarn format:check", "test": "mocha -r ts-node/register test/*.ts \"src/**/*.test.ts\" && yarn workspace @devcycle/mcp-worker test", "test:ci": "mocha --forbid-only -r ts-node/register test/*.ts \"src/**/*.test.ts\" && yarn workspace @devcycle/mcp-worker test", + "validate:server": "mkdir -p .schema && curl -sSf https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json -o .schema/server.schema.json && ajv validate -c ajv-formats --spec=draft7 --strict=false -s .schema/server.schema.json -d server.json", "test:update-snapshots": "UPDATE_SNAPSHOT=1 yarn test", "version": "oclif readme --multi && git add README.md" }, @@ -84,6 +86,9 @@ "@types/node": "^18.19.68", "@typescript-eslint/eslint-plugin": "^8.21.0", "@typescript-eslint/parser": "^8.21.0", + "ajv": "^8.17.1", + "ajv-cli": "^5.0.0", + "ajv-formats": "^3.0.1", "chai": "^5.1.2", "eslint": "^9.18.0", "eslint-config-prettier": "^9.1.0", diff --git a/server.json b/server.json new file mode 100644 index 00000000..2bc33944 --- /dev/null +++ b/server.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json", + "name": "com.devcycle/mcp", + "description": "DevCycle MCP server for feature flag management", + "version": "6.0.2", + "repository": { + "url": "https://github.com/DevCycleHQ/cli", + "source": "github" + }, + "website_url": "https://docs.devcycle.com/cli-mcp/mcp-getting-started", + "remotes": [ + { "type": "streamable-http", "url": "https://mcp.devcycle.com/mcp" }, + { "type": "sse", "url": "https://mcp.devcycle.com/sse" } + ] +} diff --git a/yarn.lock b/yarn.lock index 9135eb0b..605f7ade 100644 --- a/yarn.lock +++ b/yarn.lock @@ -771,6 +771,9 @@ __metadata: "@typescript-eslint/eslint-plugin": "npm:^8.21.0" "@typescript-eslint/parser": "npm:^8.21.0" "@zodios/core": "npm:^10.9.6" + ajv: "npm:^8.17.1" + ajv-cli: "npm:^5.0.0" + ajv-formats: "npm:^3.0.1" axios: "npm:^1.10.0" chai: "npm:^5.1.2" chalk: "npm:^4.1.2" @@ -3351,6 +3354,28 @@ __metadata: languageName: node linkType: hard +"ajv-cli@npm:^5.0.0": + version: 5.0.0 + resolution: "ajv-cli@npm:5.0.0" + dependencies: + ajv: "npm:^8.0.0" + fast-json-patch: "npm:^2.0.0" + glob: "npm:^7.1.0" + js-yaml: "npm:^3.14.0" + json-schema-migrate: "npm:^2.0.0" + json5: "npm:^2.1.3" + minimist: "npm:^1.2.0" + peerDependencies: + ts-node: ">=9.0.0" + peerDependenciesMeta: + ts-node: + optional: true + bin: + ajv: dist/index.js + checksum: 10c0/91c70cb3997fefdb32157b20278643d9ccf6e4897a6b8babf42d6bdb55cb1b7df31524bd5589bf897be14378893b4cf21c366ba313708c3d618e0e976292d7f1 + languageName: node + linkType: hard + "ajv-draft-04@npm:^1.0.0": version: 1.0.0 resolution: "ajv-draft-04@npm:1.0.0" @@ -3363,6 +3388,20 @@ __metadata: languageName: node linkType: hard +"ajv-formats@npm:^3.0.1": + version: 3.0.1 + resolution: "ajv-formats@npm:3.0.1" + dependencies: + ajv: "npm:^8.0.0" + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 10c0/168d6bca1ea9f163b41c8147bae537e67bd963357a5488a1eaf3abe8baa8eec806d4e45f15b10767e6020679315c7e1e5e6803088dfb84efa2b4e9353b83dd0a + languageName: node + linkType: hard + "ajv@npm:^6.12.4, ajv@npm:^6.12.6": version: 6.12.6 resolution: "ajv@npm:6.12.6" @@ -3375,6 +3414,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^8.0.0, ajv@npm:^8.17.1": + version: 8.17.1 + resolution: "ajv@npm:8.17.1" + dependencies: + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + checksum: 10c0/ec3ba10a573c6b60f94639ffc53526275917a2df6810e4ab5a6b959d87459f9ef3f00d5e7865b82677cb7d21590355b34da14d1d0b9c32d75f95a187e76fff35 + languageName: node + linkType: hard + "ajv@npm:^8.6.3": version: 8.12.0 resolution: "ajv@npm:8.12.0" @@ -5503,6 +5554,13 @@ __metadata: languageName: node linkType: hard +"fast-deep-equal@npm:^2.0.1": + version: 2.0.1 + resolution: "fast-deep-equal@npm:2.0.1" + checksum: 10c0/1602e0d6ed63493c865cc6b03f9070d6d3926e8cd086a123060b58f80a295f3f08b1ecfb479ae7c45b7fd45535202aea7cf5b49bc31bffb81c20b1502300be84 + languageName: node + linkType: hard + "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -5536,6 +5594,15 @@ __metadata: languageName: node linkType: hard +"fast-json-patch@npm:^2.0.0": + version: 2.2.1 + resolution: "fast-json-patch@npm:2.2.1" + dependencies: + fast-deep-equal: "npm:^2.0.1" + checksum: 10c0/3200148b8244081ac628e8044a3ba6c42bbe26542d1586b0e87221bff8d5ef58252a2dd846a709ff4683cf826e89123025c2708729933dde859430a40f0d321e + languageName: node + linkType: hard + "fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" @@ -5559,6 +5626,13 @@ __metadata: languageName: node linkType: hard +"fast-uri@npm:^3.0.1": + version: 3.1.0 + resolution: "fast-uri@npm:3.1.0" + checksum: 10c0/44364adca566f70f40d1e9b772c923138d47efeac2ae9732a872baafd77061f26b097ba2f68f0892885ad177becd065520412b8ffeec34b16c99433c5b9e2de7 + languageName: node + linkType: hard + "fastest-levenshtein@npm:^1.0.7": version: 1.0.16 resolution: "fastest-levenshtein@npm:1.0.16" @@ -6046,7 +6120,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.0, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": +"glob@npm:^7.0.0, glob@npm:^7.1.0, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -7034,7 +7108,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^3.13.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.1": +"js-yaml@npm:^3.13.0, js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.0, js-yaml@npm:^3.14.1": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" dependencies: @@ -7101,6 +7175,15 @@ __metadata: languageName: node linkType: hard +"json-schema-migrate@npm:^2.0.0": + version: 2.0.0 + resolution: "json-schema-migrate@npm:2.0.0" + dependencies: + ajv: "npm:^8.0.0" + checksum: 10c0/9d14970cd1cab496b0a5dc52c3a69a0346dc2bd4ce3135a3561739eddb46cb7696dc815ff9ddcd015c4c4532b56495a1ec5db4b141b77e6d2c9c7b492cd02c6a + languageName: node + linkType: hard + "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -7143,7 +7226,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.2.3": +"json5@npm:^2.1.3, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -7749,7 +7832,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.3, minimist@npm:^1.2.5": +"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6