feat(v0.18): kei-mcp-server single-binary compile — 5-platform via bun
Phase 1 of exobrain architecture. Ships TS MCP server as a static
binary so users on machines without Node can run KeiSeiKit (USB /
flashdrive / air-gapped scenarios).
.github/workflows/release.yml (+62 LOC) — new build-mcp-binary job:
- 5-target matrix: darwin arm64/x64, linux arm64/x64, windows x64
- bun build --compile, linux arm64 continue-on-error (ARM runners
less reliable)
- Artifact kei-mcp-server-<os>-<arch>[.exe] + sha256
- release job now needs [build-release, build-mcp-binary]
install/lib-rust.sh (+50 LOC) — have_prebuilt_mcp_server() +
report_mcp_server_binary_status(); KEI_SKIP_MCP_BUILD=1 env
flag skips bun/npm install when a prebuilt binary is present.
File 165 LOC (<200 limit).
_ts_packages/packages/mcp-server/package.json — scripts.build:native
+ 5 per-target aliases (macos-arm, macos-x64, linux-x64,
linux-arm, win-x64) for local dev.
_ts_packages/packages/mcp-server/BUILD.md (NEW, 52 LOC) — local
compile guide per platform + Gatekeeper/code-sign notes +
cites bun docs [VERIFIED: https://bun.sh/docs/bundler/executables].
README.md pre-built-binaries section gains 'MCP server binary'
subsection (download, chmod +x, xattr -d com.apple.quarantine for
macOS, UAC note for Windows).
CHANGELOG.md [Unreleased] bullet added.
Output size: ~90 MB per binary (bundled bun runtime). Acceptable
trade for zero-dep USB distribution.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bcc199a62e
commit
e67ade47c8
6 changed files with 217 additions and 4 deletions
83
.github/workflows/release.yml
vendored
83
.github/workflows/release.yml
vendored
|
|
@ -98,9 +98,77 @@ jobs:
|
|||
keisei-${{ matrix.target }}.tar.gz.sha256
|
||||
if-no-files-found: error
|
||||
|
||||
# v0.18 Phase 1 (exobrain): compile @keisei/mcp-server to a single static
|
||||
# binary for 5 platforms via `bun build --compile`. Runs in parallel with
|
||||
# build-release; the release job below `needs:` both. Linux arm64 is kept
|
||||
# `continue-on-error` because the ubuntu arm runner pool is newer and
|
||||
# occasionally flaky — a missing linux-arm64 asset must NOT block release.
|
||||
build-mcp-binary:
|
||||
name: Build mcp-server ${{ matrix.target.platform }}-${{ matrix.target.arch }}
|
||||
runs-on: ${{ matrix.target.runner }}
|
||||
continue-on-error: ${{ matrix.target.arch == 'arm64' && matrix.target.platform == 'linux' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- { platform: linux, arch: x64, runner: ubuntu-latest, bun_target: bun-linux-x64, ext: '' }
|
||||
- { platform: linux, arch: arm64, runner: ubuntu-24.04-arm, bun_target: bun-linux-arm64, ext: '' }
|
||||
- { platform: darwin, arch: x64, runner: macos-13, bun_target: bun-darwin-x64, ext: '' }
|
||||
- { platform: darwin, arch: arm64, runner: macos-latest, bun_target: bun-darwin-arm64, ext: '' }
|
||||
- { platform: windows, arch: x64, runner: windows-latest, bun_target: bun-windows-x64, ext: '.exe' }
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Install mcp-server deps
|
||||
shell: bash
|
||||
working-directory: _ts_packages/packages/mcp-server
|
||||
run: bun install --frozen-lockfile || bun install
|
||||
|
||||
- name: Compile single-binary
|
||||
shell: bash
|
||||
env:
|
||||
BIN_NAME: kei-mcp-server-${{ matrix.target.platform }}-${{ matrix.target.arch }}${{ matrix.target.ext }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p dist
|
||||
bun build \
|
||||
--compile \
|
||||
--target=${{ matrix.target.bun_target }} \
|
||||
_ts_packages/packages/mcp-server/src/index.ts \
|
||||
--outfile "dist/${BIN_NAME}"
|
||||
ls -la "dist/${BIN_NAME}"
|
||||
|
||||
- name: Compute sha256
|
||||
shell: bash
|
||||
env:
|
||||
BIN_NAME: kei-mcp-server-${{ matrix.target.platform }}-${{ matrix.target.arch }}${{ matrix.target.ext }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cd dist
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
sha256sum "${BIN_NAME}" > "${BIN_NAME}.sha256"
|
||||
else
|
||||
shasum -a 256 "${BIN_NAME}" > "${BIN_NAME}.sha256"
|
||||
fi
|
||||
cat "${BIN_NAME}.sha256"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: kei-mcp-server-${{ matrix.target.platform }}-${{ matrix.target.arch }}
|
||||
path: |
|
||||
dist/kei-mcp-server-${{ matrix.target.platform }}-${{ matrix.target.arch }}${{ matrix.target.ext }}
|
||||
dist/kei-mcp-server-${{ matrix.target.platform }}-${{ matrix.target.arch }}${{ matrix.target.ext }}.sha256
|
||||
if-no-files-found: error
|
||||
|
||||
release:
|
||||
name: Publish GitHub Release
|
||||
needs: build-release
|
||||
needs: [build-release, build-mcp-binary]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -126,8 +194,16 @@ jobs:
|
|||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p release-assets
|
||||
find dist -type f \( -name '*.tar.gz' -o -name '*.sha256' \) \
|
||||
-exec mv {} release-assets/ \;
|
||||
# Rust tarballs + sha256 sums from build-release matrix.
|
||||
# MCP-server bare binaries (+ .exe on windows) + sha256 sums from
|
||||
# build-mcp-binary matrix. Bare binaries need a stable name to stay
|
||||
# USB-drive-droppable, so no archive — we ship them raw alongside
|
||||
# the tarballs.
|
||||
find dist -type f \( \
|
||||
-name '*.tar.gz' \
|
||||
-o -name '*.sha256' \
|
||||
-o -name 'kei-mcp-server-*' \
|
||||
\) -exec mv {} release-assets/ \;
|
||||
ls -la release-assets
|
||||
|
||||
- name: Generate release notes (kei-changelog)
|
||||
|
|
@ -163,6 +239,7 @@ jobs:
|
|||
files: |
|
||||
release-assets/*.tar.gz
|
||||
release-assets/*.sha256
|
||||
release-assets/kei-mcp-server-*
|
||||
fail_on_unmatched_files: false
|
||||
|
||||
npm-publish:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ _primitives/_rust/target/release/kei-changelog \
|
|||
- Placeholder: CHANGELOG.md generation wired through `kei-changelog` (this file).
|
||||
- Placeholder: `.github/workflows/release.yml` — tag-driven multi-platform release.
|
||||
- Placeholder: pre-built-binary install path in `install.sh` (`KEI_SKIP_RUST_BUILD=1`).
|
||||
- added: `kei-mcp-server` single-binary compile for 5 platforms (linux/darwin/windows × x64/arm64 where available) via `bun build --compile` — v0.18 Phase 1 of the exobrain distribution architecture. Ships as bare binaries + `.sha256` sums on every GitHub release; `install.sh` detects a dropped binary at `_primitives/_rust/target/release/kei-mcp-server-<os>-<arch>` and skips bun/npm build. Opt-out via `KEI_SKIP_MCP_BUILD=1`. See `_ts_packages/packages/mcp-server/BUILD.md`.
|
||||
|
||||
### Changed
|
||||
- Placeholder: plugin / block format refresh targeted for v0.16.0.
|
||||
|
|
|
|||
26
README.md
26
README.md
|
|
@ -112,6 +112,32 @@ Profile resolution lives in `_primitives/MANIFEST.toml` — one `[primitive.<nam
|
|||
|
||||
> **Re-install disclaimer:** `install.sh` is idempotent for clean state but **overwrites kit-owned `_blocks/`, `_primitives/`, `_bridges/`, `_templates/`, `_assembler/`, `hooks/`, and `skills/` on re-run** — local modifications under those directories are backed up to `<dir>.bak-TIMESTAMP/` (or, for shared hook files, to `<file>.bak-TIMESTAMP`). User-owned `_manifests/*.toml` are never overwritten.
|
||||
|
||||
### MCP server binary (zero-install path, v0.18)
|
||||
|
||||
From v0.18 each GitHub release ships a **single static binary** of the `@keisei/mcp-server` package for five platforms — no Node, no `npm install`. Drop the binary anywhere (USB stick, S3 bucket, Downloads folder) and run it. This is Phase 1 of the "exobrain" distribution goal: any MCP-capable client can mount KeiSeiKit from read-only media.
|
||||
|
||||
| Platform | Asset name |
|
||||
|---|---|
|
||||
| Linux x64 | `kei-mcp-server-linux-x64` |
|
||||
| Linux arm64 | `kei-mcp-server-linux-arm64` |
|
||||
| macOS x64 | `kei-mcp-server-darwin-x64` |
|
||||
| macOS arm64 | `kei-mcp-server-darwin-arm64` |
|
||||
| Windows x64 | `kei-mcp-server-windows-x64.exe` |
|
||||
|
||||
```bash
|
||||
# Linux / macOS
|
||||
curl -L -o kei-mcp-server \
|
||||
https://github.com/<your-fork>/KeiSeiKit/releases/latest/download/kei-mcp-server-darwin-arm64
|
||||
chmod +x kei-mcp-server
|
||||
# macOS only — clear Gatekeeper quarantine on the downloaded binary:
|
||||
xattr -d com.apple.quarantine ./kei-mcp-server 2>/dev/null || true
|
||||
./kei-mcp-server --stdio
|
||||
```
|
||||
|
||||
Every asset has a matching `<name>.sha256` for integrity verification. Build details and local cross-compile recipes: `_ts_packages/packages/mcp-server/BUILD.md`.
|
||||
|
||||
If you drop the binary at `~/.claude/agents/_primitives/_rust/target/release/kei-mcp-server-<os>-<arch>[.exe]` (the same layout `install.sh` uses for Rust primitives), re-running `install.sh` will detect it and skip any bun/npm build step. Set `KEI_SKIP_MCP_BUILD=1` to force-skip that step regardless of detection.
|
||||
|
||||
## Runtime hook controls
|
||||
|
||||
Every kit-shipped hook (v0.14.2+) honours two env vars so you can silence noise or isolate a failure without editing `~/.claude/settings.json`:
|
||||
|
|
|
|||
52
_ts_packages/packages/mcp-server/BUILD.md
Normal file
52
_ts_packages/packages/mcp-server/BUILD.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Building a single-binary `kei-mcp-server`
|
||||
|
||||
> KeiSeiKit v0.18 Phase 1 (exobrain) — ship the MCP server as a portable
|
||||
> static binary so any machine without Node can run it off a USB drive.
|
||||
|
||||
## Tooling
|
||||
|
||||
Compile via **bun** (`bun build --compile`). Bundles the Bun runtime + JS
|
||||
into one static executable — no Node, no `node_modules/` at runtime.
|
||||
Requires bun `>= 1.0`. Docs (target list + flags):
|
||||
[VERIFIED: https://bun.sh/docs/bundler/executables]
|
||||
|
||||
## Supported targets
|
||||
|
||||
| Platform | Arch | `--target=` | Output name |
|
||||
|----------|-------|------------------------|---------------------------------------|
|
||||
| Linux | x64 | `bun-linux-x64` | `kei-mcp-server-linux-x64` |
|
||||
| Linux | arm64 | `bun-linux-arm64` | `kei-mcp-server-linux-arm64` |
|
||||
| macOS | x64 | `bun-darwin-x64` | `kei-mcp-server-darwin-x64` |
|
||||
| macOS | arm64 | `bun-darwin-arm64` | `kei-mcp-server-darwin-arm64` |
|
||||
| Windows | x64 | `bun-windows-x64` | `kei-mcp-server-windows-x64.exe` |
|
||||
|
||||
## Local build
|
||||
|
||||
```bash
|
||||
cd _ts_packages/packages/mcp-server
|
||||
bun install
|
||||
bun run build:native # host-native
|
||||
bun run build:native:darwin-arm64 # explicit cross-target
|
||||
```
|
||||
|
||||
Output lands in `dist/`. Size ~85–95 MB per binary (bundled runtime).
|
||||
|
||||
## Release build (CI)
|
||||
|
||||
`.github/workflows/release.yml` → job `build-mcp-binary` runs the 5-target
|
||||
matrix on tag push (`v*`) and attaches binaries + `.sha256` sums to the
|
||||
GitHub release. Runtime requirement: **none** (static).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **macOS Gatekeeper (“cannot be opened because Apple cannot check it for
|
||||
malicious software”)** — remove the quarantine attribute:
|
||||
`xattr -d com.apple.quarantine ./kei-mcp-server-darwin-arm64`
|
||||
- **Windows SmartScreen / AV flags** — not signed; right-click →
|
||||
Properties → Unblock, or add an AV exclusion for the binary path.
|
||||
- **Missing symbol at startup** — usually a native-only dep that resolved
|
||||
at runtime on Node but cannot be bundled. Re-run `bun install`, then
|
||||
`bun build --compile ... --smol` to surface the resolution error.
|
||||
- **`.js` ESM imports fail** — the mcp-server source imports via `.js`
|
||||
suffix (ESM canonical). Bun resolves these from the sibling `.ts`
|
||||
file automatically; no `tsc` pre-step needed.
|
||||
|
|
@ -20,7 +20,13 @@
|
|||
"scripts": {
|
||||
"build": "tsc -b",
|
||||
"test": "vitest run",
|
||||
"dev": "tsx src/index.ts --stdio"
|
||||
"dev": "tsx src/index.ts --stdio",
|
||||
"build:native": "bun build --compile src/index.ts --outfile dist/kei-mcp-server",
|
||||
"build:native:linux-x64": "bun build --compile --target=bun-linux-x64 src/index.ts --outfile dist/kei-mcp-server-linux-x64",
|
||||
"build:native:linux-arm64": "bun build --compile --target=bun-linux-arm64 src/index.ts --outfile dist/kei-mcp-server-linux-arm64",
|
||||
"build:native:darwin-x64": "bun build --compile --target=bun-darwin-x64 src/index.ts --outfile dist/kei-mcp-server-darwin-x64",
|
||||
"build:native:darwin-arm64": "bun build --compile --target=bun-darwin-arm64 src/index.ts --outfile dist/kei-mcp-server-darwin-arm64",
|
||||
"build:native:windows-x64": "bun build --compile --target=bun-windows-x64 src/index.ts --outfile dist/kei-mcp-server-windows-x64.exe"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.0.0",
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@
|
|||
# Requires: say / warn from lib-log.sh.
|
||||
# Reads globals: $AGENTS_DIR, $KIT_DIR.
|
||||
# Honours env: $KEI_SKIP_RUST_BUILD (1 = force-skip cargo build).
|
||||
# Honours env: $KEI_SKIP_MCP_BUILD (1 = force-skip mcp-server bun compile;
|
||||
# also set automatically when a prebuilt
|
||||
# single-binary is detected via
|
||||
# have_prebuilt_mcp_server).
|
||||
|
||||
# Echo rust crates currently installed (by scanning .installed + MANIFEST).
|
||||
installed_rust_crates() {
|
||||
|
|
@ -112,3 +116,50 @@ regenerate_rust_workspace() {
|
|||
done <<< "$members_nl"
|
||||
say " $built / $n Rust primitive binaries available"
|
||||
}
|
||||
|
||||
# --- mcp-server single-binary detection (v0.18 Phase 1 / exobrain) ----------
|
||||
# Analog of have_prebuilt_binaries for the TS @keisei/mcp-server package,
|
||||
# which is distributable as a `bun build --compile` single binary.
|
||||
#
|
||||
# Contract: returns 0 iff a matching pre-built binary is present at
|
||||
# $AGENTS_DIR/_primitives/_rust/target/release/kei-mcp-server-<os>-<arch>[.exe]
|
||||
# (reusing the target/release directory so install.sh only has to lay down
|
||||
# one staging dir from the release tarball). Release workflow puts the bare
|
||||
# binary there; install.sh can then skip any bun/npm install entirely.
|
||||
#
|
||||
# Host classification: linux | darwin | windows vs x64 | arm64.
|
||||
# Unsupported combos (e.g. freebsd, x86) return 1 — no attempt made.
|
||||
have_prebuilt_mcp_server() {
|
||||
local target_dir="$AGENTS_DIR/_primitives/_rust/target/release"
|
||||
local uname_s uname_m os arch ext bin
|
||||
uname_s="$(uname -s 2>/dev/null || echo unknown)"
|
||||
uname_m="$(uname -m 2>/dev/null || echo unknown)"
|
||||
case "$uname_s" in
|
||||
Linux) os=linux; ext='' ;;
|
||||
Darwin) os=darwin; ext='' ;;
|
||||
MINGW*|MSYS*|CYGWIN*) os=windows; ext='.exe' ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
case "$uname_m" in
|
||||
x86_64|amd64) arch=x64 ;;
|
||||
arm64|aarch64) arch=arm64 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
bin="$target_dir/kei-mcp-server-${os}-${arch}${ext}"
|
||||
[ -x "$bin" ] || return 1
|
||||
echo "$bin"
|
||||
}
|
||||
|
||||
# Consult KEI_SKIP_MCP_BUILD + pre-built detection; emit a one-line status.
|
||||
# Intentionally does NOT run bun/npm — install.sh has no TS build step today;
|
||||
# this is the hook to grow into one later without touching the call sites.
|
||||
report_mcp_server_binary_status() {
|
||||
if [ "${KEI_SKIP_MCP_BUILD:-0}" = "1" ]; then
|
||||
say " KEI_SKIP_MCP_BUILD=1 — skipping mcp-server single-binary build"
|
||||
return 0
|
||||
fi
|
||||
local bin
|
||||
if bin="$(have_prebuilt_mcp_server)"; then
|
||||
say " pre-built mcp-server binary detected: $bin"
|
||||
fi
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue