@invokta/installer
@invokta/installer is a binary-only terminal application that detects
supported MCP clients, updates their user configuration, and keeps enough local
state to manage only the entries it owns. It never invokes an Action Engine.
The shortest path is generated with every starter engine:
npm create invokta-engine@latest my-enginecd my-enginenpm run mcp:install# Later, remove the same logical engine from every managed client:npm run mcp:uninstallmcp:install builds the engine, validates its local installation manifest,
preselects every eligible client, and requests one confirmation before any
write.
Install
Section titled “Install”The generated project already includes the installer. Add it manually to an existing engine when needed:
npm install --save-dev @invokta/installerThe package is native ESM, requires Node.js 22.20.0 or later, and publishes
the invokta-installer binary plus one embeddable subpath export,
@invokta/installer/engine.
The package root exports no JavaScript API.
The bundled capability registry may remain empty. Explicit local-engine and remote-HTTP commands supply their own reviewed descriptors; new managed state persists the launch descriptor required for later lifecycle operations.
All interactive commands require both standard input and standard output to be attached to a TTY. Help and version output do not require a TTY.
Commands
Section titled “Commands”invokta-installerinvokta-installer install --engine <project-directory>invokta-installer install --http <server-name> <url> [--bearer-token-env <NAME>] [--header-env <HEADER=NAME>]...invokta-installer statusinvokta-installer enableinvokta-installer disableinvokta-installer removeinvokta-installer remove --engine <project-directory>invokta-installer --helpinvokta-installer --versionThe argument-free command remains a read-only inventory. It shows detected client evidence, safe configuration paths, and reload guidance without reading configuration contents or changing files.
Install a local Action Engine
Section titled “Install a local Action Engine”invokta-installer install --engine .The directory must contain a built entry point and invokta.mcp.json. A
generated project provides the build-first package script below, which is the
recommended interface:
{ "scripts": { "mcp:install": "tsc -p tsconfig.json --pretty false && invokta-installer install --engine .", "mcp:uninstall": "invokta-installer remove --engine ." }}The manifest is strict UTF-8 JSON with this closed version-one shape:
{ "schemaVersion": 1, "id": "support-engine", "version": "0.1.0", "title": "Support Engine", "description": "Classify and route support tickets.", "capabilityIds": ["support.classify-ticket"], "server": { "name": "support-engine", "entrypoint": "dist/mcp-stdio.js", "forwardEnv": ["SUPPORT_API_TOKEN"] }}The manifest declares only metadata, a project-relative entry point, and environment variable names. It cannot choose an arbitrary command or persist an environment value. The installer validates owned, no-follow path components and the built regular file, then records the current Node executable and absolute entry-point path. It does not import, reflect on, or execute project code.
Moving or deleting the project invalidates the recorded launch descriptor. Build and install again from the new location to update it explicitly.
The uninstall script is intentionally build-free. It validates the project
manifest but does not require the compiled entry point, recorded Node
executable, forwarded environment variables, or an installed client executable.
The manifest id selects the same logical engine across every managed target;
project location and mutable manifest metadata are not provenance.
Embed install commands in an engine binary
Section titled “Embed install commands in an engine binary”A packaged engine can ship its own installation command instead of asking the
consumer to locate the package directory. Generated Invokta starters remain
private by default, so registry publication requires an explicit author choice
of package access and license metadata plus removal of "private": true. The
@invokta/installer/engine subpath exports runEngineInstallerCli, which
accepts exactly install, uninstall, and --help and runs the same
engine-scoped interactive sessions against the embedding package root:
#!/usr/bin/env nodeimport { fileURLToPath } from "node:url";
import { runEngineInstallerCli } from "@invokta/installer/engine";
process.exitCode = await runEngineInstallerCli({ argv: process.argv.slice(2), binaryName: "support-engine", packageRoot: fileURLToPath(new URL("..", import.meta.url)),});With a package bin entry pointing at the compiled module, the consumer runs:
npm install --global support-enginesupport-engine install# Later:support-engine uninstallGenerated MCP stdio projects include this composition root, the bin entry,
and @invokta/installer as a runtime dependency. The embedded surface keeps
the manifest contract, TTY requirement, confirmations, diagnostics, and exit
statuses of the standalone commands, and it never builds, downloads, imports,
or executes the engine.
Install a remote HTTP server
Section titled “Install a remote HTTP server”Register an existing Streamable HTTP endpoint directly:
invokta-installer install --http support-engine https://support.example.com/mcp \ --bearer-token-env SUPPORT_API_TOKEN \ --header-env X-Support-Tenant=SUPPORT_TENANTThis command performs no network request. The URL must be canonical HTTPS with
a canonical MCP mount path: /mcp or an unreserved ASCII prefix ending in /mcp,
with no empty or dot segments and at most 256 bytes. For example:
invokta-installer install --http brain http://127.0.0.1:3100/e/brain/mcpLiteral 127.0.0.1 and [::1] HTTP origins are accepted for local development.
User information, query strings, fragments, embedded credentials, percent encoding,
and other noncanonical paths are rejected.
Mounted paths require installer 0.8.2 or later (ADR 0040). Version 0.8.1
and earlier accept only /mcp. To select the compatible release explicitly:
npx @invokta/installer@0.8.2 install --http brain http://127.0.0.1:3100/e/brain/mcpThe installer registers the URL; the selected client handles OAuth when it connects.
Authentication and header options name environment variables; they never read
or persist their values. --header-env may be repeated. Header names are
normalized and duplicate, reserved, or conflicting authorization headers fail
closed.
Selection and confirmation
Section titled “Selection and confirmation”An installation includes targets that have either a safely discovered user configuration or an installed client executable. A missing configuration file may be created only when executable evidence exists. Compatibility checks then remove clients that cannot represent the requested transport or environment references.
All remaining targets are preselected. You may change the selection, then one confirmation authorizes the complete set of per-client transactions. A failure in one client is reported independently and does not undo a different client that already committed. Repeating the same installation is idempotent.
Manage installations
Section titled “Manage installations”status is read-only and reports installer-managed entries as enabled,
disabled, outdated, drifted, unavailable, or missing their runtime requirement.
enable and disable present only eligible managed entries, select one
interactively, and require confirmation. Disable uses the client’s native toggle
when available and otherwise detaches the server definition while retaining its
descriptor in installer state. Enable restores the exact managed definition.
Remove several installations
Section titled “Remove several installations”remove lets you select one or more managed installations, including a remote
engine such as brain across several clients:
invokta-installer removeNo entries are preselected. Use the arrow keys to move, Space to select an entry, or A to select all eligible entries. Press Enter to review the selected engine/client pairs, then confirm once. Removal deletes only those owned server entries and state records, preserving other installations and the surrounding client configuration. It reports each result and continues if an individual removal fails; successful removals remain committed.
Multiple selection requires installer 0.9.0 or later (ADR 0041). Version 0.8.2 and earlier select one entry at a time. To use the release with multiple removal:
npx @invokta/installer@0.9.0 removeAn entry changed outside the installer is drift and is never overwritten or removed automatically. A different server using the same name is a conflict.
remove --engine <project-directory> is the project-scoped overload. It
preflights every state record matching the manifest ID in stable target order,
shows removable and blocked clients, and requests one confirmation for the
complete removable set. Each target remains an independent transaction, so a
failure stays unchanged without rolling back a different target that already
committed. Repeating a successful removal is an idempotent no-op.
Every removable record must contain its persisted launch descriptor. Legacy
records without one remain unavailable, and this command never reconstructs
ownership metadata from the current manifest or bundled registry. A record
using the manifest’s current server name under another identity fails the whole
preflight as ENGINE_IDENTITY_MISMATCH before confirmation or writes.
Supported targets
Section titled “Supported targets”The catalog recognizes twelve executable surfaces mapped to eleven user-scope configuration targets:
| Target | Executable evidence | Default user configuration |
|---|---|---|
| Antigravity | agy or antigravity |
~/.gemini/config/mcp_config.json or an established ~/.gemini/antigravity/mcp_config.json |
| Claude Code | claude |
~/.claude.json |
| Claude Desktop | Claude |
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json |
| Codex | codex |
~/.codex/config.toml |
| Cursor | cursor or cursor-agent |
~/.cursor/mcp.json |
| Grok Build | grok |
~/.grok/config.toml |
| Hermes Agent | hermes |
~/.hermes/config.yaml |
| Kimi Code | kimi |
~/.kimi-code/mcp.json |
| OpenClaw | openclaw |
Its supported home or state directory |
| OpenCode v2 | opencode2 |
~/.config/opencode/opencode.json or .jsonc |
| Visual Studio Code | code |
Linux: ~/.config/Code/User/mcp.json; macOS: ~/Library/Application Support/Code/User/mcp.json; remote server: its data/User/mcp.json |
Antigravity CLI and IDE share one target. Cursor’s executable aliases also share one target. Claude Desktop mutation is macOS-only; it is unsupported on Linux and Windows, and VS Code mutation is unsupported on Windows because both clients use platform-specific configuration locations there.
Antigravity path selection is finite and fail-closed. One populated safe global
configuration wins over an empty sibling, two populated variants report
HARNESS_CONFIG_AMBIGUOUS, and a selected empty placeholder is initialized as
a new server collection. The installer does not read configuration contents
during detection.
When code resolves inside the exact VS Code Server or VS Code Server Insiders
remote-cli layout, the installer writes the matching server-side remote user
configuration. It does not infer a Windows host profile or add project,
workspace, or named-profile configuration. If a previous Invokta release
managed the same engine and target at the native Linux path, the next confirmed
install removes that exact owned definition and installs it at the remote path.
On Windows, where no POSIX user id exists, the installer validates paths with a Windows ownership identity (ADR 0027): symbolic links and junctions are rejected, path identities are captured and revalidated before every write, and containment inside the user profile is preserved, so a globally installed engine package such as one under the npm global root installs and removes normally. Exact POSIX file modes are not asserted on Windows; directory confinement follows the user profile’s access-control lists.
VS Code uses its JSONC servers object and ${env:NAME} variables. Claude
Desktop uses the JSON mcpServers object for credential-free local stdio
servers. Its file contract cannot safely express forwarded environment names,
and remote servers must be added through Claude’s connector interface, so those
descriptors are filtered out for this target. Existing comments, trailing
commas, unrelated servers, byte-order marks, newline conventions, and safe file
modes are preserved according to each target contract.
Established client-specific path overrides remain supported, including
CLAUDE_CONFIG_DIR, CODEX_HOME, GROK_HOME, HERMES_HOME,
KIMI_CODE_HOME, OPENCODE_CONFIG_DIR, XDG_CONFIG_HOME, and the documented
OpenClaw variables.
Transaction and state boundary
Section titled “Transaction and state boundary”Each selected target is one transaction. The installer acquires bounded state and configuration locks, revalidates ownership and contents, atomically replaces the configuration, then atomically replaces its state. If the state commit fails, it restores the exact configuration pre-image. A rollback failure is reported explicitly for manual inspection.
State defaults to ~/.local/state/invokta/installer.json and honors an absolute
XDG_STATE_HOME. It contains normalized launch structure, environment variable
names, ownership fingerprints, and timestamps. It contains no environment
values or configuration-file copies.
The installer makes no network request, package import, engine invocation, or shell execution while detecting or mutating clients. Diagnostics omit rejected values, configuration bytes, credentials, causes, and stacks.
Exit behavior
Section titled “Exit behavior”| Code | Meaning |
|---|---|
0 |
Help, version, inventory, installation, management, or an idempotent result succeeded |
1 |
An operational validation, compatibility, lock, conflict, drift, write, or rollback failure occurred |
2 |
Usage was invalid, a TTY was unavailable, or initialization failed |
130 |
The user cancelled an interactive prompt |
Installer diagnostics use stable installer-specific codes. They are not
EngineError values and do not extend the seven capability invocation errors.
Public package surface
Section titled “Public package surface”{ "exports": {}, "bin": { "invokta-installer": "./dist/cli.js" }}Registry parsers, target adapters, ownership planners, state transitions, locks, and filesystem primitives are internal implementation details.