# Tunnel Manager

> Create SSH Tunnels to your remote hosts and host as an MCP Server for Agentic AI!

- **Type:** MCP server
- **Install:** `agentstack add mcp-knuckles-team-tunnel-manager`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Knuckles-Team](https://agentstack.voostack.com/s/knuckles-team)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Knuckles-Team](https://github.com/Knuckles-Team)
- **Source:** https://github.com/Knuckles-Team/tunnel-manager

## Install

```sh
agentstack add mcp-knuckles-team-tunnel-manager
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Tunnel Manager
## CLI or API | MCP | Agent

*Version: 2.1.0*

> **Documentation** — Installation, deployment, usage across the API, CLI, and MCP
> and agent interfaces are maintained in the
> [official documentation](https://knuckles-team.github.io/tunnel-manager/).

---

## Overview

**Tunnel Manager** is a production-grade Agent and Model Context Protocol (MCP) server designed to interface directly with Create SSH Tunnels to your remote hosts and host as an MCP Server for Agentic AI!.

---

## Key Features

- **Consolidated Action-Routed MCP Tools:** Minimizes token overhead and eliminates tool bloat in LLM contexts by grouping methods into optimized, togglable tool modules.
- **Enterprise-Grade Security:** Comprehensive support for Eunomia policies, OIDC token delegation, and granular execution context tracking.
- **Integrated Graph Agent:** Built-in Pydantic AI agent supporting the Agent Control Protocol (ACP) and standard Web interfaces (AG-UI).
- **Native Telemetry & Tracing:** Out-of-the-box OpenTelemetry exports and native Langfuse tracing.

---

## CLI or API

This agent wraps the Create SSH Tunnels to your remote hosts and host as an MCP Server for Agentic AI! API. You can interact with it programmatically or via its integrated execution entrypoints.

Detailed instructions on how to use the underlying API wrappers, extended schema bindings, and developer SDK references are maintained in [docs/index.md](docs/index.md).

---

## MCP

This server utilizes dynamic Action-Routed tools to optimize token overhead and maximize IDE compatibility.

### Available MCP Tools

_Auto-generated from the live MCP server — do not edit by hand._

#### Condensed action-routed tools (default — `MCP_TOOL_MODE=condensed`)

| MCP Tool | Toggle Env Var | Description |
|----------|----------------|-------------|
| `tm_files` | `FILETOOL` | Advanced file operations on remote hosts. |
| `tm_hosts` | `HOSTTOOL` | Manage the local host alias inventory. |
| `tm_inventory` | `INVENTORYTOOL` | Bulk inventory operations against YAML host groups. |
| `tm_operations` | `OPERATIONSTOOL` | Operation lifecycle and session management. |
| `tm_remote` | `REMOTETOOL` | Single-host SSH operations with shared connection params. |
| `tm_security` | `SECURITYTOOL` | Security scanning and compliance. |
| `tm_system` | `SYSTEMTOOL` | Remote system intelligence via SSH. |
| `tunnel_ingest_hosts` | `INGESTTOOL` | List the managed SSH inventory and push it into the epistemic-graph KG. |

#### Verbose 1:1 API-mapped tools (`MCP_TOOL_MODE=verbose` or `both`)

6 per-operation tools — one per public API method (click to expand)

| MCP Tool | Toggle Env Var | Description |
|----------|----------------|-------------|
| `tunnel_manager_add_host` | `HOST_MANAGERTOOL` | Invoke the add_host operation. |
| `tunnel_manager_get_host` | `HOST_MANAGERTOOL` | Invoke the get_host operation. |
| `tunnel_manager_list_hosts` | `HOST_MANAGERTOOL` | Invoke the list_hosts operation. |
| `tunnel_manager_load_inventory` | `HOST_MANAGERTOOL` | Invoke the load_inventory operation. |
| `tunnel_manager_remove_host` | `HOST_MANAGERTOOL` | Invoke the remove_host operation. |
| `tunnel_manager_save_inventory` | `HOST_MANAGERTOOL` | Invoke the save_inventory operation. |

_8 action-routed tool(s) (default) · 6 verbose 1:1 tool(s). Each is enabled unless its `TOOL` toggle is set false; `MCP_TOOL_MODE` selects the surface (`condensed` default · `verbose` 1:1 · `both`). Auto-generated — do not edit._

Detailed tool schemas, parameter shapes, and validation constraints are preserved in [docs/mcp.md](docs/mcp.md).

### Dynamic Tool Selection & Visibility

This MCP server supports dynamic toolset selection and visibility filtering at runtime. This allows you to restrict the set of exposed tools in order to prevent blowing up the LLM's context window.

You can configure tool filtering via multiple input channels:

- **CLI Arguments:** Pass `--tools` or `--toolsets` (or their disabled counterparts `--disabled-tools` and `--disabled-toolsets`) during startup.
- **Environment Variables:** Define standard environment variables:
  - `MCP_ENABLED_TOOLS` / `MCP_DISABLED_TOOLS`
  - `MCP_ENABLED_TAGS` / `MCP_DISABLED_TAGS`
- **HTTP SSE Request Headers:** Pass custom headers during transport initialization:
  - `x-mcp-enabled-tools` / `x-mcp-disabled-tools`
  - `x-mcp-enabled-tags` / `x-mcp-disabled-tags`
- **HTTP SSE Request Query Parameters:** Append query parameters directly to your transport connection URL:
  - `?tools=tool1,tool2`
  - `?tags=tag1`

When query strings or parameters are supplied, an LLM-free **Knowledge Graph resolution layer** (using `DynamicToolOrchestrator`) matches query intents against known tool tags, names, or descriptions, with safe fallback and automated 24-hour background cache refreshing.

---

### MCP Configuration Examples

> **Install the slim `[mcp]` extra.** All examples install `tunnel-manager[mcp]` — the
> MCP-server extra that pulls only the FastMCP / FastAPI tooling (`agent-utilities[mcp]`).
> It deliberately **excludes** the heavy agent runtime (`pydantic-ai`, the epistemic-graph
> engine, `dspy`, `llama-index`), so `uvx` / container installs are far smaller. Use the
> full `[agent]` extra only when you need the integrated Pydantic AI agent.

#### stdio Transport (local IDEs — Cursor, Claude Desktop, VS Code)

```json
{
  "mcpServers": {
    "tunnel-manager-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "tunnel-manager[mcp]",
        "tunnel-manager-mcp"
      ],
      "env": {
        "MCP_TOOL_MODE": "condensed",
        "FILETOOL": "True",
        "HOSTTOOL": "True",
        "INGESTTOOL": "True",
        "INVENTORYTOOL": "True",
        "OPERATIONSTOOL": "True",
        "REMOTETOOL": "True",
        "SECURITYTOOL": "True",
        "SYSTEMTOOL": "True",
        "TUNNEL_CERTIFICATE": "",
        "TUNNEL_IDENTITY_FILE": "~/.ssh/id_ed25519",
        "TUNNEL_INVENTORY": "",
        "TUNNEL_INVENTORY_GROUP": "all",
        "TUNNEL_KG_INGEST": "true",
        "TUNNEL_MANAGER_HEALTH_AGGREGATE_S": "3600",
        "TUNNEL_MANAGER_HEALTH_INGEST": "true",
        "TUNNEL_MANAGER_HEALTH_NOTIFY_URL": "",
        "TUNNEL_MANAGER_HOSTS": "r510,r710,r820,rw710",
        "TUNNEL_MAX_THREADS": "6",
        "TUNNEL_PARALLEL": "False",
        "TUNNEL_PASSWORD": "",
        "TUNNEL_PROXY_COMMAND": "",
        "TUNNEL_REMOTE_HOST": "",
        "TUNNEL_REMOTE_PORT": "22",
        "TUNNEL_USERNAME": "",
        "XDG_CONFIG_HOME": ""
      }
    }
  }
}
```

#### Streamable-HTTP Transport (networked / production)

```json
{
  "mcpServers": {
    "tunnel-manager-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "tunnel-manager[mcp]",
        "tunnel-manager-mcp",
        "--transport",
        "streamable-http",
        "--port",
        "8000"
      ],
      "env": {
        "TRANSPORT": "streamable-http",
        "HOST": "0.0.0.0",
        "PORT": "8000",
        "MCP_TOOL_MODE": "condensed",
        "FILETOOL": "True",
        "HOSTTOOL": "True",
        "INGESTTOOL": "True",
        "INVENTORYTOOL": "True",
        "OPERATIONSTOOL": "True",
        "REMOTETOOL": "True",
        "SECURITYTOOL": "True",
        "SYSTEMTOOL": "True",
        "TUNNEL_CERTIFICATE": "",
        "TUNNEL_IDENTITY_FILE": "~/.ssh/id_ed25519",
        "TUNNEL_INVENTORY": "",
        "TUNNEL_INVENTORY_GROUP": "all",
        "TUNNEL_KG_INGEST": "true",
        "TUNNEL_MANAGER_HEALTH_AGGREGATE_S": "3600",
        "TUNNEL_MANAGER_HEALTH_INGEST": "true",
        "TUNNEL_MANAGER_HEALTH_NOTIFY_URL": "",
        "TUNNEL_MANAGER_HOSTS": "r510,r710,r820,rw710",
        "TUNNEL_MAX_THREADS": "6",
        "TUNNEL_PARALLEL": "False",
        "TUNNEL_PASSWORD": "",
        "TUNNEL_PROXY_COMMAND": "",
        "TUNNEL_REMOTE_HOST": "",
        "TUNNEL_REMOTE_PORT": "22",
        "TUNNEL_USERNAME": "",
        "XDG_CONFIG_HOME": ""
      }
    }
  }
}
```

Alternatively, connect to a pre-deployed Streamable-HTTP instance by `url`:

```json
{
  "mcpServers": {
    "tunnel-manager-mcp": {
      "url": "http://localhost:8000/tunnel-manager-mcp/mcp"
    }
  }
}
```

Deploying the Streamable-HTTP server via Docker:

```bash
docker run -d \
  --name tunnel-manager-mcp-mcp \
  -p 8000:8000 \
  -e TRANSPORT=streamable-http \
  -e HOST=0.0.0.0 \
  -e PORT=8000 \
  -e MCP_TOOL_MODE=condensed \
  -e FILETOOL=True \
  -e HOSTTOOL=True \
  -e INGESTTOOL=True \
  -e INVENTORYTOOL=True \
  -e OPERATIONSTOOL=True \
  -e REMOTETOOL=True \
  -e SECURITYTOOL=True \
  -e SYSTEMTOOL=True \
  -e TUNNEL_CERTIFICATE="" \
  -e TUNNEL_IDENTITY_FILE=~/.ssh/id_ed25519 \
  -e TUNNEL_INVENTORY="" \
  -e TUNNEL_INVENTORY_GROUP=all \
  -e TUNNEL_KG_INGEST=true \
  -e TUNNEL_MANAGER_HEALTH_AGGREGATE_S=3600 \
  -e TUNNEL_MANAGER_HEALTH_INGEST=true \
  -e TUNNEL_MANAGER_HEALTH_NOTIFY_URL="" \
  -e TUNNEL_MANAGER_HOSTS=r510,r710,r820,rw710 \
  -e TUNNEL_MAX_THREADS=6 \
  -e TUNNEL_PARALLEL=False \
  -e TUNNEL_PASSWORD="" \
  -e TUNNEL_PROXY_COMMAND="" \
  -e TUNNEL_REMOTE_HOST="" \
  -e TUNNEL_REMOTE_PORT=22 \
  -e TUNNEL_USERNAME="" \
  -e XDG_CONFIG_HOME="" \
  knucklessg1/tunnel-manager:mcp
```

_Auto-generated from the code-read env surface (`MCP_TOOL_MODE` + package vars) — do not edit._

### Additional Deployment Options

`tunnel-manager` can also run as a **local container** (Docker / Podman / `uv`) or be
consumed from a **remote deployment**. The
[Deployment guide](https://knuckles-team.github.io/tunnel-manager/deployment/) has full, copy-paste
`mcp_config.json` for all four transports — **stdio**, **streamable-http**,
**local container / uv**, and **remote URL**:

- **Local container / uv** — launch the server from `mcp_config.json` via `uvx`,
  `docker run`, or `podman run`, or point at a local streamable-http container by `url`.
- **Remote URL** — connect to a server deployed behind Caddy at
  `http://tunnel-manager-mcp.arpa/mcp` using the `"url"` key.

---

## Inventory

tunnel-manager works from a single shared YAML **inventory** that maps short host
aliases (e.g. `r820`) to their SSH connection details. Every ecosystem surface reads
the **same file** — the `HostManager` API, the `tunnel-manager` CLI, the MCP server,
**container-manager-mcp** (its `cm_*` host aliases), and the `ssh-bootstrap` skill — so
you define your fleet once.

- **Location** — `~/.config/agent-utilities/inventory.yml` (`.yml` preferred). A legacy
  `inventory.yaml` at the same path is still read when no `.yml` exists, so existing
  installs keep working. Override with `TUNNEL_INVENTORY`.
- **Manage it** with the `inventory` subcommand:

  ```bash
  tunnel-manager inventory init     # write a commented inventory.yml template (--force to overwrite)
  tunnel-manager inventory doctor   # validate hosts/groups; --fix migrates legacy .yaml -> .yml
  tunnel-manager inventory show     # print the resolved path + host/group summary
  ```

Full schema, every host field, the copy-paste template, and override options live in the
[Inventory guide](docs/inventory.md).

---

## Environment Variables

#### Package environment variables

| Variable | Example | Description |
|----------|---------|-------------|
| `HOST` | `0.0.0.0` |  |
| `PORT` | `8000` |  |
| `TRANSPORT` | `stdio` | options: stdio, streamable-http, sse |
| `ENABLE_OTEL` | `True` |  |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:8080/api/public/otel` |  |
| `OTEL_EXPORTER_OTLP_PUBLIC_KEY` | `pk-...` |  |
| `OTEL_EXPORTER_OTLP_SECRET_KEY` | `sk-...` |  |
| `OTEL_EXPORTER_OTLP_PROTOCOL` | `http/protobuf` |  |
| `EUNOMIA_TYPE` | `none` | options: none, embedded, remote |
| `EUNOMIA_POLICY_FILE` | `mcp_policies.json` |  |
| `EUNOMIA_REMOTE_URL` | `http://eunomia-server:8000` |  |
| `TUNNEL_IDENTITY_FILE` | `~/.ssh/id_ed25519` |  |
| `DEBUG` | `False` |  |
| `PYTHONUNBUFFERED` | `1` |  |
| `TUNNEL_REMOTE_HOST` | — | default remote host (e.g. 192.168.1.10) |
| `TUNNEL_REMOTE_PORT` | `22` | default SSH port |
| `TUNNEL_USERNAME` | — | default SSH username |
| `TUNNEL_PASSWORD` | — | default SSH password (prefer key-based auth) |
| `TUNNEL_CERTIFICATE` | — | path to an SSH certificate file |
| `TUNNEL_PROXY_COMMAND` | — | SSH ProxyCommand for jump-host/bastion connections |
| `TUNNEL_INVENTORY` | — | path to the inventory file (defaults to XDG config path) |
| `TUNNEL_INVENTORY_GROUP` | `all` | inventory host group to target |
| `TUNNEL_PARALLEL` | `False` | run host operations in parallel |
| `TUNNEL_MAX_THREADS` | `6` | max worker threads when TUNNEL_PARALLEL=True |
| `XDG_CONFIG_HOME` | — | base config dir (defaults to ~/.config) for inventory resolution |
| `HOSTTOOL` | `True` | Grouped condensed-surface toggles, one per register__tools registrar. |
| `REMOTETOOL` | `True` |  |
| `INVENTORYTOOL` | `True` |  |
| `OPERATIONSTOOL` | `True` |  |
| `SYSTEMTOOL` | `True` |  |
| `FILETOOL` | `True` |  |
| `SECURITYTOOL` | `True` |  |
| `INGESTTOOL` | `True` | KG-ingest tools (list the SSH inventory into epistemic-graph) |
| `TUNNEL_KG_INGEST` | `true` | default-on best-effort inventory ingest on `list` |
| `TUNNEL_MANAGER_HEALTH_INGEST` | `true` | default-on best-effort network-signal trend ingestion |
| `TUNNEL_MANAGER_HEALTH_AGGREGATE_S` | `3600` | window (s) over which samples distill to ONE :HealthTrend node/host/signal |
| `TUNNEL_MANAGER_HOSTS` | `r510,r710,r820,rw710` | comma-separated inventory aliases to probe/derive over (default: full inventory) |
| `TUNNEL_MANAGER_HEALTH_NOTIFY_URL` | — | best-effort webhook for network-anomaly notifications |

#### Inherited agent-utilities variables (apply to every connector)

| Variable | Example | Description |
|----------|---------|-------------|
| `MCP_TOOL_MODE` | `condensed` | Tool surface: `condensed` | `verbose` | `both` |
| `MCP_ENABLED_TOOLS` | — | Comma-separated tool allow-list |
| `MCP_DISABLED_TOOLS` | — | Comma-separated tool deny-list |
| `MCP_ENABLED_TAGS` | — | Comma-separated tag allow-list |
| `MCP_DISABLED_TAGS` | — | Comma-separated tag deny-list |
| `MCP_CLIENT_AUTH` | — | Outbound MCP child auth: `oidc-client-credentials` | `basic` | `none` |
| `OIDC_CLIENT_ID` | — | OIDC client id (service-account auth) |
| `OIDC_CLIENT_SECRET` | — | OIDC client secret (service-account auth) |
| `MCP_BASIC_AUTH_USERNAME` | — | HTTP Basic username (`MCP_CLIENT_AUTH=basic`) |
| `MCP_BASIC_AUTH_PASSWORD` | — | HTTP Basic password (`MCP_CLIENT_AUTH=basic`) |
| `MCP_URL` | `http://localhost:8000/mcp` | URL of the MCP server the agent connects to |
| `PROVIDER` | `openai` | LLM provider for the agent |
| `MODEL_ID` | `gpt-4o` | Model id for the agent |
| `ENABLE_WEB_UI` | `True` | Serve the AG-UI web interface |

_38 package + 14 inherited variable(s). Auto-generated from `.env.example` + the shared agent-utilities set — do not edit._

Every variable the server reads, grouped by purpose. See [`.env.example`](.env.example)
for a copy-paste starting point.

### SSH connection & credentials
| Variable | Description | Default |
|----------|-------------|---------|
| `TUNNEL_IDENTITY_FILE` | Path to the SSH private key | `~/.ssh/id_ed25519` |
| `TUNNEL_USERNAME` | SSH username | — |
| `TUNNEL_PASSWORD` | SSH password (when not using a key) | — |
| `TUNNEL_CERTIFICATE` | Path to an SSH certificate | — |
| `TUNNEL_REMOTE_HOST` | Default remote host | — |
| `TUNNEL_REMOTE_PORT` | Default remote SSH port | `22` |
| `TUNNEL_PROXY_COMMAND` | SSH `ProxyCommand` for jump hosts | — |

### Inventory & parallelism
| Variable | Description | Default |
|----------|-------------|---------|
| `TUNNEL_INVENTORY` | Path to the shared inventory (`.yml` preferred, `.yaml` legacy fallback) | `~/.config/agent-utilities/inventory.yml` |
| `TUNNEL_INVENTORY_GROUP` | Default inventory host group | — |
| `TUNNEL_PARALLEL` | Run bulk operations in parallel | — |
| `TUNNEL_MAX_THREADS` | Max concurrent SSH worker threads | — |
| `XDG_CONFIG_HOME` | Base config dir used to resolve the inventory | `~/.config` |

### MCP server / transport
|

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Knuckles-Team](https://github.com/Knuckles-Team)
- **Source:** [Knuckles-Team/tunnel-manager](https://github.com/Knuckles-Team/tunnel-manager)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-knuckles-team-tunnel-manager
- Seller: https://agentstack.voostack.com/s/knuckles-team
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
