Pi-hole MCP Server

Quản lý phiên bản Pi-hole v6 của bạn với 55 công cụ bao gồm chặn DNS, quản lý tên miền, phân tích truy vấn, thống kê, DHCP và quản trị hệ thống.

Tài liệu

pihole-mcp

pihole-mcp

A production-grade MCP server for Pi-hole v6.

77 tools | 9 prompts | 5 resources | Multi-instance + sync | Single Go binary | ~6MB compressed (slim: ~3.5MB)

Licence: MIT Go Report Card CI

Gives AI assistants full control over your Pi-hole instance — DNS blocking, domain management, query analysis, statistics, network devices, DHCP, and system administration. Compatible with the Pi-hole v6 REST API.

Quick Start

Most MCP clients use the same configuration format. Add this to your client's config:

{
  "mcpServers": {
    "pihole": {
      "command": "pihole-mcp",
      "env": {
        "PIHOLE_URL": "http://192.168.1.2",
        "PIHOLE_PASSWORD": "your-password"
      }
    }
  }
}

Then install the binary via one of the methods below.

Installation

Homebrew

brew install hexamatic/tap/pihole-mcp

Scoop (Windows)

scoop bucket add hexamatic https://github.com/hexamatic/scoop-bucket
scoop install pihole-mcp

Go Install

go install github.com/hexamatic/pihole-mcp/cmd/pihole-mcp@latest

Docker

docker pull ghcr.io/hexamatic/pihole-mcp:latest

Linux Packages

.deb and .rpm packages for Debian-based (Ubuntu, Raspberry Pi OS) and RPM-based (Fedora, RHEL) distributions are available on the Releases page.

# Debian / Ubuntu / Raspberry Pi OS
sudo dpkg -i pihole-mcp_X.Y.Z_linux_amd64.deb

# Fedora / RHEL / CentOS
sudo rpm -i pihole-mcp_X.Y.Z_linux_amd64.rpm

Binary Download

Pre-built binaries for Linux, macOS, and Windows (amd64 and arm64) are available on the Releases page.

Configuration

VariableRequiredDefaultDescription
PIHOLE_URLYesPi-hole base URL (e.g. http://192.168.1.2)
PIHOLE_PASSWORDYesAdmin password or application password
PIHOLE_REQUEST_TIMEOUTNo30sHTTP request timeout
PIHOLE_RATE_LIMITNo120Per-session requests-per-minute cap on the HTTP/SSE transports. 0 disables.
PIHOLE_ALLOWED_ORIGINSNolocalhost,127.0.0.1,[::1]Comma-separated Origin/Host allowlist for HTTP/SSE transports. The literal * disables enforcement (unsafe).

Application passwords are recommended for automation — they bypass TOTP 2FA and can be revoked independently.

PIHOLE_RATE_LIMIT and PIHOLE_ALLOWED_ORIGINS only apply to the http and sse transports; stdio is a single-process, single-user channel by definition and isn't gated.

Multiple instances

To manage more than one Pi-hole, configure numbered instances instead of PIHOLE_URL/PIHOLE_PASSWORD:

VariableRequiredDescription
PIHOLE_1_URL, PIHOLE_2_URL, …YesBase URL of each instance (contiguous from 1)
PIHOLE_1_PASSWORD, PIHOLE_2_PASSWORD, …YesPassword for the matching instance
PIHOLE_1_NAME, PIHOLE_2_NAME, …NoFriendly name (default instance-1, instance-2, …)
{
  "mcpServers": {
    "pihole": {
      "command": "pihole-mcp",
      "env": {
        "PIHOLE_1_URL": "http://192.168.1.2",
        "PIHOLE_1_PASSWORD": "primary-password",
        "PIHOLE_1_NAME": "downstairs",
        "PIHOLE_2_URL": "http://192.168.1.3",
        "PIHOLE_2_PASSWORD": "secondary-password",
        "PIHOLE_2_NAME": "upstairs"
      }
    }
  }
}

Every tool then accepts an optional instance argument, and every result is labelled with the instance it came from. Omit the argument to target the first instance; pass a name to target a specific one; pass instance=all on a read-only tool (e.g. pihole_padd, pihole_stats_summary) to query every instance concurrently and get back a single structured aggregate (per-instance results plus a success/failure summary — one slow or unreachable instance no longer fails the whole call). State-changing tools require a single named instance. PIHOLE_URL and PIHOLE_1_URL are mutually exclusive.

Keeping instances in sync

When you run more than one Pi-hole, two extra tools appear for keeping them aligned:

  • pihole_instance_diff — compare two instances and see exactly what differs across adlists/allowlists, allow/deny rules (exact and regex), groups, clients, local DNS A/AAAA records, and CNAME records. It is read-only and writes nothing.
  • pihole_instance_sync — push a source instance's configuration onto a target. It is deliberately cautious:
    • One direction only. You name the source of truth and the target; only the target is ever written to.
    • Dry-run first. It returns a plan and a confirm_token by default; nothing changes until you re-run with mode=apply and that token. If the configuration drifts between planning and applying, the token no longer matches and the apply is refused.
    • Add/update by default. Entries on the target but not the source are left alone unless you pass prune=true.
    • Backed up. A teleporter backup of the target is taken before any change (disable with snapshot=false).
    • Safe by omission. Host-specific and identity settings — DHCP, interface bindings, passwords, TLS certificates, sessions, 2FA — are never synced. Group membership associations are not synced either, because Pi-hole group IDs are local to each instance.

Example: preview what the upstairs Pi-hole is missing relative to downstairs, then apply it.

pihole_instance_diff   { "source": "downstairs", "target": "upstairs" }
pihole_instance_sync   { "source": "downstairs", "target": "upstairs" }            → returns a plan + confirm_token
pihole_instance_sync   { "source": "downstairs", "target": "upstairs",
                         "mode": "apply", "confirm_token": "<token from the plan>" }

Client Setup

The Quick Start config above works for most clients. Expand the section below for client-specific instructions.

Claude Desktop

Add to your Claude Desktop configuration file:

OSPath
macOS~/Library/Application Support/Claude/claude_desktop_config.json
Windows%APPDATA%\Claude\claude_desktop_config.json
Linux~/.config/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "pihole": {
      "command": "pihole-mcp",
      "env": {
        "PIHOLE_URL": "http://192.168.1.2",
        "PIHOLE_PASSWORD": "your-password"
      }
    }
  }
}

Restart Claude Desktop after saving.

Claude Code
claude mcp add pihole \
  -e PIHOLE_URL=http://192.168.1.2 \
  -e PIHOLE_PASSWORD=your-password \
  -- pihole-mcp

Verify with:

claude mcp list
VS Code (GitHub Copilot)

Add to .vscode/mcp.json in your workspace:

{
  "servers": {
    "pihole": {
      "type": "stdio",
      "command": "pihole-mcp",
      "env": {
        "PIHOLE_URL": "http://192.168.1.2",
        "PIHOLE_PASSWORD": "your-password"
      }
    }
  }
}

Or add via the command palette: MCP: Add Server.

Note: VS Code uses "servers" as the top-level key (not "mcpServers"), and requires "type": "stdio".

Cursor

Add to ~/.cursor/mcp.json:

{
  "mcpServers": {
    "pihole": {
      "command": "pihole-mcp",
      "env": {
        "PIHOLE_URL": "http://192.168.1.2",
        "PIHOLE_PASSWORD": "your-password"
      }
    }
  }
}
Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "pihole": {
      "command": "pihole-mcp",
      "env": {
        "PIHOLE_URL": "http://192.168.1.2",
        "PIHOLE_PASSWORD": "your-password"
      }
    }
  }
}
Cline

Open Cline settings > MCP Servers > Configure, and add:

{
  "mcpServers": {
    "pihole": {
      "command": "pihole-mcp",
      "env": {
        "PIHOLE_URL": "http://192.168.1.2",
        "PIHOLE_PASSWORD": "your-password"
      }
    }
  }
}
Docker (any client)

For clients that support Docker-based MCP servers:

{
  "mcpServers": {
    "pihole": {
      "command": "docker",
      "args": ["run", "-i", "--rm",
        "-e", "PIHOLE_URL=http://192.168.1.2",
        "-e", "PIHOLE_PASSWORD=your-password",
        "ghcr.io/hexamatic/pihole-mcp:latest"]
    }
  }
}

Useful when you don't have Go installed or want to run the server on a remote host.

Tools

Dashboard

ToolDescription
pihole_paddOne-call snapshot: queries, blocking, top domain/client, cache, versions, host health

DNS Control

ToolDescription
pihole_dns_get_blockingGet current DNS blocking status and timer
pihole_dns_set_blockingEnable/disable blocking with optional timer

Statistics

ToolDescription
pihole_stats_summaryQueries, blocking rate, clients, gravity size
pihole_stats_top_domainsTop queried or blocked domains
pihole_stats_top_clientsMost active clients by query count
pihole_stats_upstreamsUpstream DNS server performance
pihole_stats_query_typesQuery type distribution (A, AAAA, MX, etc.)
pihole_stats_recent_blockedRecently blocked domains
pihole_stats_databaseLong-term database statistics

Domain Management

ToolDescription
pihole_domains_listList allow/deny domains
pihole_domains_addAdd domains (bulk supported)
pihole_domains_updateUpdate domain entry
pihole_domains_deleteRemove a domain
pihole_domains_batch_deleteRemove multiple domains

Groups, Clients, Lists

ToolDescription
pihole_groups_list/add/update/delete/batch_deleteManage groups
pihole_clients_list/suggestions/add/update/deleteManage clients
pihole_lists_list/add/update/delete/batch_deleteManage blocklists/allowlists

Query Log

ToolDescription
pihole_queries_searchSearch queries with 12 filters + cursor pagination
pihole_queries_suggestionsAvailable filter values

System

ToolDescription
pihole_info_systemHost, CPU, memory, disk, load, temperature
pihole_info_versionPi-hole component versions
pihole_info_databaseDatabase size and query count
pihole_info_messagesFTL diagnostic messages
pihole_search_domainsCross-list domain search
pihole_config_get/setRead/modify Pi-hole configuration
pihole_config_get_value/add_value/remove_valueGranular dotted-path config access
pihole_config_propertiesList read-only config keys (Pi-hole v6.6.1+)

Actions and Network

ToolDescription
pihole_action_gravity_updateRe-download blocklists
pihole_action_restart_dnsRestart FTL DNS resolver
pihole_action_flush_logs/networkFlush logs or network table
pihole_network_devices/gateway/infoNetwork device discovery
pihole_dhcp_leases/delete_leaseDHCP lease management
pihole_logs_dns/ftl/webserverLog retrieval
pihole_teleporter_export/importConfiguration backup and restore
pihole_history_graph/clientsActivity history

Multi-instance (only with more than one Pi-hole configured)

ToolDescription
pihole_instance_diffCompare configuration between two instances
pihole_instance_syncReconcile a target instance towards a source (dry-run plan, then confirmed apply)

Response Options

Most tools accept optional parameters for controlling output:

  • detail (minimal | normal | full) — Controls response depth. Default: normal. Use minimal for one-line summaries, full for complete API data.
  • format (text | csv) — Output format for tabular data. Default: text. CSV saves ~29% tokens. Available on pihole_domains_list, pihole_lists_list, pihole_clients_list, pihole_queries_search, pihole_network_devices, pihole_stats_top_domains, pihole_stats_top_clients, pihole_stats_upstreams, pihole_stats_query_types, pihole_stats_recent_blocked, pihole_stats_database_top_domains, pihole_stats_database_top_clients, pihole_stats_database_upstreams, pihole_dhcp_leases, and pihole_config_properties.

Prompts

Pre-built multi-step workflows for common tasks:

PromptDescription
diagnose_slow_dnsAnalyse upstream performance and identify bottlenecks
investigate_domainCheck why a domain is blocked/allowed across all lists
review_top_blockedIdentify false positives in top blocked domains
audit_networkDiscover unknown devices and unconfigured clients
optimise_blocklistsSuggest list consolidation and cleanup
daily_reportComprehensive daily Pi-hole health summary

Advanced Configuration

Transport

By default, pihole-mcp uses stdio (standard for MCP). HTTP and SSE transports are also available:

# Default stdio (for Claude Desktop, Cursor, etc.)
pihole-mcp

# HTTP transport (for web-based MCP clients)
pihole-mcp -transport http -address localhost:8080

# SSE transport
pihole-mcp -transport sse -address localhost:8080

Security (HTTP and SSE transports)

The http and sse transports apply two security middlewares to every request, in line with the MCP 2025-11-25 spec's DNS-rebinding protection guidance. stdio is unaffected (single-process, single-user).

  • Origin and Host validation. Both headers must resolve to a host in PIHOLE_ALLOWED_ORIGINS (default loopback only). Missing Origin is allowed for non-browser MCP clients. Mismatches return HTTP 403. To expose pihole-mcp on a LAN, extend the allowlist:

    export PIHOLE_ALLOWED_ORIGINS="localhost,127.0.0.1,[::1],pihole-mcp.lan"
    

    The literal * disables enforcement entirely — only use it if you're behind a reverse proxy doing its own access control.

  • Per-session rate limiting. A token bucket keyed by Mcp-Session-Id (fallback to client IP) caps requests at PIHOLE_RATE_LIMIT per minute (default 120, burst max(120/4, 30)). Throttled requests return HTTP 429 with Retry-After: 1. 0 disables.

    # Tighter limit for a small fleet
    export PIHOLE_RATE_LIMIT=60
    
    # Disable (only when running behind a proxy with its own rate limit)
    export PIHOLE_RATE_LIMIT=0
    

OpenTelemetry

Tracing is opt-in. Set OTEL_EXPORTER_OTLP_ENDPOINT to enable:

export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
pihole-mcp

All tool calls are automatically traced with tool name, duration, and error status.

If you don't need tracing, you can build a slim binary that strips the OpenTelemetry SDK, gRPC, protobuf, and grpc-gateway dependencies entirely (~45% smaller — from 17 MB to 9 MB stripped, 6 MB to 3.5 MB compressed):

just build-slim
# or
go build -tags slim -o bin/pihole-mcp-slim ./cmd/pihole-mcp

The slim binary is functionally identical apart from OTEL_EXPORTER_OTLP_ENDPOINT being ignored.

Development

# Prerequisites: Go 1.26+, Docker, mise, just

# One-command setup
just setup

# Start local Pi-hole (http://localhost:8081, password: test)
just dev-up

# Run quality checks (format + lint + test)
just check

# Run integration tests against local Pi-hole
just integration

# Build binary
just build

See CONTRIBUTING.md for full development guidelines.


Pi-hole is a registered trademark of Pi-hole LLC. This project is independently maintained and is not affiliated with, endorsed by, or sponsored by Pi-hole LLC.

Licence

MIT