-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
Every NimbleBrain MCP server has version numbers scattered across multiple files, each serving a different consumer. There is no single source of truth — make bump is the only mechanism keeping them in sync, and it is a manual local step with no enforcement.
Node.js servers
| File | Consumer | How version is stored |
|---|---|---|
manifest.json |
mpak registry / bundle tooling | { "version": "0.1.0" } |
package.json |
npm package manager | { "version": "0.1.0" } |
src/constants.ts |
MCP SDK handshake, runtime logs | export const VERSION = '0.1.0' |
server.json |
MCP registry discovery | { "version": "0.1.0" } (synced by mcpb-pack at release) |
Python servers
| File | Consumer | How version is stored |
|---|---|---|
manifest.json |
mpak registry / bundle tooling | { "version": "0.1.0" } |
pyproject.toml |
pip / uv package manager | version = "0.1.0" |
src/mcp_<name>/__init__.py |
FastMCP handshake, runtime logs | __version__ = "0.1.0" |
server.json |
MCP registry discovery | { "version": "0.1.0" } (synced by mcpb-pack at release) |
Current pain points
- A developer can forget to run
make bumpand commit mismatched versions — nothing catches it - CI has no version consistency check
mcpb-packonly syncsserver.jsonfrommanifest.json— it does not validate the rest- No template-level enforcement means every new server repo inherits this gap silently
make bumpcurrently requires the developer to passVERSION=x.y.zas an argument — the version has no persistent home in the repo
Proposed Solution
1. Introduce .PACKAGE_VERSION as the single source of truth
Add a .PACKAGE_VERSION file in the repo root containing only the version string:
0.1.0
This is the one file a developer ever edits when bumping a version. It is a flat file — trivially readable by any script, in any language, with no parsing.
2. make bump reads from .PACKAGE_VERSION — no argument needed
Instead of passing VERSION=x.y.z on the command line, the developer edits .PACKAGE_VERSION directly and then runs make bump with no arguments:
bump:
$(eval VERSION := $(shell cat .PACKAGE_VERSION))
@if [ -z "$(VERSION)" ]; then \
echo "Error: .PACKAGE_VERSION is empty"; exit 1; \
fi
@echo "Bumping to version $(VERSION)..."
@jq --arg v "$(VERSION)" '.version = $$v' manifest.json > manifest.tmp.json && mv manifest.tmp.json manifest.json
# Node.js
@if [ -f package.json ]; then \
jq --arg v "$(VERSION)" '.version = $$v' package.json > package.tmp.json && mv package.tmp.json package.json; \
fi
@if [ -f src/constants.ts ]; then \
sed -i '' "s/export const VERSION = '.*'/export const VERSION = '$(VERSION)'/" src/constants.ts; \
fi
# Python
@if [ -f pyproject.toml ]; then \
sed -i '' "s/^version = \".*\"/version = \"$(VERSION)\"/" pyproject.toml; \
fi
@if [ -f src/mcp_*/\_\_init\_\_.py ]; then \
sed -i '' "s/__version__ = \".*\"/__version__ = \"$(VERSION)\"/" src/mcp_*/__init__.py; \
fi
@echo "Version bumped to $(VERSION) in all files."The full developer workflow becomes:
1. Edit .PACKAGE_VERSION → "1.2.0"
2. make bump (propagates to all files)
3. git commit
4. gh release create v$(cat .PACKAGE_VERSION) (tag always matches)
3. Remove Update manifest version step from build-bundle.yml
Since the git tag is derived from .PACKAGE_VERSION, and make bump has already stamped all files before the commit, the CI step that overwrites manifest.json and server.json from the git tag is unnecessary and should be removed. mcpb-pack already handles syncing server.json version from manifest.json internally.
Optionally, add a guard in build-bundle.yml to verify the tag matches .PACKAGE_VERSION:
EXPECTED="v$(cat .PACKAGE_VERSION)"
ACTUAL="${{ github.event.release.tag_name }}"
if [ "$EXPECTED" != "$ACTUAL" ]; then
echo "Tag $ACTUAL does not match .PACKAGE_VERSION ($EXPECTED)"
echo "Did you forget to run make bump?"
exit 1
fi4. Add a version consistency check to CI
This script reads the runtime type from manifest.json and validates all relevant files match .PACKAGE_VERSION:
#!/bin/bash
set -e
EXPECTED=$(cat .PACKAGE_VERSION)
MANIFEST=$(jq -r '.version' manifest.json)
RUNTIME=$(jq -r '.server.type' manifest.json)
FAILED=0
check() {
local label=$1
local actual=$2
if [ "$actual" != "$EXPECTED" ]; then
echo "MISMATCH: $label has '$actual', expected '$EXPECTED'"
FAILED=1
else
echo "OK: $label = $actual"
fi
}
check "manifest.json" "$MANIFEST"
if [ "$RUNTIME" = "node" ]; then
check "package.json" "$(jq -r '.version' package.json)"
check "src/constants.ts" "$(grep -o "'[0-9.]*'" src/constants.ts | tr -d "'")"
elif [ "$RUNTIME" = "python" ]; then
check "pyproject.toml" "$(grep '^version' pyproject.toml | sed 's/version = "//;s/"//')"
check "src/__init__.py" "$(grep '__version__' src/mcp_*/__init__.py | grep -o '"[0-9.]*"' | tr -d '"')"
fi
if [ "$FAILED" -eq 1 ]; then
echo ""
echo "Version mismatch detected. Edit .PACKAGE_VERSION and run: make bump"
exit 1
fi
echo "All version files in sync."Add this as a step in ci.yml:
- name: Check version consistency
run: bash scripts/check-versions.sh5. Add the same check inside mcpb-pack
The version consistency check should also run inside the mcpb-pack action so it is enforced at release time as a hard gate — not just on PRs. This means even if a PR slips through, a release cannot be published with mismatched versions.
Affected repos
NimbleBrainInc/mcp-server-template— add.PACKAGE_VERSION, updatedMakefile,scripts/check-versions.sh, and removeUpdate manifest versionstep frombuild-bundle.ymlso all new servers get this for freeNimbleBrainInc/mcpb-pack— add version consistency check as a build step- All existing server repos — migrate on next version bump