Search DevTools

Jump to any tool or page

Labby

Unexplored

Rust MCP gateway with Code Mode, authentication, setup, logs, CLI, HTTP API, and operator web UI.

dinglebear-ai5 stars2 forksBrowser & Web
View source

Install

Terminal

$npx -y @dinglebear/labby mcp

mcp_config.json

{
  "mcpServers": {
    "ai-dinglebear-labby": {
      "env": {
        "LABBY_LOG": "${LABBY_LOG}",
        "LABBY_REPO": "${LABBY_REPO}",
        "LABBY_VERSION": "${LABBY_VERSION}"
      },
      "args": [
        "-y",
        "@dinglebear/labby",
        "mcp"
      ],
      "command": "npx"
    }
  }
}

Documentation

Labby

Rust MCP gateway with Code Mode, authentication, setup, logs, CLI, HTTP API, and operator web UI.

Canonical remote: git@github.com:dinglebear-ai/labby.git.

The root README is the public entrypoint. The topic docs in docs/ own the detailed contracts; when this file and a topic doc disagree, fix the topic doc first and then refresh this summary.

Contents

What Labby Does

Labby is centered on the current gateway/operator surface:

  • MCP gateway - connect HTTP and stdio upstream MCP servers, inspect their tools/resources/prompts, apply exposure filters, publish protected MCP routes, and optionally collapse the upstream catalog into Code Mode search and execute.
  • Direct stdio proxy - launch one stdio MCP server with labby proxy /path/to/dist.js and expose its unmodified MCP surface over loopback or an owned Tailscale Serve HTTPS port with tailnet, bearer, OAuth, or explicit no-auth policy.
  • Authentication and protected routes - run bearer or OAuth authentication, manage route-scoped access, authorize upstream OAuth connections, and publish protected MCP endpoints.
  • Code Mode snippets - author, store, and run reusable JavaScript snippets against the upstream catalog, with artifacts persisted under $LABBY_HOME.
  • Setup and doctor - bootstrap ~/.labby, provision the host service, and run a health audit across env, reachability, auth, and versions.
  • Filesystem service - scoped, path-safety-checked file operations exposed through the same action dispatch as every other service.
  • Server logs - search and tail the local labby serve log stream.
  • Incus and bare-metal setup - provision and operate a dedicated Labby gateway host without introducing a separate fleet or deployment product.
  • Generated discovery - publish code-owned service, action, environment, proxy configuration, API route, OpenAPI, MCP help, CLI help, and feature-matrix artifacts under docs/generated.

Use the generated service, action, and CLI catalogs below for the complete current product surface instead of copying inventories into hand-written documentation. Standalone ACP chat, Marketplace/MCP Registry browser, Fleet, Deploy, and Stash products remain retired; bounded provider-backed discovery through the artifacts control-plane service does not restore those products.

Quick Start

Proxy One Stdio MCP Server

After installing Labby, configure proxy defaults once and launch a JavaScript stdio server without proxy flags:

labby setup proxy
labby doctor proxy
labby proxy /path/to/dist.js

The built-in zero-flag policy is Tailscale Serve plus tailnet authorization on a random high port. Child flags follow the first child token unchanged, and an explicit separator is available for unusual commands:

labby proxy /path/to/dist.js --workspace /srv/data --read-only
labby proxy -- npx -y @modelcontextprotocol/server-filesystem /srv/data

Use labby proxy --local --auth none ... for explicit loopback-only development. Bearer and OAuth setup, exact-port resource audiences, safe Serve ownership, configuration precedence, output modes, and recovery are covered in the stdio MCP proxy guide.

Install A Release

Linux/macOS:

version=vX.Y.Z
base="https://github.com/dinglebear-ai/labby/releases/download/$version"
curl -fSLO "$base/labby-install.sh"
curl -fSLO "$base/labby-install.sh.sha256"
gh attestation verify labby-install.sh \
  --repo dinglebear-ai/labby \
  --signer-workflow dinglebear-ai/labby/.github/workflows/release.yml \
  --source-ref "refs/tags/$version" \
  --deny-self-hosted-runners
shasum -a 256 -c labby-install.sh.sha256
LABBY_INSTALL_VERSION="$version" sh ./labby-install.sh
labby setup
labby serve --host 127.0.0.1 --port 8765

MCP clients that prefer npm launchers can run Labby through the Node wrapper:

npx -y @dinglebear/labby mcp

Windows PowerShell:

$Version = "vX.Y.Z"
$Base = "https://github.com/dinglebear-ai/labby/releases/download/$Version"
Invoke-WebRequest "$Base/labby-install.ps1" -OutFile labby-install.ps1
Invoke-WebRequest "$Base/labby-install.ps1.sha256" -OutFile labby-install.ps1.sha256
gh attestation verify labby-install.ps1 `
  --repo dinglebear-ai/labby `
  --signer-workflow dinglebear-ai/labby/.github/workflows/release.yml `
  --source-ref "refs/tags/$Version" `
  --deny-self-hosted-runners
$Expected = ((Get-Content labby-install.ps1.sha256) -split '\s+')[0]
if ((Get-FileHash labby-install.ps1 -Algorithm SHA256).Hash.ToLower() -ne $Expected) { throw "installer digest mismatch" }
$env:LABBY_INSTALL_VERSION = $Version
& ./labby-install.ps1
labby setup
labby serve --host 127.0.0.1 --port 8765

The separately downloaded and attested install scripts resolve an immutable GitHub Release containing the current platform asset, require gh, verify the archive's attestation against the Labby repository, release.yml, exact tag, and hosted-runner policy, verify its checksum, and install labby onto the user PATH. They do not perform operator provisioning or environment setup. The scripts only install the binary (from a release or fallback source build); all first-run provisioning is handled inside labby via labby serve bootstrap and labby setup.

Override install behavior with LABBY_INSTALL_DIR, LABBY_INSTALL_VERSION, or LABBY_INSTALL_REPO. Source fallback is off by default. Opt in with LABBY_ALLOW_SOURCE_FALLBACK=1; a pinned LABBY_INSTALL_VERSION is passed to Cargo as the exact tag instead of silently building the default branch.

Each successful install retains the verified binary by SHA-256 plus an owner-only receipt beneath <install-dir>/.labby-install/. At least the prior verified artifact remains available when distribution is unavailable. Restore it without downloading or changing $LABBY_HOME:

LABBY_INSTALL_ROLLBACK=1 sh ./labby-install.sh
$env:LABBY_INSTALL_ROLLBACK = '1'
& .\labby-install.ps1

Rollback switches only the installed executable and receipt. It does not downgrade or delete configuration, credentials, databases, or other durable state. Inspect the receipt at <install-dir>/.labby-install/receipt on Unix or receipt.json on Windows.

Release qualification can install an already-downloaded candidate without network or source fallback by setting LABBY_INSTALL_LOCAL_BINARY and its exact lowercase LABBY_INSTALL_LOCAL_SHA256. The installer copies that input once to private staging, verifies the staged bytes, and activates those same bytes. It also rehashes every existing cached artifact before reuse. Before changing the binary or either receipt, the installer writes a recovery journal beneath .labby-install/; a later invocation restores the complete pre-install snapshot when it finds an interrupted activation. If restoration fails, the installer stops and retains the journal for diagnosis.

Build From Source

Prerequisites:

  • Rust 1.97.1 or newer. CI/release verifies with Rust 1.97.1.
  • just for repo commands.
  • cargo-nextest for the main test suite.
  • pnpm 9.15.9 for the Labby web UI. The repo pins this in .mise.toml and apps/gateway-admin/package.json.
  • openssl if you want to generate a bearer token manually.
git clone git@github.com:dinglebear-ai/labby.git
cd labby
just install
just web-build
labby serve --host 127.0.0.1 --port 8765

just install builds the all-features release binary and symlinks it to ~/.local/bin/labby.

On macOS, install the gateway as a persistent per-user service instead of running labby serve in a terminal:

just macos-service-install
just macos-service-status

This installs a launchd LaunchAgent that keeps Labby listening on 127.0.0.1:8765, restarts it after login or exit, and uses the stable absolute LABBY_HOME (default ~/.labby) as both working directory and durable configuration root. It never persists the directory from which installation was invoked. Logs default to the same root. Use just macos-service-restart after changing service settings or just macos-service-uninstall to remove it. The cross-platform just service-install, just service-status, just service-restart, and just service-uninstall bindings select launchd on macOS and systemd on Linux. This is suitable for a Tailscale Serve/Funnel route whose OAuth callback targets the local gateway.

When overriding the launchd paths, LABBY_SERVICE_BIN, LABBY_STATE_DIR, and LABBY_HOME must all be absolute; relative paths fail before the plist or service is changed.

First Run

For loopback development, labby serve can bootstrap a missing bearer token for you. If LABBY_MCP_HTTP_TOKEN is absent and LABBY_AUTH_MODE is not oauth, it generates a token, writes a minimal ~/.labby/.env, reloads it into the running process, prints the setup URL, and continues. The token itself is stored in ~/.labby/.env rather than printed.

Bootstrap writes these required setup keys if no env exists yet:

  • LABBY_MCP_HTTP_TOKEN (generated random 64-character hex token)
  • LABBY_MCP_TRANSPORT=http
  • LABBY_MCP_HTTP_HOST=127.0.0.1
  • LABBY_MCP_HTTP_PORT=8765
  • LABBY_AUTH_MODE=bearer

It also enforces secure file creation via Labby's env_merge path (0600 perms on Unix) and then skips creating anything else until the web wizard runs.

For explicit setup:

mkdir -p ~/.labby
printf 'LABBY_AUTH_MODE=bearer\nLABBY_MCP_HTTP_TOKEN=%s\n' "$(openssl rand -hex 32)" > ~/.labby/.env
chmod 600 ~/.labby/.env
labby setup
labby serve --host 127.0.0.1 --port 8765

Open http://127.0.0.1:8765/. Build static Labby assets with just web-build first when running from a source checkout.

Self-Host The Gateway

The recommended self-hosted gateway substrate is an amd64 Ubuntu 26.04 Incus system container. Bare metal is the secondary supported shape for a dedicated gateway host or VM. Docker is retained for explicit development/image smoke, but it is not the recommended production boundary for Labby because stdio MCP servers and agent CLIs are installed and launched at runtime.

scripts/incus-bootstrap.sh --version vX.Y.Z
incus exec labby -- systemctl status labby --no-pager
incus exec labby -- curl -fsS http://127.0.0.1:8765/ready

See docs/runtime/INCUS.md for the full Incus runbook, bare-metal variant, /dev/net/tun Tailscale passthrough, manual claude/codex/gemini login checklist, and rollback commands.

Core Workflows

Start Labby

labby serve --host 127.0.0.1 --port 8765
labby mcp

labby serve starts the hosted HTTP runtime: /v1 product APIs, /mcp streamable HTTP MCP, auth routes, OAuth relay endpoints, and static Labby web assets when an export is available. labby mcp is the stdio MCP entrypoint for local MCP clients. A client configured to launch labby mcp does not need an HTTP URL: when a labby serve daemon is reachable, the stdio process becomes a transparent bridge to that daemon and uses its gateway configuration, upstream connections, and OAuth state. If no daemon is found and no explicit target is set, it starts a standalone local gateway instead. See the local bridge guide for client configuration and LABBY_SERVER_URL fail-closed behavior.

Manage Upstream MCP Gateways

labby gateway add \
  --name github \
  --url https://example.com/mcp \
  --bearer-token-env GITHUB_MCP_TOKEN \
  -y

labby gateway reload
labby gateway list

Stdio upstreams execute local commands when tested or reconciled, so gateway tests and config mutations use the shared destructive-action confirmation gate. The stdio spawn guard allows known runtimes such as npx, uvx, docker, node, python, python3, deno, pipx, and dnx; customize it in [gateway] inside config.toml.

Use Code Mode

When [code_mode].enabled = true, Labby hides raw proxied upstream tools from MCP list_tools() and exposes the canonical synthetic codemode tool.

labby gateway code status
labby gateway code enable
labby gateway code exec --code 'async () => tools.length'

MCP call shapes:

{ "code": "async () => (await codemode.search(\"github issues\")).results" }
{ "code": "async () => callTool(\"github::search_issues\", {\"query\":\"repo:dinglebear-ai/labby gateway\"})" }
{ "code": "async () => codemode.run(\"gateway-summary\", {\"includeHealth\": true})" }

Code Mode can call exposed upstream MCP tools only. It cannot call Labby actions from inside the sandbox.

Work With Code Mode Snippets

labby snippets list
labby snippets get gateway-summary
labby snippets create --name my-snippet --file ./my-snippet.js
labby snippets validate my-snippet
labby snippets exec my-snippet
labby snippets test my-snippet

Snippets are stored per-user under $LABBY_HOME and executed through the gateway Code Mode runner, so they can reach exposed upstream tools but not Labby actions. The snippets service is gateway-gated: it is unavailable in builds without the gateway feature.

Audit Health And Logs

labby doctor            # audit every configured service
labby doctor system     # local env vars, Docker, disk, toolchain
labby doctor auth       # auth/OAuth env vars, files, permissions
labby doctor proxy      # zero-route stdio-proxy config/dependency preflight
labby doctor proxy --app-url URL --mcp-url URL --route /path
                        # routed public reverse-proxy checks remain available
labby doctor oauth-relay
labby health            # lightweight liveness/readiness probe
labby logs              # tail the active deployment's service journal

labby doctor --json is the CI-friendly form; the exit code reflects the worst severity found.

Removed surfaces. Earlier releases documented labby marketplace, labby stash, labby nodes, and labby deploy, along with ACP chat, the MCP Registry browser, and device/fleet runtimes. Those products have been deleted from source, manifests, packaging, and CI — not merely feature-gated. scripts/check-retired-features.sh guards against reintroduction, and the historical designs are archived under docs/archive/retired-labby. Plugin marketplace assets now live in the separate dendrite repo.

Drive The API

Generic action dispatch:

curl -s -X POST http://127.0.0.1:8765/v1/gateway \
  -H "Authorization: Bearer $LABBY_MCP_HTTP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"action":"gateway.list","params":{}}'

Dedicated product routes also exist for catalog discovery (/v1/{service}/actions), setup, doctor, snippets, filesystem, server logs, gateway OAuth (/v1/gateway/oauth/*), OAuth relay, auth allowlists (/v1/auth/allowed-emails), /v1/openapi, and the browser session routes under /auth/*. See generated API routes and OpenAPI.

Runtime Surfaces

SurfaceEntry PointNotes
CLIlabby <command>Current commands are generated in docs/generated/cli-help.md. Use --json for machine-readable output and `--color auto
MCP stdiolabby mcpLocal editor/desktop MCP clients.
MCP HTTPlabby serve plus /mcpStreamable HTTP MCP with bearer or OAuth JWT auth.
HTTP APIlabby serve plus /v1/*Generic POST /v1/{service} action dispatch plus dedicated product routes.
Web UIlabby serve plus exported assetsMain routes are / (overview), /gateways, /gateway, /snippets, /usage, /settings (with core, services, services/[service], surfaces, features, doctor, extract, advanced subpages), /docs, /design-system, and /mcp/code-mode.

MCP service tools use the shared action shape:

{
  "action": "mcp.list",
  "params": { "search": "postgres", "limit": 10 }
}

Every service tool also supports help and schema through the shared dispatcher. Destructive MCP actions use elicitation when the client supports it; headless clients pass "confirm": true inside params.

Configuration

Configuration is split deliberately:

DataLocationExamples
Secrets and endpoint values$LABBY_HOME/.envLABBY_MCP_HTTP_TOKEN, LABBY_GOOGLE_CLIENT_SECRET, upstream bearer token env values
Preferences$LABBY_HOME/config.tomltransport, CORS, auth mode, workspace root, gateway spawn guard, and upstream behavior

LABBY_HOME selects the one authoritative configuration and durable-state root and must be absolute. It defaults to ~/.labby; Labby does not implicitly read CWD or XDG fallback files. Existing process environment values win over values loaded from the selected .env. Runtime precedence is:

  1. CLI flags
  2. Environment variables
  3. config.toml
  4. Built-in defaults

Useful environment variables:

VariablePurpose
LABBY_MCP_HTTP_TOKENStatic bearer token for protected admin/API/MCP routes.
LABBY_AUTH_MODEbearer or oauth.
LABBY_PUBLIC_URLPublic base URL for OAuth metadata, issuer/audience, callbacks, and allowed-host derivation.
LABBY_AUTH_PROVIDERInbound OAuth identity provider: google (stable) or authelia (open beta).
LABBY_GOOGLE_CLIENT_ID / LABBY_GOOGLE_CLIENT_SECRETGoogle credentials when Google is selected.
LABBY_AUTHELIA_ISSUER_URL / LABBY_AUTHELIA_CLIENT_ID / LABBY_AUTHELIA_CLIENT_SECRETAuthelia OIDC configuration; see the pinned registration contract in the OAuth guide.
LABBY_AUTH_ADMIN_EMAILBootstrap admin email; required in OAuth mode.
LABBY_OAUTH_ENCRYPTION_KEYBase64 32-byte key required for encrypted upstream OAuth credentials. Rotation requires reauthorizing affected upstreams.
LABBY_WEB_ASSETS_DIROverride static Labby export directory.
LABBY_WEB_UI_AUTH_DISABLEDDevelopment-only browser auth bypass.
LABBY_LOG / LABBY_LOG_FORMAT / LABBY_LOG_COLORTracing filter, text/json format, and non-TTY color policy.
LABBY_LOG_DIROptional rolling JSON file log directory.
LABBY_ACTOR_KEY_SECRETStable secret for redacted actor correlation in logs.
LABBY_ADMIN_ENABLEDRuntime opt-in for the lab_admin tool.

Bearer auth is an operator/admin shortcut for Labby routes. Public protected MCP routes validate route-scoped Labby OAuth JWTs; do not treat LABBY_MCP_HTTP_TOKEN as a public resource credential.

When driving the web UI with automation while OAuth is enabled, pass the bearer token as a same-origin header. /auth/session recognizes that token and returns a synthetic admin session:

TOKEN=$(awk -F= '/^LAB

Sourced from the repository README.

More in Browser & Web