Skip to main content
Glama

vpnhop

MCP server that sends API calls through a VPN without connecting your machine to the VPN. Each profile's VPN client runs in its own throwaway Docker container; requests run from inside it.

VPN

Client in container

Auth

OpenVPN (incl. AWS Client VPN, OpenVPN Connect .ovpn)

openvpn 2.7

certs, username/password

WireGuard

wg-quick (kernel, falls back to wireguard-go)

private key

Cisco AnyConnect / ocserv, GlobalProtect, Pulse/Ivanti, Juniper NC, Fortinet, F5, Array

openconnect

username/password, TOTP, cert pin

IPsec IKEv2

strongSwan (swanctl)

EAP-MSCHAPv2, PSK

How it works

  • No sudo, no host routes, no system VPN. Host traffic is never affected.

  • Secrets are resolved per connect from env, file or command (e.g. op read). They are piped into the container as a tar over stdin, so there's no host temp file, env var or bind mount.

  • DNS is resolved inside the tunnel (pushed DNS, WireGuard DNS=, or dns/searchDomains overrides).

  • Tunnels connect on first http_request and close after idleMinutes, or when the server exits.

  • Client logs come back redacted, and only for tunnels this server started.

Related MCP server: pipepie

Tools

Tool

Does

list_profiles

Profiles, type, allowed hosts, tunnel state

http_request

HTTP(S) via a profile; auto-connects

connect / disconnect

Manual tunnel control

status

State, plus the redacted client log

refresh

Same as vpnhop refresh

Install

Needs Docker Desktop (running) and Node.js 24+. One command installs and registers it with Claude Code:

curl -fsSL https://raw.githubusercontent.com/kylepantall/vpnhop/main/scripts/install.sh | bash -s -- --claude

What the installer does:

  • Installs into ~/.local/share/vpnhop, with a vpnhop launcher in ~/.local/bin. The launcher uses the Node it found at install time.

  • Builds the VPN runtime image.

  • Creates ~/.config/vpnhop/config.json from the example if you don't have one. Edit it to add your VPNs.

  • Starts the new version: servers on the old build are stopped, and Claude starts the new one when it reconnects.

Options:

  • Pin a branch, tag or commit: bash -s -- --claude <ref>.

  • An existing vpnhop entry stops the installer. --force replaces it.

  • From a local checkout: VPNHOP_SOURCE_DIR=~/Code/vpnhop bash scripts/install.sh --claude.

  • VPNHOP_INSTALL_DIR and VPNHOP_BIN_DIR choose other directories.

Start a new Claude session after installing.

Uninstall

curl -fsSL https://raw.githubusercontent.com/kylepantall/vpnhop/main/scripts/uninstall.sh | bash

This removes:

  • the Claude entry;

  • running servers;

  • tunnel containers and runtime images;

  • the launcher and the install directory.

Your config is kept. Add -s -- --purge to delete ~/.config/vpnhop as well.

Command line

Command

Does

vpnhop / vpnhop serve

MCP server on stdio

vpnhop update

Checks GitHub for a newer release and reruns the installer for it. --check only reports, --yes skips the prompt, --json for scripts

vpnhop refresh

Closes and restarts dangling instances (details below). macOS and Linux

vpnhop status

Every profile and its tunnel state

vpnhop connect <p> / disconnect <p>

Bring a tunnel up or down

vpnhop get <p> <url>

GET a URL through a tunnel

vpnhop build

Rebuild the runtime image

What vpnhop refresh does:

  • Running servers close their tunnels, which reconnect on the next call.

  • Servers older than the installed build, or orphaned by a closed client, are stopped. Claude restarts them on reconnect.

  • Leftover tunnel containers and old runtime images are removed.

Releasing: bump version in package.json and src/version.ts, then publish a v<version> GitHub release. vpnhop update picks it up.

Config

~/.config/vpnhop/config.json (or $VPNHOP_CONFIG). See examples/config.json. Relative paths resolve against the config file's folder.

Field

Applies to

Notes

allowHosts

all

*, exact host, *.suffix, IPv4 CIDR. Omit to allow any

dns, searchDomains

all

Override pushed DNS

idleMinutes, connectTimeoutSeconds

all

Also settable under defaults

secrets

all

{ "env": "X" }, { "file": "path" }, { "command": ["op","read","op://…"] }. Literal values are rejected

⚠️ For OpenVPN, external ca/cert/key/tls-* files are copied in, and host hook scripts (up, down, …) are dropped.

Limits

  • SAML / browser SSO VPNs (AWS Client VPN federated auth, Okta-fronted GlobalProtect) need a human in a browser, so they can't run headless.

  • L2TP, PPTP and SSTP are not supported.

  • HTTP(S) only. There is no raw TCP or SOCKS proxy yet.

Develop

npm install
npm test            # unit
npm run test:e2e    # real WireGuard, OpenVPN and IPsec servers in Docker
npm run typecheck

Available Tools

6 tools
connectConnect a VPN profileA
Idempotent

Starts the tunnel for a profile and waits until it is up (http_request also does this on demand). Reuses a running tunnel. On failure the error includes the redacted VPN client log.

Inputs: profile (required).

disconnectDisconnect a VPN profileB
Idempotent

Stops and removes the tunnel container for a profile.

Inputs: profile (required).

http_requestHTTP request through a VPNA
Destructive

Sends an HTTP(S) request from inside the profile's tunnel (connecting first if needed) and returns status, headers and body. Text bodies come back as utf8, binary as base64; bodies over maxBodyBytes are truncated. Redirects are not followed unless followRedirects is set.

Inputs: url (required), profile (required), body, method, +6 more.

list_profilesList VPN profilesB
Read-only

Configured VPN profiles with their type, description, allowed hosts and whether each tunnel is up.

Inputs: no named parameters.

refreshRefresh vpnhopA
Idempotent

Closes every tunnel (they reconnect on the next call), recycles other running vpnhop servers, stops outdated or orphaned ones, and removes dangling tunnel containers and old runtime images. Use after a tunnel gets stuck or after updating vpnhop.

Inputs: no named parameters.

statusTunnel statusB
Read-only

State of one or all tunnels, optionally with the last lines of the (redacted) VPN client log.

Inputs: logs, profile.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 6 tools

    Disambiguation4/5

    Each tool maps to a distinct operation: listing profiles, starting/stopping tunnels, inspecting status, sending proxied HTTP requests, and global refresh cleanup. Minor overlap exists because list_profiles reports whether tunnels are up and http_request connects on demand, but the descriptions clarify the intended use of each.

    Naming Consistency3/5

    Names use lowercase snake_case and are readable, but conventions are mixed: list_profiles and http_request are verb_noun, connect/disconnect/refresh are bare verbs, and status is a noun. The pattern is understandable but not uniform.

    Tool Count5/5

    Six tools is a tight, well-scoped set for VPN tunnel management and proxied HTTP requests. Every tool has a clear role and none feels redundant.

    Completeness4/5

    Core lifecycle is covered: list, connect, disconnect, status/logs, proxied requests, and global refresh. Profile creation/editing is absent, but profiles appear to be configured externally; a dedicated log-retrieval tool is also missing, though status exposes recent log lines.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      Credential isolation proxy for AI agents. Injects API keys at the network boundary so your agent never sees the raw credential. Supports domain allowlists, agent auth, policy enforcement, and audit logging.
      3
      141 npm
      16
      Apache 2.0
    • A
      license
      Not graded
      quality
      B
      maintenance
      Bounded egress gateway & secret proxy for AI agents and applications, enabling safe credential injection into upstream requests while keeping raw secrets out of LLM prompt contexts.
      24 npm
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Playwright browser MCP for coding agents working behind a full-tunnel VPN. The tunnel stays up so the agent keeps reaching its API, while the browser's own traffic egresses through your real ISP — for services that reject the tunnel's exit IP: domestic APIs, payment and SMS gateways, bank endpoints. Per-socket binding plus a LAN-bound proxy, with per-host routing rules so you choose which hosts go
      80 npm
      4
      MIT