Enterprise install
The fleet-deployment path for the Agent Keeper MCP Gateway. Written for IT and platform teams rolling the gateway out to 10+ laptops via a configuration-management tool. If you are an individual developer trying the gateway on your own machine, use the one-line install instead.
Design stance
Pin <version, sha256> and fetch directly from GitHub Releases. Do not use the one-line install script in a fleet context. The install script is a convenience UX for interactive developers; the enterprise path is reproducible, versioned, and independently verifiable.
| Concern | How this path addresses it |
|---|---|
| Supply-chain integrity | Pin a specific <version, sha256> per release. Fetch from GitHub Releases. Optionally verify cosign signature at pin time. |
| Reproducibility | Same archive + checksum on every laptop, every run of the config-management recipe. |
| Offline survivability | Checksum verification happens locally; no runtime dependency on YOUR_AGENTKEEPER_URL or the install script. |
| Rollback | Change the pinned version in your recipe and reapply. Never retag, every fix is a new patch version. |
| No per-developer variance | Config dropped at /etc/agentkeeper-mcp-gateway/config.json. No $HOME assumptions. |
Recipe (generic shell pseudocode)
#!/usr/bin/env bash
set -euo pipefail
# Pin these at rollout time. Rotate by changing both values together.
VERSION="v0.1.1"
SHA256_LINUX_AMD64="<paste from checksums.txt at pin time>"
ARCHIVE="agentkeeper-mcp-gateway_linux_amd64.tar.gz"
BASE="https://github.com/rad-security/agentkeeper-mcp-gateway/releases/download/${VERSION}"
# 1. Download + verify.
curl -fsSLO "${BASE}/${ARCHIVE}"
echo "${SHA256_LINUX_AMD64} ${ARCHIVE}" | sha256sum -c -
# 2. Install.
tar -xzf "${ARCHIVE}"
install -m 0755 agentkeeper-mcp-gateway /usr/local/bin/agentkeeper-mcp-gateway
# 3. Drop config (rendered from your secret store).
install -d -m 0755 /etc/agentkeeper-mcp-gateway
install -m 0600 -o agentkeeper -g agentkeeper \
/path/to/rendered/config.json \
/etc/agentkeeper-mcp-gateway/config.json
The gateway resolves its config from /etc/agentkeeper-mcp-gateway/config.json automatically, no $HOME knowledge required. See the headless install section of the README for the full resolution chain.
Sample config.json
{
"mode": "audit",
"api_key": "ak_live_...",
"api_url": "https://YOUR_AGENTKEEPER_URL",
"detection": {
"threat": "warn",
"sensitive_data": "warn"
}
}
The api_key can alternatively be supplied via the AGENTKEEPER_API_KEY environment variable (set in the systemd unit, launchd plist, or per-user shell profile). File always wins when set. rotation happens by re-rendering the file from your secret store, not by shadowing it with an env var.
Verifying cosign signatures (optional, one-time per pin)
Every release's checksums.txt is signed by our GitHub Actions workflow via cosign keyless. Verifying once per version bump proves the artifact came from our real build pipeline:
BASE=https://github.com/rad-security/agentkeeper-mcp-gateway/releases/download/${VERSION}
curl -fsSLO "${BASE}/checksums.txt"
curl -fsSLO "${BASE}/checksums.txt.sig"
curl -fsSLO "${BASE}/checksums.txt.pem"
cosign verify-blob \
--certificate-identity-regexp "https://github.com/rad-security/agentkeeper-mcp-gateway/.github/workflows/release.yml@refs/tags/.*" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--signature checksums.txt.sig \
--certificate checksums.txt.pem \
checksums.txt
Successful verification binds the checksum file to a specific GitHub Actions workflow on a specific tag, the SHA-256 you pin in your recipe is covered by the same signature.
Zero-touch IDE wiring
Installing the gateway binary is step one. Step two is pointing each developer's IDE at the gateway so traffic actually flows through it, rewriting ~/.cursor/mcp.json, ~/.claude/settings.json, and ~/Library/Application Support/Claude/claude_desktop_config.json. Doing this by hand per engineer does not scale. The gateway ships a subcommand that does it for you:
agentkeeper-mcp-gateway configure-ide
What it does, per installed IDE:
- Backs up the existing config to
<path>.agentkeeper-backup-<unix-nanos> - Migrates any already-registered MCP servers into the gateway's own
servers[]array (env vars included) - Rewrites the IDE's
mcpServersmap to a single entry pointing atagentkeeper-mcp-gateway server - Preserves every non-MCP top-level key verbatim (
permissions,preferences, etc.)
It is idempotent, a second run on an already-wired config is a no-op, with no second backup. Safe to run from a login hook, postinstall script, or every Kandji reapply. Supports Claude Code, Claude Desktop (macOS + Linux), and Cursor. Windsurf is a separate hooks-based integration.
Kandji invocation pattern (per-user)
Kandji runs as root, so the recipe needs to resolve the logged-in user and invoke configure-ide as that user. Same pattern our Kandji doc uses for the Cowork MCP server deploy:
# macOS: resolve console user and run configure-ide on their behalf
CURRENT_USER=$(/usr/bin/stat -f%Su /dev/console)
if [ "$CURRENT_USER" != "loginwindow" ] && [ "$CURRENT_USER" != "root" ]; then
/usr/bin/sudo -u "$CURRENT_USER" /usr/local/bin/agentkeeper-mcp-gateway configure-ide
fi
# Linux: resolve active seat user and run as them
CURRENT_USER=$(loginctl list-sessions --no-legend | awk '$3=="seat0"{print $4; exit}')
if [ -n "$CURRENT_USER" ] && [ "$CURRENT_USER" != "root" ]; then
sudo -u "$CURRENT_USER" /usr/local/bin/agentkeeper-mcp-gateway configure-ide
fi
Run these as part of the same Kandji recipe that drops /etc/agentkeeper-mcp-gateway/config.json. Repeat on every reapply, the idempotency guarantee means no churn.
macOS per-user launchd agent (alternative)
For teams that prefer a user-session LaunchAgent over a root-invoked postinstall hook:
<!-- ~/Library/LaunchAgents/dev.agentkeeper.configure-ide.plist -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key> <string>dev.agentkeeper.configure-ide</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/agentkeeper-mcp-gateway</string>
<string>configure-ide</string>
</array>
<key>RunAtLoad</key> <true/>
<key>StandardOutPath</key> <string>/tmp/agentkeeper-configure-ide.log</string>
<key>StandardErrorPath</key><string>/tmp/agentkeeper-configure-ide.log</string>
</dict>
</plist>
Load with launchctl load ~/Library/LaunchAgents/dev.agentkeeper.configure-ide.plist, runs once per login.
Claude Code skill + MCP inventory (scan-inventory)
A third subcommand, available in v0.4.0+, captures the skills and MCP servers already installed in each developer's ~/.claude tree and reports them to the dashboard at YOUR_AGENTKEEPER_URL/claude-code/skills. This is what populates the "installed skills" and "installed MCP servers" tables per host, the same data the plugin reports, but emitted by the gateway binary instead of requiring a Claude Code plugin install.
agentkeeper-mcp-gateway scan-inventory
What it does:
- Walks
~/.claude/skills/*/SKILL.md(user-scoped),<cwd>/.claude/skills/*/SKILL.md(project-scoped), and plugin-installed skills via~/.claude/plugins/installed_plugins.json, with a cache glob fallback if the manifest is missing - Reads
mcpServersfrom~/.claude/settings.json,<cwd>/.claude/settings.json, and<cwd>/.claude/settings.local.json - POSTs a payload matching the plugin's format to
{api_url}/api/v1/claude-code/checkin
Flags: --dry-run prints the JSON body that would be sent without sending. --cwd <path> overrides the project directory when invoked outside a Claude Code hook. --claude-version <ver> sets the claude_version field when not supplied by the hook envelope on stdin.
Fail-open by design: exits 0 on success, 0 on network failure, non-zero only on a fatal config error. A SessionStart hook that calls this subcommand will never block a developer's Claude Code session.
Wiring into Claude Code SessionStart
The gateway binary replaces the older type: "http" SessionStart hook that POSTed directly to /api/v1/claude-code/checkin. The HTTP hook can't read the filesystem, so it delivered an empty inventory. scan-inventory fixes that.
{
"hooks": {
"SessionStart": [{
"matcher": "*",
"hooks": [{
"type": "command",
"command": "/usr/local/bin/agentkeeper-mcp-gateway scan-inventory",
"timeout": 30
}]
}]
}
}
For the full Kandji recipe that writes this hook alongside the PreToolUse / PostToolUse / UserPromptSubmit hooks, see Kandji deployment.
Linux per-user systemd unit (alternative)
# ~/.config/systemd/user/agentkeeper-configure-ide.service
[Unit]
Description=Wire IDE configs through the Agent Keeper gateway
After=default.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/agentkeeper-mcp-gateway configure-ide
[Install]
WantedBy=default.target
Enable with systemctl --user enable agentkeeper-configure-ide.service.
Sample systemd unit (Linux)
# /etc/systemd/system/agentkeeper-mcp-gateway.service
[Unit]
Description=Agent Keeper MCP Gateway
After=network-online.target
[Service]
Type=simple
User=agentkeeper
Group=agentkeeper
ExecStart=/usr/local/bin/agentkeeper-mcp-gateway server
Environment=AGENTKEEPER_CONFIG=/etc/agentkeeper-mcp-gateway/config.json
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Sample Ansible task
- name: Install Agent Keeper MCP Gateway
hosts: developer_laptops
vars:
ck_version: "v0.1.1"
ck_sha256_linux_amd64: "<pinned>"
tasks:
- name: Download gateway archive
get_url:
url: "https://github.com/rad-security/agentkeeper-mcp-gateway/releases/download/{{ ck_version }}/agentkeeper-mcp-gateway_linux_amd64.tar.gz"
dest: "/tmp/agentkeeper-mcp-gateway.tar.gz"
checksum: "sha256:{{ ck_sha256_linux_amd64 }}"
mode: "0644"
- name: Extract gateway binary
unarchive:
src: "/tmp/agentkeeper-mcp-gateway.tar.gz"
dest: "/usr/local/bin/"
remote_src: yes
extra_opts: ["--no-same-owner"]
- name: Render gateway config
template:
src: "agentkeeper-config.json.j2"
dest: "/etc/agentkeeper-mcp-gateway/config.json"
owner: agentkeeper
group: agentkeeper
mode: "0600"
notify: restart agentkeeper-mcp-gateway
handlers:
- name: restart agentkeeper-mcp-gateway
service:
name: agentkeeper-mcp-gateway
state: restarted
Sample Kandji pseudocode
VERSION="v0.1.1"
SHA256="<pinned at rollout time>"
download https://github.com/rad-security/agentkeeper-mcp-gateway/releases/download/${VERSION}/agentkeeper-mcp-gateway_linux_amd64.tar.gz
verify sha256 = ${SHA256}
extract /usr/local/bin/agentkeeper-mcp-gateway
render /etc/agentkeeper-mcp-gateway/config.json from secrets/agentkeeper (0600, owned by agentkeeper)
restart agentkeeper-mcp-gateway.service
Upgrading
Upgrade is the same recipe with a new VERSION + SHA256 pair. The gateway is a single binary with no in-place upgrade path of its own, your config-management tool controls rollout cadence.
Never retag a published version. Every bug fix is a new patch release (v0.1.2, v0.1.3, …). If you already rolled out a version that turned out to be broken, pin forward to the next patch, do not assume a previous pinned SHA-256 will still resolve if we ever had to pull a release.
Private mirrors
If your security review forbids downloading binaries from github.com, mirror the signed release artifacts into an internal package repository and keep the same version, checksum, and signature verification steps. Enterprise customers can also arrange a private Agent Keeper mirror during deployment planning.
Related
- One-line install, for individual developers trying the gateway on their own machine.
- MCP Gateway overview, what the gateway does and how to wire it into your IDE.