From 6ee7627ee975f5d566aac7713e2791756fb86096 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 3 Apr 2025 14:17:19 +1100 Subject: [PATCH 01/14] Initial work for adding a Dockerfile and creating an image for inspector Fixes #237 --- .dockerignore | 35 +++++++++++++++++++++++++++++++++++ Dockerfile | 26 ++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..a3e960e3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,35 @@ +# Version control +.git +.gitignore + +# Node.js +node_modules +npm-debug.log + +# Build artifacts +client/dist +client/build +server/dist +server/build + +# Environment variables +.env +.env.local +.env.development +.env.test +.env.production + +# Editor files +.vscode +.idea + +# Logs +logs +*.log + +# Testing +coverage + +# Docker +Dockerfile +.dockerignore \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..2d318a33 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM node:22-slim + +# Set working directory +WORKDIR /app + +# Copy files +COPY . . + +# Install dependencies +# Working around https://github.com/npm/cli/issues/4828 +# RUN npm ci +RUN npm install --no-package-lock + +# Build the application +RUN npm run build + +ENV CLIENT_PORT=6274 +ENV SERVER_PORT=6277 + +# Expose the CLIENT_PORT and SERVER_PORT +EXPOSE $CLIENT_PORT +EXPOSE $SERVER_PORT + +# Use ENTRYPOINT with CMD for arguments +ENTRYPOINT ["npm", "start"] +CMD [] \ No newline at end of file From 6d561a0e0df804dfcf2b5b5c2c3909675846f5e4 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Tue, 8 Apr 2025 11:45:39 +1000 Subject: [PATCH 02/14] Updating workflow to publish to GitHub Container Registry Using guide from https://docs.github.com/en/actions/use-cases-and-examples/publishing-packages/publishing-docker-images --- .github/workflows/main.yml | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1f134440..ad23a17a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -58,3 +58,43 @@ jobs: - run: npm run publish-all env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + publish-github-container-registry: + runs-on: ubuntu-latest + if: github.event_name == 'release' + environment: release + needs: build + permissions: + contents: write + id-token: write + steps: + - uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + + - name: Build and push Docker image + id: push + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v2 + with: + subject-name: ghcr.io/${{ github.repository }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true \ No newline at end of file From ad8d0579c4286c473c8c2a51edd2766f694d20be Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 24 Apr 2025 15:12:19 +1000 Subject: [PATCH 03/14] Fixing prettier error --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d3a31bed..769f4197 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -99,4 +99,4 @@ jobs: with: subject-name: ghcr.io/${{ github.repository }} subject-digest: ${{ steps.push.outputs.digest }} - push-to-registry: true \ No newline at end of file + push-to-registry: true From 890f6fdba2b83aa5e49d0d6a91e4ff77b6f88d38 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 24 Apr 2025 15:28:30 +1000 Subject: [PATCH 04/14] Dockerfile (#1) * Initial work for adding a Dockerfile and creating an image for inspector Fixes #237 * Updating workflow to publish to GitHub Container Registry Using guide from https://docs.github.com/en/actions/use-cases-and-examples/publishing-packages/publishing-docker-images --- .dockerignore | 35 +++++++++++++++++++++++++++++++++ .github/workflows/main.yml | 40 ++++++++++++++++++++++++++++++++++++++ Dockerfile | 26 +++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..a3e960e3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,35 @@ +# Version control +.git +.gitignore + +# Node.js +node_modules +npm-debug.log + +# Build artifacts +client/dist +client/build +server/dist +server/build + +# Environment variables +.env +.env.local +.env.development +.env.test +.env.production + +# Editor files +.vscode +.idea + +# Logs +logs +*.log + +# Testing +coverage + +# Docker +Dockerfile +.dockerignore \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9621e313..d3a31bed 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -60,3 +60,43 @@ jobs: - run: npm run publish-all env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + publish-github-container-registry: + runs-on: ubuntu-latest + if: github.event_name == 'release' + environment: release + needs: build + permissions: + contents: write + id-token: write + steps: + - uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + + - name: Build and push Docker image + id: push + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@v2 + with: + subject-name: ghcr.io/${{ github.repository }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..2d318a33 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM node:22-slim + +# Set working directory +WORKDIR /app + +# Copy files +COPY . . + +# Install dependencies +# Working around https://github.com/npm/cli/issues/4828 +# RUN npm ci +RUN npm install --no-package-lock + +# Build the application +RUN npm run build + +ENV CLIENT_PORT=6274 +ENV SERVER_PORT=6277 + +# Expose the CLIENT_PORT and SERVER_PORT +EXPOSE $CLIENT_PORT +EXPOSE $SERVER_PORT + +# Use ENTRYPOINT with CMD for arguments +ENTRYPOINT ["npm", "start"] +CMD [] \ No newline at end of file From 9e186e3b1b76427fbf1d4b09cec450957f0c0a46 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 24 Apr 2025 15:31:37 +1000 Subject: [PATCH 05/14] ci fix (#2) --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d3a31bed..769f4197 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -99,4 +99,4 @@ jobs: with: subject-name: ghcr.io/${{ github.repository }} subject-digest: ${{ steps.push.outputs.digest }} - push-to-registry: true \ No newline at end of file + push-to-registry: true From b0031d0b6f705e465b196da89567a6572af78778 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 24 Apr 2025 15:41:40 +1000 Subject: [PATCH 06/14] Fixing permissions (#3) --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 769f4197..3c9e08dc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -67,7 +67,9 @@ jobs: environment: release needs: build permissions: - contents: write + contents: read + packages: write + attestations: write id-token: write steps: - uses: actions/checkout@v4 From 243fd1494e672df968321fe4f3bdf33185e37991 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 24 Apr 2025 15:46:22 +1000 Subject: [PATCH 07/14] Fixing permissions --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 769f4197..3c9e08dc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -67,7 +67,9 @@ jobs: environment: release needs: build permissions: - contents: write + contents: read + packages: write + attestations: write id-token: write steps: - uses: actions/checkout@v4 From ef6d84933aa686e236341cf03d007749ac5ba85a Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 2 Jun 2025 13:49:38 +1000 Subject: [PATCH 08/14] Apply suggestions from code review Co-authored-by: John McBride --- .github/workflows/main.yml | 1 + Dockerfile | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b68890f3..45f2c680 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -95,6 +95,7 @@ jobs: with: context: . push: true + platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index 2d318a33..f5c491d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,12 +14,10 @@ RUN npm install --no-package-lock # Build the application RUN npm run build -ENV CLIENT_PORT=6274 -ENV SERVER_PORT=6277 +ARG CLIENT_PORT=6274 +ARG SERVER_PORT=6277 -# Expose the CLIENT_PORT and SERVER_PORT -EXPOSE $CLIENT_PORT -EXPOSE $SERVER_PORT +EXPOSE ${CLIENT_PORT} ${SERVER_PORT} # Use ENTRYPOINT with CMD for arguments ENTRYPOINT ["npm", "start"] From 769d045c16ea3fbf89cff3baef975dbdc614f2f8 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 4 Jun 2025 12:18:43 +1000 Subject: [PATCH 09/14] Converting to multi-stage dockerfile --- Dockerfile | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index f5c491d4..5d7724d0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,48 @@ -FROM node:22-slim +# Build stage +FROM node:24-slim AS builder # Set working directory WORKDIR /app -# Copy files -COPY . . +# Copy package files for installation +COPY package*.json ./ +COPY .npmrc ./ +COPY client/package*.json ./client/ +COPY server/package*.json ./server/ +COPY cli/package*.json ./cli/ # Install dependencies -# Working around https://github.com/npm/cli/issues/4828 -# RUN npm ci -RUN npm install --no-package-lock +RUN npm ci --ignore-scripts + +# Copy source files +COPY . . # Build the application RUN npm run build -ARG CLIENT_PORT=6274 -ARG SERVER_PORT=6277 +# Production stage +FROM node:24-slim -EXPOSE ${CLIENT_PORT} ${SERVER_PORT} +WORKDIR /app + +# Copy package files for production +COPY package*.json ./ +COPY .npmrc ./ +COPY client/package*.json ./client/ +COPY server/package*.json ./server/ +COPY cli/package*.json ./cli/ + +# Install only production dependencies +RUN npm ci --omit=dev --ignore-scripts + +# Copy built files from builder stage +COPY --from=builder /app/client/dist ./client/dist +COPY --from=builder /app/client/bin ./client/bin +COPY --from=builder /app/server/build ./server/build +COPY --from=builder /app/cli/build ./cli/build + +# Document which ports the application uses internally +EXPOSE 6274 6277 # Use ENTRYPOINT with CMD for arguments -ENTRYPOINT ["npm", "start"] -CMD [] \ No newline at end of file +ENTRYPOINT ["npm", "start"] \ No newline at end of file From f73894fbf083c044a861b639976fb2b2c2eadbf4 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 4 Jun 2025 12:30:44 +1000 Subject: [PATCH 10/14] Allowing setting of the ports at the environment variable level so the apps are aware of them --- Dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 5d7724d0..f36fb8bb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,8 +41,12 @@ COPY --from=builder /app/client/bin ./client/bin COPY --from=builder /app/server/build ./server/build COPY --from=builder /app/cli/build ./cli/build +# Set default port values as environment variables +ENV CLIENT_PORT=6274 +ENV SERVER_PORT=6277 + # Document which ports the application uses internally -EXPOSE 6274 6277 +EXPOSE ${CLIENT_PORT} ${SERVER_PORT} # Use ENTRYPOINT with CMD for arguments ENTRYPOINT ["npm", "start"] \ No newline at end of file From 37bd103cdbbf24c91a9257a8f3ad7ff69d2d2634 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 5 Jun 2025 10:30:09 +1000 Subject: [PATCH 11/14] Support for multi-platform builds --- .github/workflows/main.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 45f2c680..dd0b5e40 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -89,6 +89,12 @@ jobs: with: images: ghcr.io/${{ github.repository }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build and push Docker image id: push uses: docker/build-push-action@v6 From b70cf563a867efc4c9fa376aa02e991ce4360867 Mon Sep 17 00:00:00 2001 From: Jerome Date: Sat, 14 Jun 2025 19:52:36 +0100 Subject: [PATCH 12/14] feat: add version management scripts and CI check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added update-version.js script to automate version bumps across all packages - Added check-version-consistency.js script to verify version consistency - Integrated version check into CI workflow - Scripts check package.json versions AND package-lock.json sync - Added npm scripts: `npm run update-version` and `npm run check-version` - Added documentation in scripts/README.md This ensures version consistency across the monorepo and prevents accidental version mismatches or outdated lock files. šŸ¤– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/main.yml | 3 + package.json | 4 +- scripts/README.md | 66 +++++++++++ scripts/check-version-consistency.js | 169 +++++++++++++++++++++++++++ scripts/update-version.js | 96 +++++++++++++++ 5 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 scripts/README.md create mode 100755 scripts/check-version-consistency.js create mode 100755 scripts/update-version.js diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8efb6773..fa430b79 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,6 +26,9 @@ jobs: # - run: npm ci - run: npm install --no-package-lock + - name: Check version consistency + run: npm run check-version + - name: Check linting working-directory: ./client run: npm run lint diff --git a/package.json b/package.json index 69bbfaaf..656a511f 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,9 @@ "prettier-check": "prettier --check .", "lint": "prettier --check . && cd client && npm run lint", "prepare": "npm run build", - "publish-all": "npm publish --workspaces --access public && npm publish --access public" + "publish-all": "npm publish --workspaces --access public && npm publish --access public", + "update-version": "node scripts/update-version.js", + "check-version": "node scripts/check-version-consistency.js" }, "dependencies": { "@modelcontextprotocol/inspector-cli": "^0.14.1", diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 00000000..5f4cf6f5 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,66 @@ +# Version Management Scripts + +This directory contains scripts for managing version consistency across the monorepo. + +## Scripts + +### update-version.js + +Updates the version across all package.json files in the monorepo and updates package-lock.json. + +**Usage:** +```bash +npm run update-version +# Example: +npm run update-version 0.14.3 +``` + +This script will: +1. Update the version in all package.json files (root, client, server, cli) +2. Update workspace dependencies in the root package.json +3. Run `npm install` to update package-lock.json +4. Provide next steps for committing and tagging + +### check-version-consistency.js + +Checks that all packages have consistent versions and that package-lock.json is up to date. + +**Usage:** +```bash +npm run check-version +``` + +This script checks: +1. All package.json files have the same version +2. Workspace dependencies in root package.json match the current version +3. package-lock.json version matches package.json +4. Workspace packages in package-lock.json have the correct versions + +This check runs automatically in CI on every PR and push to main. + +## CI Integration + +The version consistency check is integrated into the GitHub Actions workflow (`.github/workflows/main.yml`) and will fail the build if: +- Package versions are inconsistent +- package-lock.json is out of sync + +## Common Workflows + +### Bumping version for a release: +```bash +# Update to new version +npm run update-version 0.15.0 + +# Verify everything is correct +npm run check-version + +# Commit the changes +git add -A +git commit -m "chore: bump version to 0.15.0" + +# Create a tag +git tag 0.15.0 + +# Push changes and tag +git push && git push --tags +``` \ No newline at end of file diff --git a/scripts/check-version-consistency.js b/scripts/check-version-consistency.js new file mode 100755 index 00000000..72fa15f2 --- /dev/null +++ b/scripts/check-version-consistency.js @@ -0,0 +1,169 @@ +#!/usr/bin/env node + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +/** + * Checks version consistency across all package.json files in the monorepo + * Exits with code 1 if versions are inconsistent + * Usage: node scripts/check-version-consistency.js + */ + +console.log('šŸ” Checking version consistency across packages...\n'); + +// List of package.json files to check +const packagePaths = [ + 'package.json', + 'client/package.json', + 'server/package.json', + 'cli/package.json' +]; + +const versions = new Map(); +const errors = []; + +// Read version from each package.json +packagePaths.forEach(packagePath => { + const fullPath = path.join(__dirname, '..', packagePath); + + if (!fs.existsSync(fullPath)) { + console.warn(`āš ļø Skipping ${packagePath} - file not found`); + return; + } + + try { + const packageJson = JSON.parse(fs.readFileSync(fullPath, 'utf8')); + const version = packageJson.version; + const packageName = packageJson.name || packagePath; + + versions.set(packagePath, { + name: packageName, + version: version, + dependencies: packageJson.dependencies || {} + }); + + console.log(`šŸ“¦ ${packagePath}:`); + console.log(` Name: ${packageName}`); + console.log(` Version: ${version}`); + } catch (error) { + errors.push(`Failed to read ${packagePath}: ${error.message}`); + } +}); + +if (errors.length > 0) { + console.error('\nāŒ Errors occurred while reading package files:'); + errors.forEach(error => console.error(` - ${error}`)); + process.exit(1); +} + +// Check if all versions match +const allVersions = Array.from(versions.values()).map(v => v.version); +const uniqueVersions = [...new Set(allVersions)]; + +console.log('\nšŸ“Š Version Summary:'); +console.log(` Total packages: ${versions.size}`); +console.log(` Unique versions: ${uniqueVersions.length}`); + +if (uniqueVersions.length > 1) { + console.error('\nāŒ Version mismatch detected!'); + console.error(' Found versions: ' + uniqueVersions.join(', ')); + + console.error('\n Package versions:'); + versions.forEach((info, path) => { + console.error(` - ${path}: ${info.version}`); + }); +} else { + console.log(` āœ… All packages are at version: ${uniqueVersions[0]}`); +} + +// Check workspace dependencies in root package.json +const rootPackage = versions.get('package.json'); +if (rootPackage) { + console.log('\nšŸ”— Checking workspace dependencies...'); + const expectedVersion = rootPackage.version; + let dependencyErrors = false; + + Object.entries(rootPackage.dependencies).forEach(([dep, version]) => { + if (dep.startsWith('@modelcontextprotocol/inspector-')) { + const expectedDepVersion = `^${expectedVersion}`; + if (version !== expectedDepVersion) { + console.error(` āŒ ${dep}: ${version} (expected ${expectedDepVersion})`); + dependencyErrors = true; + } else { + console.log(` āœ… ${dep}: ${version}`); + } + } + }); + + if (dependencyErrors) { + errors.push('Workspace dependency versions do not match package versions'); + } +} + +// Check if package-lock.json is up to date +console.log('\nšŸ”’ Checking package-lock.json...'); +const lockPath = path.join(__dirname, '..', 'package-lock.json'); +let lockFileError = false; + +if (!fs.existsSync(lockPath)) { + console.error(' āŒ package-lock.json not found'); + lockFileError = true; +} else { + try { + const lockFile = JSON.parse(fs.readFileSync(lockPath, 'utf8')); + const lockVersion = lockFile.version; + const expectedVersion = rootPackage?.version || uniqueVersions[0]; + + if (lockVersion !== expectedVersion) { + console.error(` āŒ package-lock.json version (${lockVersion}) does not match package.json version (${expectedVersion})`); + lockFileError = true; + } else { + console.log(` āœ… package-lock.json version matches: ${lockVersion}`); + } + + // Check workspace package versions in lock file + if (lockFile.packages) { + const workspacePackages = [ + { path: 'client', name: '@modelcontextprotocol/inspector-client' }, + { path: 'server', name: '@modelcontextprotocol/inspector-server' }, + { path: 'cli', name: '@modelcontextprotocol/inspector-cli' } + ]; + + workspacePackages.forEach(({ path, name }) => { + const lockPkgPath = lockFile.packages[path]; + if (lockPkgPath && lockPkgPath.version !== expectedVersion) { + console.error(` āŒ ${name} in lock file: ${lockPkgPath.version} (expected ${expectedVersion})`); + lockFileError = true; + } + }); + } + } catch (error) { + console.error(` āŒ Failed to parse package-lock.json: ${error.message}`); + lockFileError = true; + } +} + +// Final result +console.log('\nšŸŽÆ Result:'); +if (uniqueVersions.length === 1 && errors.length === 0 && !lockFileError) { + console.log(' āœ… Version consistency check passed!'); + process.exit(0); +} else { + console.error(' āŒ Version consistency check failed!'); + if (uniqueVersions.length > 1) { + console.error(' - Package versions are not consistent'); + } + if (errors.length > 0) { + console.error(' - ' + errors.join('\n - ')); + } + if (lockFileError) { + console.error(' - package-lock.json is out of sync'); + } + console.error('\nšŸ’” Run "npm run update-version " to fix version inconsistencies'); + console.error(' or run "npm install" to update package-lock.json'); + process.exit(1); +} \ No newline at end of file diff --git a/scripts/update-version.js b/scripts/update-version.js new file mode 100755 index 00000000..7f82b936 --- /dev/null +++ b/scripts/update-version.js @@ -0,0 +1,96 @@ +#!/usr/bin/env node + +import fs from 'fs'; +import path from 'path'; +import { execSync } from 'child_process'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +/** + * Updates version across all package.json files in the monorepo + * Usage: node scripts/update-version.js + * Example: node scripts/update-version.js 0.14.2 + */ + +const newVersion = process.argv[2]; + +if (!newVersion) { + console.error('āŒ Please provide a version number'); + console.error('Usage: node scripts/update-version.js '); + console.error('Example: node scripts/update-version.js 0.14.2'); + process.exit(1); +} + +// Validate version format +const versionRegex = /^\d+\.\d+\.\d+(-[\w.]+)?$/; +if (!versionRegex.test(newVersion)) { + console.error('āŒ Invalid version format. Please use semantic versioning (e.g., 1.2.3 or 1.2.3-beta.1)'); + process.exit(1); +} + +console.log(`šŸ”„ Updating all packages to version ${newVersion}...`); + +// List of package.json files to update +const packagePaths = [ + 'package.json', + 'client/package.json', + 'server/package.json', + 'cli/package.json' +]; + +const updatedFiles = []; + +// Update version in each package.json +packagePaths.forEach(packagePath => { + const fullPath = path.join(__dirname, '..', packagePath); + + if (!fs.existsSync(fullPath)) { + console.warn(`āš ļø Skipping ${packagePath} - file not found`); + return; + } + + try { + const packageJson = JSON.parse(fs.readFileSync(fullPath, 'utf8')); + const oldVersion = packageJson.version; + packageJson.version = newVersion; + + // Update workspace dependencies in root package.json + if (packagePath === 'package.json' && packageJson.dependencies) { + Object.keys(packageJson.dependencies).forEach(dep => { + if (dep.startsWith('@modelcontextprotocol/inspector-')) { + packageJson.dependencies[dep] = `^${newVersion}`; + } + }); + } + + fs.writeFileSync(fullPath, JSON.stringify(packageJson, null, 2) + '\n'); + updatedFiles.push(packagePath); + console.log(`āœ… Updated ${packagePath} from ${oldVersion} to ${newVersion}`); + } catch (error) { + console.error(`āŒ Failed to update ${packagePath}:`, error.message); + process.exit(1); + } +}); + +console.log('\nšŸ“ Summary:'); +console.log(`Updated ${updatedFiles.length} files to version ${newVersion}`); + +// Update package-lock.json +console.log('\nšŸ”’ Updating package-lock.json...'); +try { + execSync('npm install', { stdio: 'inherit' }); + console.log('āœ… package-lock.json updated successfully'); +} catch (error) { + console.error('āŒ Failed to update package-lock.json:', error.message); + console.error('Please run "npm install" manually'); + process.exit(1); +} + +console.log('\n✨ Version update complete!'); +console.log('\nNext steps:'); +console.log('1. Review the changes: git diff'); +console.log('2. Commit the changes: git add -A && git commit -m "chore: bump version to ' + newVersion + '"'); +console.log('3. Create a git tag: git tag v' + newVersion); +console.log('4. Push changes and tag: git push && git push --tags'); \ No newline at end of file From a30a3fbe8df5e748c5b279fc473620c5cafda418 Mon Sep 17 00:00:00 2001 From: Jerome Date: Sat, 14 Jun 2025 19:56:58 +0100 Subject: [PATCH 13/14] Lint --- scripts/README.md | 8 +- scripts/check-version-consistency.js | 108 ++++++++++++++------------- scripts/update-version.js | 76 ++++++++++--------- 3 files changed, 107 insertions(+), 85 deletions(-) diff --git a/scripts/README.md b/scripts/README.md index 5f4cf6f5..d6887faf 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -9,6 +9,7 @@ This directory contains scripts for managing version consistency across the mono Updates the version across all package.json files in the monorepo and updates package-lock.json. **Usage:** + ```bash npm run update-version # Example: @@ -16,6 +17,7 @@ npm run update-version 0.14.3 ``` This script will: + 1. Update the version in all package.json files (root, client, server, cli) 2. Update workspace dependencies in the root package.json 3. Run `npm install` to update package-lock.json @@ -26,11 +28,13 @@ This script will: Checks that all packages have consistent versions and that package-lock.json is up to date. **Usage:** + ```bash npm run check-version ``` This script checks: + 1. All package.json files have the same version 2. Workspace dependencies in root package.json match the current version 3. package-lock.json version matches package.json @@ -41,12 +45,14 @@ This check runs automatically in CI on every PR and push to main. ## CI Integration The version consistency check is integrated into the GitHub Actions workflow (`.github/workflows/main.yml`) and will fail the build if: + - Package versions are inconsistent - package-lock.json is out of sync ## Common Workflows ### Bumping version for a release: + ```bash # Update to new version npm run update-version 0.15.0 @@ -63,4 +69,4 @@ git tag 0.15.0 # Push changes and tag git push && git push --tags -``` \ No newline at end of file +``` diff --git a/scripts/check-version-consistency.js b/scripts/check-version-consistency.js index 72fa15f2..379931de 100755 --- a/scripts/check-version-consistency.js +++ b/scripts/check-version-consistency.js @@ -1,8 +1,8 @@ #!/usr/bin/env node -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -13,39 +13,39 @@ const __dirname = path.dirname(__filename); * Usage: node scripts/check-version-consistency.js */ -console.log('šŸ” Checking version consistency across packages...\n'); +console.log("šŸ” Checking version consistency across packages...\n"); // List of package.json files to check const packagePaths = [ - 'package.json', - 'client/package.json', - 'server/package.json', - 'cli/package.json' + "package.json", + "client/package.json", + "server/package.json", + "cli/package.json", ]; const versions = new Map(); const errors = []; // Read version from each package.json -packagePaths.forEach(packagePath => { - const fullPath = path.join(__dirname, '..', packagePath); - +packagePaths.forEach((packagePath) => { + const fullPath = path.join(__dirname, "..", packagePath); + if (!fs.existsSync(fullPath)) { console.warn(`āš ļø Skipping ${packagePath} - file not found`); return; } try { - const packageJson = JSON.parse(fs.readFileSync(fullPath, 'utf8')); + const packageJson = JSON.parse(fs.readFileSync(fullPath, "utf8")); const version = packageJson.version; const packageName = packageJson.name || packagePath; - + versions.set(packagePath, { name: packageName, version: version, - dependencies: packageJson.dependencies || {} + dependencies: packageJson.dependencies || {}, }); - + console.log(`šŸ“¦ ${packagePath}:`); console.log(` Name: ${packageName}`); console.log(` Version: ${version}`); @@ -55,24 +55,24 @@ packagePaths.forEach(packagePath => { }); if (errors.length > 0) { - console.error('\nāŒ Errors occurred while reading package files:'); - errors.forEach(error => console.error(` - ${error}`)); + console.error("\nāŒ Errors occurred while reading package files:"); + errors.forEach((error) => console.error(` - ${error}`)); process.exit(1); } // Check if all versions match -const allVersions = Array.from(versions.values()).map(v => v.version); +const allVersions = Array.from(versions.values()).map((v) => v.version); const uniqueVersions = [...new Set(allVersions)]; -console.log('\nšŸ“Š Version Summary:'); +console.log("\nšŸ“Š Version Summary:"); console.log(` Total packages: ${versions.size}`); console.log(` Unique versions: ${uniqueVersions.length}`); if (uniqueVersions.length > 1) { - console.error('\nāŒ Version mismatch detected!'); - console.error(' Found versions: ' + uniqueVersions.join(', ')); - - console.error('\n Package versions:'); + console.error("\nāŒ Version mismatch detected!"); + console.error(" Found versions: " + uniqueVersions.join(", ")); + + console.error("\n Package versions:"); versions.forEach((info, path) => { console.error(` - ${path}: ${info.version}`); }); @@ -81,62 +81,68 @@ if (uniqueVersions.length > 1) { } // Check workspace dependencies in root package.json -const rootPackage = versions.get('package.json'); +const rootPackage = versions.get("package.json"); if (rootPackage) { - console.log('\nšŸ”— Checking workspace dependencies...'); + console.log("\nšŸ”— Checking workspace dependencies..."); const expectedVersion = rootPackage.version; let dependencyErrors = false; - + Object.entries(rootPackage.dependencies).forEach(([dep, version]) => { - if (dep.startsWith('@modelcontextprotocol/inspector-')) { + if (dep.startsWith("@modelcontextprotocol/inspector-")) { const expectedDepVersion = `^${expectedVersion}`; if (version !== expectedDepVersion) { - console.error(` āŒ ${dep}: ${version} (expected ${expectedDepVersion})`); + console.error( + ` āŒ ${dep}: ${version} (expected ${expectedDepVersion})`, + ); dependencyErrors = true; } else { console.log(` āœ… ${dep}: ${version}`); } } }); - + if (dependencyErrors) { - errors.push('Workspace dependency versions do not match package versions'); + errors.push("Workspace dependency versions do not match package versions"); } } // Check if package-lock.json is up to date -console.log('\nšŸ”’ Checking package-lock.json...'); -const lockPath = path.join(__dirname, '..', 'package-lock.json'); +console.log("\nšŸ”’ Checking package-lock.json..."); +const lockPath = path.join(__dirname, "..", "package-lock.json"); let lockFileError = false; if (!fs.existsSync(lockPath)) { - console.error(' āŒ package-lock.json not found'); + console.error(" āŒ package-lock.json not found"); lockFileError = true; } else { try { - const lockFile = JSON.parse(fs.readFileSync(lockPath, 'utf8')); + const lockFile = JSON.parse(fs.readFileSync(lockPath, "utf8")); const lockVersion = lockFile.version; const expectedVersion = rootPackage?.version || uniqueVersions[0]; - + if (lockVersion !== expectedVersion) { - console.error(` āŒ package-lock.json version (${lockVersion}) does not match package.json version (${expectedVersion})`); + console.error( + ` āŒ package-lock.json version (${lockVersion}) does not match package.json version (${expectedVersion})`, + ); lockFileError = true; } else { console.log(` āœ… package-lock.json version matches: ${lockVersion}`); } - + // Check workspace package versions in lock file if (lockFile.packages) { const workspacePackages = [ - { path: 'client', name: '@modelcontextprotocol/inspector-client' }, - { path: 'server', name: '@modelcontextprotocol/inspector-server' }, - { path: 'cli', name: '@modelcontextprotocol/inspector-cli' } + { path: "client", name: "@modelcontextprotocol/inspector-client" }, + { path: "server", name: "@modelcontextprotocol/inspector-server" }, + { path: "cli", name: "@modelcontextprotocol/inspector-cli" }, ]; - + workspacePackages.forEach(({ path, name }) => { const lockPkgPath = lockFile.packages[path]; if (lockPkgPath && lockPkgPath.version !== expectedVersion) { - console.error(` āŒ ${name} in lock file: ${lockPkgPath.version} (expected ${expectedVersion})`); + console.error( + ` āŒ ${name} in lock file: ${lockPkgPath.version} (expected ${expectedVersion})`, + ); lockFileError = true; } }); @@ -148,22 +154,24 @@ if (!fs.existsSync(lockPath)) { } // Final result -console.log('\nšŸŽÆ Result:'); +console.log("\nšŸŽÆ Result:"); if (uniqueVersions.length === 1 && errors.length === 0 && !lockFileError) { - console.log(' āœ… Version consistency check passed!'); + console.log(" āœ… Version consistency check passed!"); process.exit(0); } else { - console.error(' āŒ Version consistency check failed!'); + console.error(" āŒ Version consistency check failed!"); if (uniqueVersions.length > 1) { - console.error(' - Package versions are not consistent'); + console.error(" - Package versions are not consistent"); } if (errors.length > 0) { - console.error(' - ' + errors.join('\n - ')); + console.error(" - " + errors.join("\n - ")); } if (lockFileError) { - console.error(' - package-lock.json is out of sync'); + console.error(" - package-lock.json is out of sync"); } - console.error('\nšŸ’” Run "npm run update-version " to fix version inconsistencies'); + console.error( + '\nšŸ’” Run "npm run update-version " to fix version inconsistencies', + ); console.error(' or run "npm install" to update package-lock.json'); process.exit(1); -} \ No newline at end of file +} diff --git a/scripts/update-version.js b/scripts/update-version.js index 7f82b936..91b69f3b 100755 --- a/scripts/update-version.js +++ b/scripts/update-version.js @@ -1,9 +1,9 @@ #!/usr/bin/env node -import fs from 'fs'; -import path from 'path'; -import { execSync } from 'child_process'; -import { fileURLToPath } from 'url'; +import fs from "fs"; +import path from "path"; +import { execSync } from "child_process"; +import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -17,16 +17,18 @@ const __dirname = path.dirname(__filename); const newVersion = process.argv[2]; if (!newVersion) { - console.error('āŒ Please provide a version number'); - console.error('Usage: node scripts/update-version.js '); - console.error('Example: node scripts/update-version.js 0.14.2'); + console.error("āŒ Please provide a version number"); + console.error("Usage: node scripts/update-version.js "); + console.error("Example: node scripts/update-version.js 0.14.2"); process.exit(1); } // Validate version format const versionRegex = /^\d+\.\d+\.\d+(-[\w.]+)?$/; if (!versionRegex.test(newVersion)) { - console.error('āŒ Invalid version format. Please use semantic versioning (e.g., 1.2.3 or 1.2.3-beta.1)'); + console.error( + "āŒ Invalid version format. Please use semantic versioning (e.g., 1.2.3 or 1.2.3-beta.1)", + ); process.exit(1); } @@ -34,63 +36,69 @@ console.log(`šŸ”„ Updating all packages to version ${newVersion}...`); // List of package.json files to update const packagePaths = [ - 'package.json', - 'client/package.json', - 'server/package.json', - 'cli/package.json' + "package.json", + "client/package.json", + "server/package.json", + "cli/package.json", ]; const updatedFiles = []; // Update version in each package.json -packagePaths.forEach(packagePath => { - const fullPath = path.join(__dirname, '..', packagePath); - +packagePaths.forEach((packagePath) => { + const fullPath = path.join(__dirname, "..", packagePath); + if (!fs.existsSync(fullPath)) { console.warn(`āš ļø Skipping ${packagePath} - file not found`); return; } try { - const packageJson = JSON.parse(fs.readFileSync(fullPath, 'utf8')); + const packageJson = JSON.parse(fs.readFileSync(fullPath, "utf8")); const oldVersion = packageJson.version; packageJson.version = newVersion; - + // Update workspace dependencies in root package.json - if (packagePath === 'package.json' && packageJson.dependencies) { - Object.keys(packageJson.dependencies).forEach(dep => { - if (dep.startsWith('@modelcontextprotocol/inspector-')) { + if (packagePath === "package.json" && packageJson.dependencies) { + Object.keys(packageJson.dependencies).forEach((dep) => { + if (dep.startsWith("@modelcontextprotocol/inspector-")) { packageJson.dependencies[dep] = `^${newVersion}`; } }); } - - fs.writeFileSync(fullPath, JSON.stringify(packageJson, null, 2) + '\n'); + + fs.writeFileSync(fullPath, JSON.stringify(packageJson, null, 2) + "\n"); updatedFiles.push(packagePath); - console.log(`āœ… Updated ${packagePath} from ${oldVersion} to ${newVersion}`); + console.log( + `āœ… Updated ${packagePath} from ${oldVersion} to ${newVersion}`, + ); } catch (error) { console.error(`āŒ Failed to update ${packagePath}:`, error.message); process.exit(1); } }); -console.log('\nšŸ“ Summary:'); +console.log("\nšŸ“ Summary:"); console.log(`Updated ${updatedFiles.length} files to version ${newVersion}`); // Update package-lock.json -console.log('\nšŸ”’ Updating package-lock.json...'); +console.log("\nšŸ”’ Updating package-lock.json..."); try { - execSync('npm install', { stdio: 'inherit' }); - console.log('āœ… package-lock.json updated successfully'); + execSync("npm install", { stdio: "inherit" }); + console.log("āœ… package-lock.json updated successfully"); } catch (error) { - console.error('āŒ Failed to update package-lock.json:', error.message); + console.error("āŒ Failed to update package-lock.json:", error.message); console.error('Please run "npm install" manually'); process.exit(1); } -console.log('\n✨ Version update complete!'); -console.log('\nNext steps:'); -console.log('1. Review the changes: git diff'); -console.log('2. Commit the changes: git add -A && git commit -m "chore: bump version to ' + newVersion + '"'); -console.log('3. Create a git tag: git tag v' + newVersion); -console.log('4. Push changes and tag: git push && git push --tags'); \ No newline at end of file +console.log("\n✨ Version update complete!"); +console.log("\nNext steps:"); +console.log("1. Review the changes: git diff"); +console.log( + '2. Commit the changes: git add -A && git commit -m "chore: bump version to ' + + newVersion + + '"', +); +console.log("3. Create a git tag: git tag v" + newVersion); +console.log("4. Push changes and tag: git push && git push --tags"); From 1c75f8876002067f3b3c9d47784c73c427858ae3 Mon Sep 17 00:00:00 2001 From: cliffhall Date: Tue, 17 Jun 2025 16:38:29 -0400 Subject: [PATCH 14/14] Bump version to 0.14.3 - Need to do a patch level release in order to test the ghcr docker container publishing feature added to main.yml in #257 --- cli/package.json | 2 +- client/package.json | 2 +- package-lock.json | 16 ++++++++-------- package.json | 8 ++++---- server/package.json | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cli/package.json b/cli/package.json index 8e895a55..f1ff1c33 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector-cli", - "version": "0.14.2", + "version": "0.14.3", "description": "CLI for the Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", diff --git a/client/package.json b/client/package.json index 540320bf..37a0675b 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector-client", - "version": "0.14.2", + "version": "0.14.3", "description": "Client-side application for the Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", diff --git a/package-lock.json b/package-lock.json index b46e4597..a54bf664 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@modelcontextprotocol/inspector", - "version": "0.14.2", + "version": "0.14.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@modelcontextprotocol/inspector", - "version": "0.14.2", + "version": "0.14.3", "license": "MIT", "workspaces": [ "client", @@ -14,9 +14,9 @@ "cli" ], "dependencies": { - "@modelcontextprotocol/inspector-cli": "^0.14.2", - "@modelcontextprotocol/inspector-client": "^0.14.2", - "@modelcontextprotocol/inspector-server": "^0.14.2", + "@modelcontextprotocol/inspector-cli": "^0.14.3", + "@modelcontextprotocol/inspector-client": "^0.14.3", + "@modelcontextprotocol/inspector-server": "^0.14.3", "@modelcontextprotocol/sdk": "^1.12.1", "concurrently": "^9.0.1", "open": "^10.1.0", @@ -40,7 +40,7 @@ }, "cli": { "name": "@modelcontextprotocol/inspector-cli", - "version": "0.14.2", + "version": "0.14.3", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", @@ -63,7 +63,7 @@ }, "client": { "name": "@modelcontextprotocol/inspector-client", - "version": "0.14.2", + "version": "0.14.3", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", @@ -10920,7 +10920,7 @@ }, "server": { "name": "@modelcontextprotocol/inspector-server", - "version": "0.14.2", + "version": "0.14.3", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", diff --git a/package.json b/package.json index 061ddf1a..7e7be67f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector", - "version": "0.14.2", + "version": "0.14.3", "description": "Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", @@ -43,9 +43,9 @@ "check-version": "node scripts/check-version-consistency.js" }, "dependencies": { - "@modelcontextprotocol/inspector-cli": "^0.14.2", - "@modelcontextprotocol/inspector-client": "^0.14.2", - "@modelcontextprotocol/inspector-server": "^0.14.2", + "@modelcontextprotocol/inspector-cli": "^0.14.3", + "@modelcontextprotocol/inspector-client": "^0.14.3", + "@modelcontextprotocol/inspector-server": "^0.14.3", "@modelcontextprotocol/sdk": "^1.12.1", "concurrently": "^9.0.1", "open": "^10.1.0", diff --git a/server/package.json b/server/package.json index 9417243d..8f81a9df 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector-server", - "version": "0.14.2", + "version": "0.14.3", "description": "Server-side application for the Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)",