agent-mcp-host

One-origin MCP host for the agent-* CLI family

Language
Go
Version
0.6.3
License
PolyForm Perimeter 1.0.0
Category
CLI Tool

An MCP host that serves the whole agent-* CLI family from one machine, behind one domain, with one OAuth authorization server and a separate login per tool. Each family CLI keeps being a full MCP server in its own binary — the host mounts it behind a path rather than re-implementing it, owning only the shared front door, token minting, and the unified browser-facing pairing and enrollment pages. A person adds one Claude connector per tool; every call thereafter carries their identity.

Features

01

One origin for the whole family — every mounted agent-* CLI's MCP tools served from one domain, e.g. a single Tailscale funnel

02

One connector per tool, not one merged surface — /slack/mcp and /lin/mcp stay isolated, independently versioned and authorized

03

No URL to figure out — --tailscale funnel derives the public origin from MagicDNS and tears the tunnel down on exit

04

No separate step to start the tools — serve spawns each mounted binary in delegate mode with everything it needs injected

05

Attach mounts for when you want control — mount-env prints the exact launch command, then the host proxies to the process you started under a debugger or launchd

06

Single OAuth authorization server — the host owns pairing codes, named principals, token minting and the human-facing pages

07

Ed25519 AS/RS split — a delegate tool receives only the verify key, so it can validate tokens but never mint them

08

Per-tool audiences — a token minted for the Slack mount is useless at the Lin mount, by construction

09

Login once, grow into tools — a 30-day browser session covers identity, so adding tool N asks for no pairing code, only that tool's delta

10

Self-enrollment where a binding was not provisioned — the credential form's fields come from the tool's own mcp schema, and secrets reach it over stdin, never argv

11

Mounts by exec, not linking — the host discovers each tool via its MCP schema; no tool code is compiled in

12

Family-wide revocation — pair remove drops a person's pairing code, refresh tokens and browser sessions in one step

Install

Homebrew

>_
$ brew install shhac/tap/agent-mcp-host

AI Agent Skill

>_
$ npx skills add shhac/agent-skills --skill agent-mcp-host --global

GitHub Release (macOS)

>_
$ curl -L https://github.com/shhac/agent-mcp-host/releases/latest/download/agent-mcp-host-darwin-arm64.tar.gz | tar xz

Go Install

>_
$ go install github.com/shhac/agent-mcp-host/cmd/agent-mcp-host@latest

Build from Source

>_
$ git clone https://github.com/shhac/agent-mcp-host.git && cd agent-mcp-host && make build

Getting Started

agent-mcp-host is the operator's front door: one process runs the OAuth authorization server and reverse proxy, spawns each mounted family CLI as a loopback MCP server in delegate mode, and renders the shared pairing and enrollment pages. Install the tools you intend to mount; the host does the rest. Its signing key and pairing store live in the OS keychain.

01 · Provision a person

>_
$ agent-mcp-host pair add alice --bind slack:workspace=acme --bind lin:workspace=acme

Prints alice's pairing code — a secret, share it only with her. Bindings are namespaced per tool and both are optional: a tool that supports enrollment lets her enter credentials herself.

02 · Serve the family behind one origin

>_
$ agent-mcp-host serve --tailscale funnel --mount slack=agent-slack --mount lin=lin

With Tailscale there is no URL to work out. Otherwise pass --public-url https://hub.example and point your reverse proxy at the --http listener.

03 · She adds one connector per tool

>_
$ https://hub.tailnet.example/slack/mcp

She enters her pairing code once in the browser, and fills in that tool's credential form if no binding was provisioned. Adding /lin/mcp afterwards asks for no code — only lin's delta.

04 · Revoke in one place

>_
$ agent-mcp-host pair remove alice

Kills the pairing code, every per-tool refresh token, and her browser sessions together.

Usage

>_ Mount two family tools behind one funnel
$ agent-mcp-host serve --tailscale funnel --mount slack=agent-slack --mount lin=lin
>_ Mint a pairing code with per-tool bindings
$ agent-mcp-host pair add alice --bind slack:workspace=acme
>_ List named principals and their bindings
$ agent-mcp-host pair list
>_ Re-print a principal's pairing code
$ agent-mcp-host pair show alice
>_ Issue a fresh code, preserving bindings
$ agent-mcp-host pair rotate alice
>_ Run a tool yourself and proxy to it
$ agent-mcp-host mount-env lin=lin
>_ Check who the host thinks you are
$ agent-mcp-host whoami
>_ Revoke a person across every tool
$ agent-mcp-host pair remove alice