metamcp: package v2.4.22 as a NixOS-deployable service
Single-derivation pnpm/Turbo monorepo build producing:
- metamcp full orchestrator (waits for PG, runs drizzle
migrations, launches backend :12009 + frontend :12008)
- metamcp-backend bare backend launcher
- metamcp-frontend Next.js standalone server.js launcher
Notes:
- Upstream pins packageManager: pnpm@9.0.0; rewrite to match the nixpkgs
pnpm (Turbo requires the field but won't fight a matching version).
- Frontend uses next.config 'output: standalone'; we copy .next/static
and public/ into the standalone tree since Next doesn't.
- HOSTNAME defaults to 0.0.0.0 (override with METAMCP_HOSTNAME) — Next
standalone otherwise inherits the system hostname and is unreachable
on 127.0.0.1.
This commit is contained in:
@@ -57,6 +57,7 @@
|
||||
{
|
||||
hello-world = pkgs.callPackage ./packages/hello-world.nix { };
|
||||
geesefs = pkgs.callPackage ./packages/geesefs.nix { };
|
||||
metamcp = pkgs.callPackage ./packages/metamcp.nix { };
|
||||
xonsh = pkgs.callPackage ./packages/xonsh.nix {
|
||||
xonsh-unwrapped = import ./packages/xonsh-unwrapped.nix {
|
||||
inherit (pkgs) lib python3Packages fetchFromGitHub;
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
makeWrapper,
|
||||
nodejs_20,
|
||||
pnpm_10,
|
||||
fetchPnpmDeps,
|
||||
pnpmConfigHook,
|
||||
postgresql,
|
||||
}:
|
||||
|
||||
# MetaMCP — MCP aggregator/orchestrator.
|
||||
#
|
||||
# Upstream is a pnpm monorepo (Turbo) with two apps:
|
||||
# - apps/backend : Express/tRPC API, built with tsup -> dist/index.js
|
||||
# port 12009 (internal), runs drizzle-kit migrations at boot
|
||||
# - apps/frontend : Next.js 15, port 12008 (public), launched via `next start`
|
||||
#
|
||||
# Both require runtime node_modules (Next.js non-standalone; drizzle-kit is
|
||||
# a devDep invoked at runtime by docker-entrypoint.sh). We ship the whole
|
||||
# built tree under $out/lib/metamcp and provide launcher scripts.
|
||||
#
|
||||
# The upstream Dockerfile patches Next.js' proxy timeout (30s -> 600s) by
|
||||
# sed-editing two files inside node_modules/.pnpm/next@.../...; we replicate
|
||||
# that in postBuild so the behaviour matches the official image.
|
||||
#
|
||||
# Build is single-derivation: pnpm fetch -> pnpm build -> install. First
|
||||
# build prints the right pnpmDeps hash; paste it back here and rebuild.
|
||||
|
||||
let
|
||||
pname = "metamcp";
|
||||
version = "2.4.22";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "metatool-ai";
|
||||
repo = "metamcp";
|
||||
rev = "v${version}";
|
||||
hash = lib.fakeHash; # nix build will print the right one
|
||||
};
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
inherit pname version src;
|
||||
|
||||
pnpmDeps = fetchPnpmDeps {
|
||||
inherit pname version src;
|
||||
fetcherVersion = 3;
|
||||
hash = lib.fakeHash; # nix build will print the right one
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
nodejs_20
|
||||
pnpm_10
|
||||
pnpmConfigHook
|
||||
makeWrapper
|
||||
];
|
||||
|
||||
# pnpmConfigHook places node_modules; build the workspace with Turbo.
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
# Match the upstream Dockerfile sed-patch on Next.js proxy timeout.
|
||||
# Files live under the pnpm virtual store; glob to tolerate minor
|
||||
# next/react version bumps on later tags.
|
||||
for f in \
|
||||
node_modules/.pnpm/next@*/node_modules/next/dist/server/lib/router-utils/proxy-request.js \
|
||||
node_modules/.pnpm/next@*/node_modules/next/dist/esm/server/lib/router-utils/proxy-request.js; do
|
||||
if [ -f "$f" ]; then
|
||||
sed -i -e "s/30000/600000/" "$f"
|
||||
fi
|
||||
done
|
||||
|
||||
pnpm build
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p $out/lib/metamcp $out/bin
|
||||
|
||||
# Ship the whole built workspace. This is bulky but reliable:
|
||||
# `next start` needs .next + node_modules + package.json side-by-side,
|
||||
# and the backend's runtime invokes `pnpm exec drizzle-kit migrate`.
|
||||
cp -r \
|
||||
apps \
|
||||
packages \
|
||||
node_modules \
|
||||
package.json \
|
||||
pnpm-workspace.yaml \
|
||||
pnpm-lock.yaml \
|
||||
turbo.json \
|
||||
docker-entrypoint.sh \
|
||||
$out/lib/metamcp/
|
||||
|
||||
# Sanitise the entrypoint: drop the hard-coded `cd /app/...` paths,
|
||||
# set our launch root via $METAMCP_ROOT, keep the orchestration logic.
|
||||
substituteInPlace $out/lib/metamcp/docker-entrypoint.sh \
|
||||
--replace-fail "/app" "$out/lib/metamcp"
|
||||
|
||||
# Launcher: identical sequence to docker-entrypoint.sh, with PATH
|
||||
# carrying pg_isready (for the readiness wait) and node.
|
||||
cat > $out/bin/metamcp <<EOF
|
||||
#!${stdenv.shell}
|
||||
export METAMCP_ROOT=$out/lib/metamcp
|
||||
export PATH=${
|
||||
lib.makeBinPath [
|
||||
nodejs_20
|
||||
pnpm_10
|
||||
postgresql # for pg_isready
|
||||
]
|
||||
}:\$PATH
|
||||
cd \$METAMCP_ROOT
|
||||
exec ${stdenv.shell} \$METAMCP_ROOT/docker-entrypoint.sh "\$@"
|
||||
EOF
|
||||
chmod +x $out/bin/metamcp
|
||||
|
||||
# Direct sub-launchers (handy for systemd "two-unit" deployments if
|
||||
# you ever want to skip the bundled orchestrator).
|
||||
makeWrapper ${nodejs_20}/bin/node $out/bin/metamcp-backend \
|
||||
--add-flags "$out/lib/metamcp/apps/backend/dist/index.js" \
|
||||
--set NODE_ENV production
|
||||
|
||||
cat > $out/bin/metamcp-frontend <<EOF
|
||||
#!${stdenv.shell}
|
||||
export PATH=${lib.makeBinPath [ nodejs_20 pnpm_10 ]}:\$PATH
|
||||
cd $out/lib/metamcp/apps/frontend
|
||||
exec pnpm start "\$@"
|
||||
EOF
|
||||
chmod +x $out/bin/metamcp-frontend
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
# The pnpm/turbo build writes into $HOME; give it a writable one.
|
||||
preBuild = ''
|
||||
export HOME=$TMPDIR
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "MetaMCP — MCP aggregator, orchestrator, middleware, gateway";
|
||||
homepage = "https://github.com/metatool-ai/metamcp";
|
||||
license = lib.licenses.mit;
|
||||
mainProgram = "metamcp";
|
||||
platforms = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
];
|
||||
};
|
||||
})
|
||||
Reference in New Issue
Block a user