From ccf3793d2bbe58f03458d876a882bcf81e23d456 Mon Sep 17 00:00:00 2001 From: ianshward Date: Mon, 6 Oct 2025 14:11:40 -0400 Subject: [PATCH 1/3] add server.json for mcp registry --- manifest.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- server.json | 31 +++++++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 server.json diff --git a/manifest.json b/manifest.json index e0d6875..16a197c 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "dxt_version": "0.1", "name": "@mapbox/mcp-devkit-server", "display_name": "Mapbox MCP DevKit Server", - "version": "0.4.3", + "version": "0.4.4", "description": "Mapbox MCP devkit server", "author": { "name": "Mapbox, Inc." diff --git a/package-lock.json b/package-lock.json index 629f03d..1ace5b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mapbox/mcp-devkit-server", - "version": "0.4.3", + "version": "0.4.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mapbox/mcp-devkit-server", - "version": "0.4.3", + "version": "0.4.4", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.17.5", diff --git a/package.json b/package.json index aef39e5..c213241 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mapbox/mcp-devkit-server", - "version": "0.4.3", + "version": "0.4.4", "description": "Mapbox MCP devkit server", "main": "./dist/commonjs/index.js", "module": "./dist/esm/index.js", diff --git a/server.json b/server.json new file mode 100644 index 0000000..0b6c9fc --- /dev/null +++ b/server.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-16/server.schema.json", + "name": "io.github.mapbox/mcp-devkit-server", + "description": "Provides AI assistants with direct access to Mapbox developer APIs and documentation.", + "repository": { + "url": "https://github.com/mapbox/mcp-devkit-server", + "source": "github" + }, + "version": "0.4.4", + "packages": [ + { + "registryType": "npm", + "registryBaseUrl": "https://registry.npmjs.org", + "runtimeHint": "npx", + "version": "0.4.4", + "identifier": "@mapbox/mcp-devkit-server", + "transport": { + "type": "stdio" + }, + "environmentVariables": [ + { + "description": "Your Mapbox access token. See docs for required scopes.", + "format": "string", + "isRequired": true, + "isSecret": true, + "name": "MAPBOX_ACCESS_TOKEN" + } + ] + } + ] +} From bd72968886c615932b0fb6d8b7a2233bad857567 Mon Sep 17 00:00:00 2001 From: ianshward Date: Mon, 6 Oct 2025 14:18:32 -0400 Subject: [PATCH 2/3] update version sync script, update and add tests --- scripts/sync-manifest-version.cjs | 124 ++++++++++--- test/project/fixtures/manifest.json | 9 + test/project/fixtures/package.json | 5 + test/project/fixtures/server.json | 12 ++ test/project/sync-manifest-version.test.ts | 204 +++++++++++++++++++++ test/project/version-consistency.test.ts | 27 +++ test/version-consistency.test.ts | 15 -- 7 files changed, 358 insertions(+), 38 deletions(-) create mode 100644 test/project/fixtures/manifest.json create mode 100644 test/project/fixtures/package.json create mode 100644 test/project/fixtures/server.json create mode 100644 test/project/sync-manifest-version.test.ts create mode 100644 test/project/version-consistency.test.ts delete mode 100644 test/version-consistency.test.ts diff --git a/scripts/sync-manifest-version.cjs b/scripts/sync-manifest-version.cjs index 931cb9a..d1bb85b 100644 --- a/scripts/sync-manifest-version.cjs +++ b/scripts/sync-manifest-version.cjs @@ -1,36 +1,114 @@ -// Sync manifest.json version with package.json +// Sync manifest.json and server.json versions with package.json const fs = require('node:fs'); const path = require('node:path'); -function syncManifestVersion() { +/** + * Pure function that syncs versions across config objects + * @param {Object} packageJson - The package.json object + * @param {Object} manifestJson - The manifest.json object + * @param {Object} serverJson - The server.json object + * @returns {Object} Result containing updated configs and change information + */ +function syncVersionsCore(packageJson, manifestJson, serverJson) { + const packageVersion = packageJson.version; + const result = { + packageVersion, + updatedManifest: null, + updatedServer: null, + changes: { + manifest: false, + server: false, + serverPackage: false + }, + oldVersions: { + manifest: manifestJson.version, + server: serverJson.version, + serverPackage: serverJson.packages?.[0]?.version + } + }; + + // Check and update manifest.json + if (manifestJson.version !== packageVersion) { + result.updatedManifest = { ...manifestJson, version: packageVersion }; + result.changes.manifest = true; + } + + // Check and update server.json + const serverNeedsUpdate = serverJson.version !== packageVersion; + const packageNeedsUpdate = serverJson.packages?.[0] && + serverJson.packages[0].version !== packageVersion; + + if (serverNeedsUpdate || packageNeedsUpdate) { + result.updatedServer = JSON.parse(JSON.stringify(serverJson)); // Deep clone + + if (serverNeedsUpdate) { + result.updatedServer.version = packageVersion; + result.changes.server = true; + } + + if (packageNeedsUpdate) { + result.updatedServer.packages[0].version = packageVersion; + result.changes.serverPackage = true; + } + } + + return result; +} + +function syncVersions() { const packageJsonPath = path.join(process.cwd(), 'package.json'); const manifestJsonPath = path.join(process.cwd(), 'manifest.json'); + const serverJsonPath = path.join(process.cwd(), 'server.json'); - // Read package.json + // Read files const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); - const packageVersion = packageJson.version; - - // Read manifest.json const manifestJson = JSON.parse(fs.readFileSync(manifestJsonPath, 'utf-8')); - const manifestVersion = manifestJson.version; + const serverJson = JSON.parse(fs.readFileSync(serverJsonPath, 'utf-8')); + + // Sync versions using pure function + const result = syncVersionsCore(packageJson, manifestJson, serverJson); + + let updatedFiles = []; - // Check if versions are already in sync - if (manifestVersion === packageVersion) { - console.log(`✓ Versions already in sync: ${packageVersion}`); - return; + // Write updated manifest if needed + if (result.updatedManifest) { + fs.writeFileSync( + manifestJsonPath, + JSON.stringify(result.updatedManifest, null, 2) + '\n', + 'utf-8' + ); + console.log( + `✓ Updated manifest.json version: ${result.oldVersions.manifest} → ${result.packageVersion}` + ); + updatedFiles.push('manifest.json'); } - // Update manifest.json version - manifestJson.version = packageVersion; - fs.writeFileSync( - manifestJsonPath, - JSON.stringify(manifestJson, null, 2) + '\n', - 'utf-8' - ); - - console.log( - `✓ Updated manifest.json version: ${manifestVersion} → ${packageVersion}` - ); + // Write updated server if needed + if (result.updatedServer) { + fs.writeFileSync( + serverJsonPath, + JSON.stringify(result.updatedServer, null, 2) + '\n', + 'utf-8' + ); + console.log( + `✓ Updated server.json versions: ${result.oldVersions.server} → ${result.packageVersion}` + ); + updatedFiles.push('server.json'); + } + + if (updatedFiles.length === 0) { + console.log(`✓ All versions already in sync: ${result.packageVersion}`); + } else { + console.log(`✓ Synced ${updatedFiles.join(', ')} with package.json version: ${result.packageVersion}`); + } +} + +// Export for testing +if (typeof module !== 'undefined' && module.exports) { + module.exports = { syncVersionsCore, syncVersions }; } -syncManifestVersion(); \ No newline at end of file +// Run if called directly +if (require.main === module) { + syncVersions(); +} \ No newline at end of file diff --git a/test/project/fixtures/manifest.json b/test/project/fixtures/manifest.json new file mode 100644 index 0000000..3a0e863 --- /dev/null +++ b/test/project/fixtures/manifest.json @@ -0,0 +1,9 @@ +{ + "dxt_version": "0.1", + "name": "test-manifest", + "version": "1.0.0", + "description": "Test manifest", + "author": { + "name": "Test Author" + } +} diff --git a/test/project/fixtures/package.json b/test/project/fixtures/package.json new file mode 100644 index 0000000..b9e1eff --- /dev/null +++ b/test/project/fixtures/package.json @@ -0,0 +1,5 @@ +{ + "name": "test-package", + "version": "2.0.0", + "description": "Test package for sync script" +} diff --git a/test/project/fixtures/server.json b/test/project/fixtures/server.json new file mode 100644 index 0000000..660c3da --- /dev/null +++ b/test/project/fixtures/server.json @@ -0,0 +1,12 @@ +{ + "$schema": "test-schema", + "name": "test-server", + "version": "1.5.0", + "packages": [ + { + "identifier": "test-package", + "version": "1.2.0", + "registryType": "npm" + } + ] +} diff --git a/test/project/sync-manifest-version.test.ts b/test/project/sync-manifest-version.test.ts new file mode 100644 index 0000000..f748dc2 --- /dev/null +++ b/test/project/sync-manifest-version.test.ts @@ -0,0 +1,204 @@ +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { createRequire } from 'node:module'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const require = createRequire(import.meta.url); + +// Import the pure function from the sync script +const { syncVersionsCore } = require('../../scripts/sync-manifest-version.cjs'); + +describe('sync-manifest-version.cjs - syncVersionsCore', () => { + // Load fixtures + const fixturesDir = join(__dirname, 'fixtures'); + const packageJsonFixture = JSON.parse( + readFileSync(join(fixturesDir, 'package.json'), 'utf-8') + ); + const manifestJsonFixture = JSON.parse( + readFileSync(join(fixturesDir, 'manifest.json'), 'utf-8') + ); + const serverJsonFixture = JSON.parse( + readFileSync(join(fixturesDir, 'server.json'), 'utf-8') + ); + + it('should update manifest.json when version differs from package.json', () => { + const packageJson = { ...packageJsonFixture, version: '3.0.0' }; + const manifestJson = { ...manifestJsonFixture, version: '1.0.0' }; + const serverJson = { + ...serverJsonFixture, + version: '3.0.0', + packages: [{ ...serverJsonFixture.packages[0], version: '3.0.0' }] + }; + + const result = syncVersionsCore(packageJson, manifestJson, serverJson); + + expect(result.updatedManifest).toBeDefined(); + expect(result.updatedManifest.version).toBe('3.0.0'); + expect(result.updatedManifest.name).toBe('test-manifest'); // Other fields preserved + expect(result.changes.manifest).toBe(true); + expect(result.changes.server).toBe(false); + expect(result.changes.serverPackage).toBe(false); + expect(result.updatedServer).toBeNull(); + }); + + it('should update server.json top-level version when it differs', () => { + const packageJson = { ...packageJsonFixture, version: '4.0.0' }; + const manifestJson = { ...manifestJsonFixture, version: '4.0.0' }; + const serverJson = { + ...serverJsonFixture, + version: '2.0.0', + packages: [{ ...serverJsonFixture.packages[0], version: '4.0.0' }] + }; + + const result = syncVersionsCore(packageJson, manifestJson, serverJson); + + expect(result.updatedServer).toBeDefined(); + expect(result.updatedServer.version).toBe('4.0.0'); + expect(result.updatedServer.name).toBe('test-server'); // Other fields preserved + expect(result.changes.server).toBe(true); + expect(result.changes.serverPackage).toBe(false); + expect(result.changes.manifest).toBe(false); + expect(result.updatedManifest).toBeNull(); + }); + + it('should update server.json packages[0].version when it differs', () => { + const packageJson = { ...packageJsonFixture, version: '5.0.0' }; + const manifestJson = { ...manifestJsonFixture, version: '5.0.0' }; + const serverJson = { + ...serverJsonFixture, + version: '5.0.0', + packages: [{ ...serverJsonFixture.packages[0], version: '3.0.0' }] + }; + + const result = syncVersionsCore(packageJson, manifestJson, serverJson); + + expect(result.updatedServer).toBeDefined(); + expect(result.updatedServer.packages[0].version).toBe('5.0.0'); + expect(result.updatedServer.packages[0].identifier).toBe('test-package'); // Other fields preserved + expect(result.changes.serverPackage).toBe(true); + expect(result.changes.server).toBe(false); + expect(result.changes.manifest).toBe(false); + }); + + it('should update all versions when all differ', () => { + const packageJson = { ...packageJsonFixture, version: '6.0.0' }; + const manifestJson = { ...manifestJsonFixture, version: '1.0.0' }; + const serverJson = { + ...serverJsonFixture, + version: '2.0.0', + packages: [{ ...serverJsonFixture.packages[0], version: '3.0.0' }] + }; + + const result = syncVersionsCore(packageJson, manifestJson, serverJson); + + expect(result.updatedManifest).toBeDefined(); + expect(result.updatedManifest.version).toBe('6.0.0'); + expect(result.updatedServer).toBeDefined(); + expect(result.updatedServer.version).toBe('6.0.0'); + expect(result.updatedServer.packages[0].version).toBe('6.0.0'); + expect(result.changes.manifest).toBe(true); + expect(result.changes.server).toBe(true); + expect(result.changes.serverPackage).toBe(true); + }); + + it('should return no updates when all versions are in sync', () => { + const packageJson = { ...packageJsonFixture, version: '7.0.0' }; + const manifestJson = { ...manifestJsonFixture, version: '7.0.0' }; + const serverJson = { + ...serverJsonFixture, + version: '7.0.0', + packages: [{ ...serverJsonFixture.packages[0], version: '7.0.0' }] + }; + + const result = syncVersionsCore(packageJson, manifestJson, serverJson); + + expect(result.updatedManifest).toBeNull(); + expect(result.updatedServer).toBeNull(); + expect(result.changes.manifest).toBe(false); + expect(result.changes.server).toBe(false); + expect(result.changes.serverPackage).toBe(false); + expect(result.packageVersion).toBe('7.0.0'); + }); + + it('should handle server.json without packages array', () => { + const packageJson = { ...packageJsonFixture, version: '8.0.0' }; + const manifestJson = { ...manifestJsonFixture, version: '8.0.0' }; + const serverJson = { + name: 'test-server', + version: '1.0.0' + // No packages array + }; + + const result = syncVersionsCore(packageJson, manifestJson, serverJson); + + expect(result.updatedServer).toBeDefined(); + expect(result.updatedServer.version).toBe('8.0.0'); + expect(result.updatedServer.packages).toBeUndefined(); // Should not add packages + expect(result.changes.server).toBe(true); + expect(result.changes.serverPackage).toBe(false); + }); + + it('should handle server.json with empty packages array', () => { + const packageJson = { ...packageJsonFixture, version: '9.0.0' }; + const manifestJson = { ...manifestJsonFixture, version: '9.0.0' }; + const serverJson = { + ...serverJsonFixture, + version: '9.0.0', + packages: [] + }; + + const result = syncVersionsCore(packageJson, manifestJson, serverJson); + + expect(result.updatedServer).toBeNull(); + expect(result.changes.server).toBe(false); + expect(result.changes.serverPackage).toBe(false); + }); + + it('should track old versions for reporting', () => { + const packageJson = { ...packageJsonFixture, version: '10.0.0' }; + const manifestJson = { ...manifestJsonFixture, version: '1.1.0' }; + const serverJson = { + ...serverJsonFixture, + version: '2.2.0', + packages: [{ ...serverJsonFixture.packages[0], version: '3.3.0' }] + }; + + const result = syncVersionsCore(packageJson, manifestJson, serverJson); + + expect(result.oldVersions.manifest).toBe('1.1.0'); + expect(result.oldVersions.server).toBe('2.2.0'); + expect(result.oldVersions.serverPackage).toBe('3.3.0'); + expect(result.packageVersion).toBe('10.0.0'); + }); + + it('should preserve all non-version fields in updated objects', () => { + const packageJson = { ...packageJsonFixture, version: '11.0.0' }; + const manifestJson = { + ...manifestJsonFixture, + version: '1.0.0', + customField: 'should-be-preserved', + nested: { data: 'also-preserved' } + }; + const serverJson = { + ...serverJsonFixture, + version: '2.0.0', + packages: [ + { + ...serverJsonFixture.packages[0], + version: '3.0.0', + extraData: 'keep-this' + } + ], + metadata: 'preserve-me' + }; + + const result = syncVersionsCore(packageJson, manifestJson, serverJson); + + expect(result.updatedManifest.customField).toBe('should-be-preserved'); + expect(result.updatedManifest.nested).toEqual({ data: 'also-preserved' }); + expect(result.updatedServer.metadata).toBe('preserve-me'); + expect(result.updatedServer.packages[0].extraData).toBe('keep-this'); + }); +}); diff --git a/test/project/version-consistency.test.ts b/test/project/version-consistency.test.ts new file mode 100644 index 0000000..1601106 --- /dev/null +++ b/test/project/version-consistency.test.ts @@ -0,0 +1,27 @@ +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +describe('Version Consistency', () => { + it('should have matching versions in package.json, server.json, and manifest.json', () => { + const packageJsonPath = join(__dirname, '..', '..', 'package.json'); + const serverJsonPath = join(__dirname, '..', '..', 'server.json'); + const manifestJsonPath = join(__dirname, '..', '..', 'manifest.json'); + + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); + const serverJson = JSON.parse(readFileSync(serverJsonPath, 'utf-8')); + const manifestJson = JSON.parse(readFileSync(manifestJsonPath, 'utf-8')); + + const packageVersion = packageJson.version; + const serverVersion = serverJson.version; + const serverPackageVersion = serverJson.packages?.[0]?.version; + const manifestVersion = manifestJson.version; + + expect(serverVersion).toBe(packageVersion); + expect(serverPackageVersion).toBe(packageVersion); + expect(manifestVersion).toBe(packageVersion); + }); +}); diff --git a/test/version-consistency.test.ts b/test/version-consistency.test.ts deleted file mode 100644 index 8b95bd3..0000000 --- a/test/version-consistency.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { readFileSync } from 'node:fs'; -import { join } from 'node:path'; - -describe('Version Consistency', () => { - it('should have matching versions in package.json and manifest.json', () => { - const packageJsonPath = join(process.cwd(), 'package.json'); - const manifestJsonPath = join(process.cwd(), 'manifest.json'); - - const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); - const manifestJson = JSON.parse(readFileSync(manifestJsonPath, 'utf-8')); - - expect(manifestJson.version).toBe(packageJson.version); - }); -}); From cc90c61d09d5cacadb433f954a6598cbede12fca Mon Sep 17 00:00:00 2001 From: ianshward Date: Mon, 6 Oct 2025 14:32:46 -0400 Subject: [PATCH 3/3] update changelog --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b152be6..f8a9995 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ -## 0.4.0 (Unreleased) +## 0.4.4 + +### Other + +- Add to MCP registry + +## 0.4.0 ### Features Added