Skip to main content
Glama

Git MCP Server

/** * @fileoverview This script automates the process of preparing and publishing an MCP server * to the MCP Registry. It performs the following steps in order: * * 1. **Sync Metadata**: Reads `package.json` to get the `version` and `mcpName`, * then updates `server.json` with these values. * 2. **Validate Schema**: Validates the updated `server.json` against the official * MCP server schema from the static CDN. * 3. **Auto-Commit**: Automatically commits the updated `server.json` with a * conventional commit message, only if there are changes. * 4. **Authenticate**: Initiates `mcp-publisher login github` and waits for the user * to complete the browser-based authentication. * 5. **Publish**: Runs `mcp-publisher publish` to upload the server package to the registry. * * It supports flags like `--validate-only` and `--no-commit` for flexible control. * @module scripts/validate-mcp-publish-schema */ import Ajv from "ajv"; import addFormats from "ajv-formats"; import axios from "axios"; import { execSync } from "child_process"; import fs from "fs/promises"; import path from "path"; // --- Constants --- const PACKAGE_JSON_PATH = path.resolve(process.cwd(), "package.json"); const SERVER_JSON_PATH = path.resolve(process.cwd(), "server.json"); const MCP_SCHEMA_URL = "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json"; // --- Helper Functions --- function runCommand(command: string, stepName: string) { console.log(`\n--- 🚀 Starting Step: ${stepName} ---`); console.log(`> ${command}`); try { execSync(command, { stdio: "inherit" }); console.log(`--- ✅ Finished Step: ${stepName} ---`); } catch (_error) { console.error(`\n--- ❌ Step Failed: ${stepName} ---`); console.error(`Command "${command}" failed.`); process.exit(1); } } async function syncMetadata(): Promise<string> { const stepName = "Sync Metadata from package.json"; console.log(`\n--- 🚀 Starting Step: ${stepName} ---`); try { const pkgContent = await fs.readFile(PACKAGE_JSON_PATH, "utf-8"); const serverContent = await fs.readFile(SERVER_JSON_PATH, "utf-8"); const pkg = JSON.parse(pkgContent); const server = JSON.parse(serverContent); const { version, mcpName } = pkg; if (!version || !mcpName) { throw new Error( "`version` and/or `mcpName` are missing from package.json.", ); } server.version = version; server.mcpName = mcpName; if (Array.isArray(server.packages)) { server.packages.forEach((p: { version?: string }) => { p.version = version; }); console.log(`Updated version for ${server.packages.length} package(s).`); } await fs.writeFile(SERVER_JSON_PATH, JSON.stringify(server, null, 2)); console.log(`Synced server.json to version "${version}".`); console.log(`--- ✅ Finished Step: ${stepName} ---`); return version; } catch (error) { console.error(`\n--- ❌ Step Failed: ${stepName} ---`, error); process.exit(1); } } function autoCommitChanges(version: string) { const stepName = "Auto-commit server.json"; console.log(`\n--- 🚀 Starting Step: ${stepName} ---`); try { const status = execSync("git status --porcelain server.json") .toString() .trim(); if (!status) { console.log("No changes to commit in server.json. Skipping."); console.log(`--- ✅ Finished Step: ${stepName} (No-op) ---`); return; } execSync("git add server.json"); const commitMessage = `chore(release): bump server.json to v${version}`; const commitCommand = `git commit --no-verify -m "${commitMessage}"`; console.log(`> ${commitCommand}`); execSync(commitCommand); console.log("Successfully committed version bump for server.json."); console.log(`--- ✅ Finished Step: ${stepName} ---`); } catch (_error) { console.warn(`\n--- ⚠️ Step Skipped: ${stepName} ---`); console.warn("Failed to auto-commit. Please commit changes manually."); } } async function validateServerJson() { const stepName = "Validate server.json Schema"; console.log(`\n--- 🚀 Starting Step: ${stepName} ---`); try { const { data: schema } = await axios.get(MCP_SCHEMA_URL); const serverJson = JSON.parse(await fs.readFile(SERVER_JSON_PATH, "utf-8")); const ajv = new Ajv({ strict: false }); addFormats(ajv); const validate = ajv.compile(schema); if (!validate(serverJson)) { console.error("Validation failed:", validate.errors); throw new Error("server.json does not conform to the MCP schema."); } console.log("Validation successful!"); console.log(`--- ✅ Finished Step: ${stepName} ---`); } catch (error) { console.error(`\n--- ❌ Step Failed: ${stepName} ---`, error); process.exit(1); } } async function main() { const args = process.argv.slice(2); const syncOnly = args.includes("--sync-only"); const validateOnly = args.includes("--validate-only"); const noCommit = args.includes("--no-commit"); const publishOnly = args.includes("--publish-only"); console.log("🚀 Starting MCP Server Publish Workflow..."); if (publishOnly) { console.log( "\n⚪ --publish-only flag detected. Skipping local file changes.", ); runCommand("mcp-publisher login github", "Authenticate with GitHub"); runCommand("mcp-publisher publish", "Publish to MCP Registry"); console.log("\n🎉🎉🎉 Publish Complete! 🎉🎉🎉"); return; } const newVersion = await syncMetadata(); if (syncOnly) { console.log("\n✅ --sync-only flag detected. Halting after metadata sync."); return; } await validateServerJson(); if (validateOnly) { console.log( "\n✅ --validate-only flag detected. Halting after validation.", ); return; } if (!noCommit) { autoCommitChanges(newVersion); } else { console.log("\n⚪ --no-commit flag detected. Skipping auto-commit."); } runCommand("mcp-publisher login github", "Authenticate with GitHub"); runCommand("mcp-publisher publish", "Publish to MCP Registry"); console.log( "\n🎉🎉🎉 Workflow Complete! Your server has been successfully published. 🎉🎉🎉", ); } // --- Execute --- main();

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cyanheads/git-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server