Skip to main content

Get started

This guide walks you through NetFoundry MCP Gateway from scratch. You'll start with the simplest possible setup — a single MCP server exposed over the network — and build up to a full multi-backend gateway with tool filtering and namespacing.

Prerequisites

Before you begin, you need:

  • Go 1.25.4+: For building from source.
  • A zrok v2.0.x account: Sign up for free at zrok.io or follow the zrok2 invite instructions below.

Part 1: Enable zrok

NetFoundry MCP Gateway uses zrok for secure, zero-trust networking. All traffic between components travels over an OpenZiti overlay network — nothing is ever exposed on a public IP.

If you already have a zrok v1.x account on zrok.io, the same account token works for enabling a v2.x environment; the new environment ends up in ~/.zrok2 and appears in your account overview.

Request an account

zrok2 invite

Enter your email address. You'll receive an invitation email with your account token.

Install zrok

Download the zrok2 binary (v2.0.0-rc7 or later) for your platform from the releases page.

Enable your environment

zrok2 enable <your-token>
zrok2 status

Part 2: Your first MCP server (mcp-bridge + mcp-tools)

The simplest setup uses two components:

  • mcp-bridge: Takes a local stdio MCP server and makes it available over the overlay.
  • mcp-tools: Connects to a remote share and bridges it back to stdio.

Together they let any MCP client talk to an MCP server running anywhere, without opening ports or configuring firewalls.

Install

Install all components with a single command:

go install github.com/openziti/mcp-gateway/cmd/...@latest

This installs all components: mcp-gateway, mcp-bridge, mcp-tools, and mcp-filesystem (a sandboxed filesystem server included for getting started).

Build from source

Clone the repository and build each binary individually:

git clone https://github.com/openziti/mcp-gateway.git
cd mcp-gateway
go build ./cmd/mcp-gateway
go build ./cmd/mcp-bridge
go build ./cmd/mcp-tools

Start the bridge

mcp-bridge mcp-filesystem ~/Documents

The bridge spawns mcp-filesystem ~/Documents, creates a zrok private share, and prints the share token:

{"share_token":"a1b2c3d4e5f6"}

The share token is the only thing needed to connect. There's no IP address, no port, no DNS name — the server is a "dark service" that doesn't listen on any network interface. Keep this terminal running.

Connect with mcp-tools

In a second terminal:

mcp-tools run a1b2c3d4e5f6

mcp-tools run connects to the zrok share and bridges it to stdin/stdout. Any MCP client that speaks stdio can use this as its transport.

Configure Claude Desktop

Add the share to Claude Desktop's config file:

PlatformPath
macOS~/Library/Application Support/Claude/claude_desktop_config.json
Windows%APPDATA%\Claude\claude_desktop_config.json
Linux~/.config/Claude/claude_desktop_config.json

Add the server entry:

{
"mcpServers": {
"filesystem": {
"command": "mcp-tools",
"args": ["run", "a1b2c3d4e5f6"]
}
}
}

Restart Claude Desktop. The read_file, write_file, and list_directory tools will be available.

Part 3: Aggregate multiple servers (mcp-gateway)

mcp-gateway aggregates multiple backends and serves them all through a single zrok share.

Create a configuration file

Create gateway-config.yml:

aggregator:
name: "my-gateway"
version: "1.0.0"
separator: ":"

backends:
- id: docs
transport:
type: stdio
command: mcp-filesystem
args: ["~/Documents"]

- id: data
transport:
type: stdio
command: mcp-filesystem
args: ["~/Data"]
tools:
mode: allow
list:
- "read_file"
- "list_directory"

Start the gateway

Pass the config file path as the argument:

mcp-gateway run gateway-config.yml
Output
{"share_token":"x9y8z7w6v5u4"}

Connect the same way:

mcp-tools run x9y8z7w6v5u4

The available tools are now namespaced by backend ID:

ToolSource
docs:read_filedocs backend
docs:write_filedocs backend
docs:list_directorydocs backend
data:read_filedata backend (filtered to read-only)
data:list_directorydata backend (filtered to read-only)

data:write_file is absent because the allow list on the data backend only includes read_file and list_directory. See Configuration for the full list of aggregator settings, transport types, filtering options, and environment variable syntax.

Part 4: Connect remote servers

You can connect to MCP servers running on other machines using mcp-bridge with the zrok transport.

Run a bridge on a remote machine

mcp-bridge mcp-filesystem /data
Output
{"share_token":"remote-token"}

Add as a gateway backend

Reference the remote bridge's share token under a zrok transport:

backends:
- id: local
transport:
type: stdio
command: mcp-filesystem
args: ["~/Documents"]

- id: remote
transport:
type: zrok
share_token: "remote-token"

The gateway connects over the zrok overlay — no ports to open, no firewall rules. The remote backend's tools are namespaced and filtered like any other backend.

Gateways can chain freely: a gateway backend can point to another gateway's share, or to a bridge running anywhere on the network.

Part 5: Connect to your agent

Claude Desktop (stdio)

Add the gateway share to Claude Desktop's config:

{
"mcpServers": {
"my-tools": {
"command": "mcp-tools",
"args": ["run", "x9y8z7w6v5u4"]
}
}
}

HTTP mode

For agents or clients that expect an HTTP endpoint:

mcp-tools http x9y8z7w6v5u4 --bind 127.0.0.1:8080

Options:

  • --bind: Address to listen on (default: 127.0.0.1:8080)
  • --stateless: No session persistence
  • --json-response: Prefer JSON responses over SSE streams

Any MCP client that supports stdio transport can use mcp-tools run <token> directly. For HTTP-based clients, use mcp-tools http.

n8n example: Configure the n8n MCP Client Tool:

  • URL: http://127.0.0.1:8080
  • Transport: SSE (default) or streamable HTTP

Troubleshooting

  • "zrok enable" required: Run zrok2 enable with your account token first.

  • Backend connection failures: Check that stdio commands are correct and executables are in PATH. For zrok backends, verify the share token is valid and the remote bridge is running.

  • Tool not found: Check the namespace prefix matches the backend ID. Verify the tool isn't filtered by your allow/deny list.

  • Debug logging: Set PFXLOG_LEVEL=debug for verbose output:

    PFXLOG_LEVEL=debug mcp-gateway run config.yml

What's next

  • Configuration: Full reference for every aggregator, backend, and filtering option.
  • Persistent shares: Create share tokens that survive restarts for production deployments.