Skip to content

Install

A compatible MCPB host can import guildcontrol-0.1.2.mcpb from the immutable GitHub Release or the MCP Registry. The cross-platform manifest requires Node.js 22 through 26, asks for one existing strict configuration file as non-secret input, and asks for the bot token through one sensitive input. The launcher maps that token only to the exact environment variable named by the selected policy, removes the bundle-only input before server startup, and never persists it. It deliberately refuses a file-backed credential policy; use the generated host adapter or OCI secret-volume path when protected-file custody is required.

The bundle embeds its privacy policy, deterministic SPDX inventory, exact dependency notices, credential-free catalog evidence, and a single self-contained ESM server. Its verifier builds twice, checks exact ZIP structure and metadata, compares bytes, scans every entry for secrets and non-neutral branding, validates the embedded evidence, unpacks to a fresh directory, and completes a real MCP initialization and catalog handshake. Verify the downloaded file against its SHA256SUMS entry and GitHub Release attestation before import.

After a release is published, run an exact version from npm:

Terminal window
npx --yes guildcontrol@0.1.2 help

Pinning the version keeps the executable stable across restarts. The MCP Registry manifest uses the same exact npm version.

Operational and credential-free catalog connections advertise the same complete public MCP server identity during initialization: machine name, display title, exact release version, description, repository website, and one release-tagged HTTPS PNG icon with its media type and intrinsic size. No credential, local path, policy, profile, or Discord identity enters this metadata. The server does not fetch the icon, and its operation does not depend on client presentation behavior.

The same exact release is available as a multi-architecture OCI image for linux/amd64 and linux/arm64. Its default command is the credential-free catalog, so merely starting the image does not contact Discord:

Terminal window
docker run --rm -i \
--network=none \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges:true \
--pids-limit=64 \
ghcr.io/j-256/guildcontrol:0.1.2 catalog --check

For an operational read-only connection, create one verified non-secret policy file on the host, then mount it read-only and supply only the caller-owned token. The container needs outbound network access to Discord, but it needs no writable root filesystem or Linux capability:

Terminal window
export DISCORD_BOT_TOKEN
printf 'Discord bot token: '
read -r -s DISCORD_BOT_TOKEN
printf '\n'
npx --yes guildcontrol@0.1.2 setup \
--npx \
--config ./guildcontrol.json \
--preset server-observer \
--guild-id YOUR_GUILD_ID
docker run --rm -i \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges:true \
--pids-limit=64 \
--env DISCORD_BOT_TOKEN \
--mount "type=bind,source=$PWD/guildcontrol.json,target=/configuration/guildcontrol.json,readonly" \
ghcr.io/j-256/guildcontrol:0.1.2 serve --config /configuration/guildcontrol.json

For a Docker or Kubernetes secret volume, create the policy with credential.provider set to file and credential.path set to the exact in-container path such as /run/secrets/discord_bot_token, then mount both the policy and secret read-only. The projected target must be owned by root or the image's node user, must not be group or world writable, and must have one hard link; the common root-owned read-only secret-volume shape passes this boundary. A projected-secret symlink is accepted so atomic orchestrator rotation works without broadening ordinary config-file link policy.

The image contains only the compiled server, production dependencies, package metadata, and license. It runs as the unprivileged node user, embeds no connector configuration, and never stores the supplied token. The Registry manifest encodes the same read-only root, dropped capabilities, process limit, config mount, fixed in-container path, and explicit serve command so OCI installation does not fall back to catalog mode.

For development from source:

Terminal window
npm run deps:locked
npm run typecheck
npm test
npm run build

The source build's public CLI launcher is dist/bin.js; dist/cli.js is its internal executable module. The package's dist/index.js is its import-only library entrypoint; executing it directly fails with a fixed credential-free correction to use guildcontrol serve --config FILE or node dist/bin.js serve --config FILE instead of closing silently during MCP initialization. The npm and source CLI launchers select serve when no command is supplied, then fail closed unless a configuration file or schema-v2 profile is selected. The OCI image deliberately defaults to the safe catalog and requires an explicit serve command plus its mounted configuration for Discord access.

The public launcher favors lower resident memory by starting verified Node 22 through 26 lines with V8's --lite-mode before connector code loads. That profile disables WebAssembly; the connector and its pinned dependencies require none, and Discord work is normally network-bound, so the principal tradeoff is lower execution throughput. Node 22 and 23 descriptors also pass --no-expose-wasm to suppress those lines' conflicting-default warning, while Node 24 through 26 reject the obsolete flag and receive only --lite-mode. Unknown future lines continue through the standard profile until the optimization is release-verified. MCPB uses the universal flag and therefore declares the exact >=22 <27 range; its single static argument list means Node 22 and 23 emit one expected V8 compatibility warning before readiness, and bundle verification rejects any other stderr. The Node-22-pinned OCI image uses both flags. Smoke and generated direct-Node descriptors select the exact version-compatible profile themselves. On runtimes that expose POSIX process replacement, a bare or npx package launch replaces its tiny bootstrap in the same PID while preserving standard streams, Node arguments, CLI arguments, and the inherited environment; runtimes without that facility continue through the standard profile. Use guildcontrol --standard-runtime COMMAND when CPU throughput is more important than the memory profile. Custom --command launchers are never assumed to be Node and receive no injected runtime flags.

Canonical source: docs/reference.md

Documentation generated for guildcontrol@0.0.0. Canonical source and edit history remain in the public repository. GuildControl is an independent project and is not affiliated with or endorsed by Discord Inc. Discord is used only to identify the platform that GuildControl connects to.