feat: add UniFi, TrueNAS, and Grafana MCP sidecars #29

Open
opened 2026-02-21 18:34:14 +00:00 by cpfarhood · 2 comments
cpfarhood commented 2026-02-21 18:34:14 +00:00 (Migrated from github.com)

Summary

Add three new MCP server sidecars to the Helm chart, all disabled by default. These extend the devcontainer's AI assistant capabilities to manage network infrastructure, storage, and observability.

New MCP Sidecars

1. UniFi MCP Server

  • Repo: https://github.com/enuno/unifi-mcp-server
  • Image: ghcr.io/enuno/unifi-mcp-server:0.2.4
  • Multi-arch: amd64, arm64, arm/v7
  • Required env vars:
    • UNIFI_API_KEY — UniFi API authentication credential
    • UNIFI_API_TYPElocal, cloud-ea, or cloud-v1 (recommend local)
    • UNIFI_LOCAL_HOST — Gateway IP (e.g., 192.168.2.1) when using local mode
  • Transport: stdio only (no SSE currently)
  • Notes: Exposes UniFi Network Controller API for managing network infrastructure. Cloud API modes have limited functionality compared to local gateway API.

2. TrueNAS MCP Server

  • Repo: https://github.com/truenas/truenas-mcp
  • Image: None published — ships as a native Go binary
  • Required env vars:
    • TRUENAS_URL — TrueNAS hostname or IP (e.g., truenas.local)
    • TRUENAS_API_KEY — API key from TrueNAS System Settings
  • Transport: stdio only (JSON-RPC over stdio, connects to TrueNAS via wss:// on port 443)
  • Notes: Currently in research preview — not recommended for production by upstream. No Docker image exists; would need to build a custom image wrapping the binary, or wait for upstream to publish one.

3. Grafana MCP Server

  • Repo: https://github.com/grafana/mcp-grafana
  • Image: Dockerfile exists in repo, but no published image found on GHCR/DockerHub
  • Required env vars:
    • GRAFANA_URL — Grafana instance endpoint
    • GRAFANA_API_KEY — Service account token with appropriate RBAC
  • Transport: Unclear — repo has a Dockerfile but SSE support not explicitly documented
  • Notes: Requires Grafana 9.0+. Supports granular tool enablement via --enabled-tools and --disable-<category> flags. Covers dashboards, datasources, alerting, incidents, and more.

Implementation Challenges

stdio vs SSE transport

The existing MCP sidecars (kubernetes, flux, homeassistant, github) all expose an SSE HTTP endpoint that the devcontainer connects to via .mcp.json. However:

  • UniFi: stdio only — no SSE support
  • TrueNAS: stdio only — no SSE support
  • Grafana: unclear, needs investigation

Options to resolve:

  1. Wait for upstream SSE support — cleanest, but depends on external projects
  2. Use a stdio-to-SSE bridge/proxy (e.g., supergateway, mcp-proxy) — wrap each stdio server in a proxy container that exposes SSE
  3. Configure Claude Code / Happy to connect via stdio directly — would require running the MCP server inside the main devcontainer rather than as a sidecar, which changes the architecture

No published Docker images

  • TrueNAS has no Docker image at all — would need a custom Dockerfile that downloads the binary
  • Grafana has a Dockerfile but no published image — would need to build and host it, or wait for upstream

Proposed values.yaml structure

mcpSidecars:
  unifi:
    enabled: false
    image:
      repository: ghcr.io/enuno/unifi-mcp-server
      tag: 0.2.4
    port: 8089
    resources:
      requests:
        memory: "64Mi"
        cpu: "50m"
      limits:
        memory: "256Mi"
        cpu: "500m"
  truenas:
    enabled: false
    image:
      repository: TBD  # No published image yet
      tag: latest
    port: 8090
    resources:
      requests:
        memory: "64Mi"
        cpu: "50m"
      limits:
        memory: "256Mi"
        cpu: "500m"
  grafana:
    enabled: false
    image:
      repository: TBD  # No published image yet
      tag: latest
    port: 8091
    resources:
      requests:
        memory: "64Mi"
        cpu: "50m"
      limits:
        memory: "256Mi"
        cpu: "500m"

Secret keys (in env secret)

  • unifi-api-key, unifi-api-type, unifi-local-host
  • truenas-url, truenas-api-key
  • grafana-url, grafana-api-key

Checklist

  • Resolve stdio-to-SSE transport for UniFi and TrueNAS
  • Determine Grafana MCP transport support and Docker image availability
  • Add UniFi MCP sidecar to deployment template and values
  • Add TrueNAS MCP sidecar (pending Docker image)
  • Add Grafana MCP sidecar (pending Docker image / SSE confirmation)
  • Update .mcp.json with new SSE endpoints
  • Update CLAUDE.md documentation
## Summary Add three new MCP server sidecars to the Helm chart, all disabled by default. These extend the devcontainer's AI assistant capabilities to manage network infrastructure, storage, and observability. ## New MCP Sidecars ### 1. UniFi MCP Server - **Repo:** https://github.com/enuno/unifi-mcp-server - **Image:** `ghcr.io/enuno/unifi-mcp-server:0.2.4` - **Multi-arch:** amd64, arm64, arm/v7 - **Required env vars:** - `UNIFI_API_KEY` — UniFi API authentication credential - `UNIFI_API_TYPE` — `local`, `cloud-ea`, or `cloud-v1` (recommend `local`) - `UNIFI_LOCAL_HOST` — Gateway IP (e.g., `192.168.2.1`) when using local mode - **Transport:** stdio only (no SSE currently) - **Notes:** Exposes UniFi Network Controller API for managing network infrastructure. Cloud API modes have limited functionality compared to local gateway API. ### 2. TrueNAS MCP Server - **Repo:** https://github.com/truenas/truenas-mcp - **Image:** None published — ships as a native Go binary - **Required env vars:** - `TRUENAS_URL` — TrueNAS hostname or IP (e.g., `truenas.local`) - `TRUENAS_API_KEY` — API key from TrueNAS System Settings - **Transport:** stdio only (JSON-RPC over stdio, connects to TrueNAS via wss:// on port 443) - **Notes:** Currently in **research preview** — not recommended for production by upstream. No Docker image exists; would need to build a custom image wrapping the binary, or wait for upstream to publish one. ### 3. Grafana MCP Server - **Repo:** https://github.com/grafana/mcp-grafana - **Image:** Dockerfile exists in repo, but no published image found on GHCR/DockerHub - **Required env vars:** - `GRAFANA_URL` — Grafana instance endpoint - `GRAFANA_API_KEY` — Service account token with appropriate RBAC - **Transport:** Unclear — repo has a Dockerfile but SSE support not explicitly documented - **Notes:** Requires Grafana 9.0+. Supports granular tool enablement via `--enabled-tools` and `--disable-<category>` flags. Covers dashboards, datasources, alerting, incidents, and more. ## Implementation Challenges ### stdio vs SSE transport The existing MCP sidecars (kubernetes, flux, homeassistant, github) all expose an SSE HTTP endpoint that the devcontainer connects to via `.mcp.json`. However: - **UniFi**: stdio only — no SSE support - **TrueNAS**: stdio only — no SSE support - **Grafana**: unclear, needs investigation **Options to resolve:** 1. **Wait for upstream SSE support** — cleanest, but depends on external projects 2. **Use a stdio-to-SSE bridge/proxy** (e.g., `supergateway`, `mcp-proxy`) — wrap each stdio server in a proxy container that exposes SSE 3. **Configure Claude Code / Happy to connect via stdio directly** — would require running the MCP server inside the main devcontainer rather than as a sidecar, which changes the architecture ### No published Docker images - TrueNAS has no Docker image at all — would need a custom `Dockerfile` that downloads the binary - Grafana has a Dockerfile but no published image — would need to build and host it, or wait for upstream ## Proposed values.yaml structure ```yaml mcpSidecars: unifi: enabled: false image: repository: ghcr.io/enuno/unifi-mcp-server tag: 0.2.4 port: 8089 resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "256Mi" cpu: "500m" truenas: enabled: false image: repository: TBD # No published image yet tag: latest port: 8090 resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "256Mi" cpu: "500m" grafana: enabled: false image: repository: TBD # No published image yet tag: latest port: 8091 resources: requests: memory: "64Mi" cpu: "50m" limits: memory: "256Mi" cpu: "500m" ``` ## Secret keys (in env secret) - `unifi-api-key`, `unifi-api-type`, `unifi-local-host` - `truenas-url`, `truenas-api-key` - `grafana-url`, `grafana-api-key` ## Checklist - [ ] Resolve stdio-to-SSE transport for UniFi and TrueNAS - [ ] Determine Grafana MCP transport support and Docker image availability - [ ] Add UniFi MCP sidecar to deployment template and values - [ ] Add TrueNAS MCP sidecar (pending Docker image) - [ ] Add Grafana MCP sidecar (pending Docker image / SSE confirmation) - [ ] Update `.mcp.json` with new SSE endpoints - [ ] Update CLAUDE.md documentation
cpfarhood commented 2026-02-21 18:38:01 +00:00 (Migrated from github.com)

Architecture Decision: stdio inside container + alternative image

Transport Decision

Use stdio transport for UniFi, TrueNAS, and Grafana MCP servers — not sidecars. These servers only need API keys (no Kubernetes RBAC), so there's no reason for them to be separate containers. stdio is how Claude Code natively connects to MCP servers and avoids the complexity of a stdio-to-SSE bridge.

Image Strategy

Build an alternative "mcp-extras" image variant that includes the stdio MCP tools pre-installed:

ghcr.io/cpfarhood/devcontainer:latest              # base (current, slim)
ghcr.io/cpfarhood/devcontainer:latest-mcp-extras    # base + unifi, truenas, grafana MCP tools

Build approach: Multi-stage Dockerfile with a build arg (e.g., --build-arg MCP_EXTRAS=true) that conditionally installs the tools. CI builds both tags from the same Dockerfile.

Helm Integration

Select image via Helm values and enable/disable individual stdio MCP servers:

image:
  repository: ghcr.io/cpfarhood/devcontainer
  tag: latest-mcp-extras  # use mcp-extras variant

mcpStdio:
  unifi:
    enabled: false  # disabled by default
  truenas:
    enabled: false
  grafana:
    enabled: false

The Helm chart would template .mcp.json at deploy time (via ConfigMap or init script) based on which stdio servers are enabled, injecting the correct command and env entries.

.mcp.json stdio entries (when enabled)

{
  "mcpServers": {
    "unifi": {
      "type": "stdio",
      "command": "unifi-mcp-server",
      "env": {
        "UNIFI_API_KEY": "${UNIFI_API_KEY}",
        "UNIFI_API_TYPE": "${UNIFI_API_TYPE}",
        "UNIFI_LOCAL_HOST": "${UNIFI_LOCAL_HOST}"
      }
    },
    "truenas": {
      "type": "stdio",
      "command": "truenas-mcp",
      "args": ["--truenas-url", "${TRUENAS_URL}", "--api-key", "${TRUENAS_API_KEY}"]
    },
    "grafana": {
      "type": "stdio",
      "command": "mcp-grafana",
      "env": {
        "GRAFANA_URL": "${GRAFANA_URL}",
        "GRAFANA_API_KEY": "${GRAFANA_API_KEY}"
      }
    }
  }
}

What needs to be installed in the mcp-extras image

Server Install method Size impact
UniFi MCP pip install unifi-mcp-server Python package
TrueNAS MCP Download Go binary from GitHub releases Single binary (~10-20MB)
Grafana MCP Build from source or download binary (TBD) Go binary

Updated checklist

  • Add MCP_EXTRAS build arg to Dockerfile with conditional install
  • Install unifi-mcp-server (pip), truenas-mcp (binary), mcp-grafana (TBD)
  • Update CI to build both latest and latest-mcp-extras tags
  • Add mcpStdio section to values.yaml
  • Template .mcp.json in Helm chart based on enabled MCP servers (both SSE sidecars and stdio)
  • Add secret key mappings for new env vars
  • Update CLAUDE.md documentation
## Architecture Decision: stdio inside container + alternative image ### Transport Decision Use **stdio** transport for UniFi, TrueNAS, and Grafana MCP servers — not sidecars. These servers only need API keys (no Kubernetes RBAC), so there's no reason for them to be separate containers. stdio is how Claude Code natively connects to MCP servers and avoids the complexity of a stdio-to-SSE bridge. ### Image Strategy Build an alternative "mcp-extras" image variant that includes the stdio MCP tools pre-installed: ``` ghcr.io/cpfarhood/devcontainer:latest # base (current, slim) ghcr.io/cpfarhood/devcontainer:latest-mcp-extras # base + unifi, truenas, grafana MCP tools ``` **Build approach:** Multi-stage Dockerfile with a build arg (e.g., `--build-arg MCP_EXTRAS=true`) that conditionally installs the tools. CI builds both tags from the same Dockerfile. ### Helm Integration Select image via Helm values and enable/disable individual stdio MCP servers: ```yaml image: repository: ghcr.io/cpfarhood/devcontainer tag: latest-mcp-extras # use mcp-extras variant mcpStdio: unifi: enabled: false # disabled by default truenas: enabled: false grafana: enabled: false ``` The Helm chart would template `.mcp.json` at deploy time (via ConfigMap or init script) based on which stdio servers are enabled, injecting the correct `command` and `env` entries. ### .mcp.json stdio entries (when enabled) ```json { "mcpServers": { "unifi": { "type": "stdio", "command": "unifi-mcp-server", "env": { "UNIFI_API_KEY": "${UNIFI_API_KEY}", "UNIFI_API_TYPE": "${UNIFI_API_TYPE}", "UNIFI_LOCAL_HOST": "${UNIFI_LOCAL_HOST}" } }, "truenas": { "type": "stdio", "command": "truenas-mcp", "args": ["--truenas-url", "${TRUENAS_URL}", "--api-key", "${TRUENAS_API_KEY}"] }, "grafana": { "type": "stdio", "command": "mcp-grafana", "env": { "GRAFANA_URL": "${GRAFANA_URL}", "GRAFANA_API_KEY": "${GRAFANA_API_KEY}" } } } } ``` ### What needs to be installed in the mcp-extras image | Server | Install method | Size impact | |--------|---------------|-------------| | UniFi MCP | `pip install unifi-mcp-server` | Python package | | TrueNAS MCP | Download Go binary from GitHub releases | Single binary (~10-20MB) | | Grafana MCP | Build from source or download binary (TBD) | Go binary | ### Updated checklist - [ ] Add `MCP_EXTRAS` build arg to Dockerfile with conditional install - [ ] Install `unifi-mcp-server` (pip), `truenas-mcp` (binary), `mcp-grafana` (TBD) - [ ] Update CI to build both `latest` and `latest-mcp-extras` tags - [ ] Add `mcpStdio` section to `values.yaml` - [ ] Template `.mcp.json` in Helm chart based on enabled MCP servers (both SSE sidecars and stdio) - [ ] Add secret key mappings for new env vars - [ ] Update CLAUDE.md documentation
cpfarhood commented 2026-02-24 11:18:42 +00:00 (Migrated from github.com)

This should really be a separate container/image, maybe infracontainer?

This should really be a separate container/image, maybe infracontainer?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: farhoodlabs/devcontainer#29