nginx-proxy-manager-mcp
Enables AI agents to manage Nginx Proxy Manager (reverse proxies, streams, redirects, and Let's Encrypt certificates) through natural language commands.
README
nginx-proxy-manager-mcp
A Model Context Protocol server that exposes the Nginx Proxy Manager (NPM) REST API to AI agents. Let assistants like Claude Desktop, Hermes, Cursor, or any MCP-compatible client create reverse proxies, TCP/UDP streams, redirects, 404 hosts, and request/renew Let's Encrypt certificates for you — in plain English.
"Hey Hermes, point
grafana.example.comat192.168.1.50:3000and get a Let's Encrypt cert for it." →npm_create_proxy_host+npm_create_certificate+npm_update_proxy_host
Features
- Proxy hosts — create / list / update / delete / enable / disable reverse proxies
- Streams — TCP & UDP port forwarding
- Redirection hosts — domain → domain redirects (301/302)
- Dead (404) hosts — return 404 for parked/unused domains
- Certificates — request Let's Encrypt (HTTP-01 or DNS-01), renew, delete, download
- Users & audit log — inspect users and recent actions
- Raw passthrough —
npm_raw_requestfor anything not covered - 30 tools total, all typed with JSON schemas for reliable agent use
- Two transports —
stdio(default, for local agents) and Streamablehttp - No runtime deps besides the official MCP SDK + zod
Quick start
1. Install
git clone https://github.com/linuskang/nginx-proxy-manager-mcp.git
cd nginx-proxy-manager-mcp
npm install
npm run build
Or run directly without cloning (npx once published):
npx nginx-proxy-manager-mcp
2. Configure
Copy .env.example → .env and fill in your NPM admin credentials:
cp .env.example .env
| Variable | Required | Description |
|---|---|---|
NPM_BASE_URL |
✅ | Base URL of NPM, e.g. http://npm.local:81 (no trailing slash) |
NPM_EMAIL |
✅* | Admin email (NPM_TOKEN alternative) |
NPM_PASSWORD |
✅* | Admin password (NPM_TOKEN alternative) |
NPM_TOKEN |
✅* | Pre-existing JWT token (takes precedence over email/password) |
NPM_TIMEOUT_MS |
❌ | Request timeout, default 30000 |
NPM_DEBUG |
❌ | Verbose stderr logging, default false |
MCP_TRANSPORT |
❌ | stdio (default) or http |
MCP_PORT |
❌ | HTTP port, default 3000 |
MCP_HOST |
❌ | HTTP bind address, default 0.0.0.0 |
MCP_ENDPOINT |
❌ | HTTP endpoint path, default /mcp |
* Provide either NPM_TOKEN or both NPM_EMAIL + NPM_PASSWORD.
3. Wire it up to your agent
Claude Desktop (or Claude Code)
Edit claude_desktop_config.json (macOS:
~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"nginx-proxy-manager": {
"command": "node",
"args": ["D:/Code/Git/nginx-proxy-manager-mcp/dist/index.js"],
"env": {
"NPM_BASE_URL": "http://npm.local:81",
"NPM_EMAIL": "[email protected]",
"NPM_PASSWORD": "your-password",
},
},
},
}
Hermes
In your Hermes agent config (or MCP registry), add a server entry pointing at the
same command/env above. Hermes speaks standard MCP over stdio, so no special
setup is needed — just point it at node dist/index.js with your NPM_* env.
Remote / HTTP transport (browser agents, remote runners)
MCP_TRANSPORT=http MCP_PORT=3000 MCP_HOST=0.0.0.0 node dist/index.js
# POST your JSON-RPC messages to http://localhost:3000/mcp
Available tools (30)
Proxy hosts
| Tool | Description |
|---|---|
npm_list_proxy_hosts |
List all reverse proxies |
npm_get_proxy_host |
Get one by id |
npm_create_proxy_host |
Create a reverse proxy (the headline tool) |
npm_update_proxy_host |
Update fields on an existing proxy |
npm_delete_proxy_host |
Delete by id |
npm_enable_proxy_host |
Enable a disabled proxy |
npm_disable_proxy_host |
Disable a proxy (without deleting) |
Streams (TCP/UDP port forwarding)
| Tool | Description |
|---|---|
npm_list_streams |
List all streams |
npm_get_stream |
Get one by id |
npm_create_stream |
Create a TCP/UDP port forward |
npm_update_stream |
Update a stream |
npm_delete_stream |
Delete a stream |
Redirection hosts
| Tool | Description |
|---|---|
npm_list_redirection_hosts |
List redirections |
npm_create_redirection_host |
Create a redirect (301/302) |
npm_update_redirection_host |
Update a redirect |
npm_delete_redirection_host |
Delete a redirect |
Dead (404) hosts
| Tool | Description |
|---|---|
npm_list_dead_hosts |
List 404 hosts |
npm_create_dead_host |
Create a 404 host |
npm_update_dead_host |
Update a 404 host |
npm_delete_dead_host |
Delete a 404 host |
Certificates (Let's Encrypt & custom)
| Tool | Description |
|---|---|
npm_list_certificates |
List all certificates |
npm_create_certificate |
Request a new Let's Encrypt cert (HTTP-01 or DNS-01) |
npm_renew_certificate |
Renew an existing cert |
npm_delete_certificate |
Delete a certificate |
npm_download_certificate |
Download cert / private key / chain (PEM) |
Users, audit & power tools
| Tool | Description |
|---|---|
npm_ping |
Health check the NPM instance |
npm_list_users |
List NPM users |
npm_get_user |
Get a user by id |
npm_list_audit_log |
Browse recent audit log entries |
npm_raw_request |
Authenticated escape hatch to any /api/... endpoint |
Example: create a proxy host
// npm_create_proxy_host
{
"domain_names": ["grafana.example.com"],
"forward_scheme": "http",
"forward_host": "192.168.1.50",
"forward_port": 3000,
"block_exploits": true,
"allow_websocket_upgrade": true,
"certificate_id": 0,
"ssl_forced": false,
"enabled": true,
}
A natural-language request like "Proxy grafana.example.com → 192.168.1.50:3000
with a Let's Encrypt cert" will typically run npm_create_proxy_host, then
npm_create_certificate (provider letsencrypt), then
npm_update_proxy_host with the returned certificate_id and ssl_forced: true.
Deploying with Docker
A prebuilt multi-arch image (linux/amd64 + linux/arm64) is published to the
GitHub Container Registry on every push to main/master and on version tags:
docker pull ghcr.io/linuskang/nginx-proxy-manager-mcp:latest
Image tags: latest, :vX.Y.Z, :X.Y, :X, :sha-<short>, :master.
Which transport? Use stdio when the agent runs on the same machine (Claude Desktop, Hermes, Cursor) and you launch the container as a child process. Use http when a remote agent or browser client needs to POST JSON-RPC over the network.
Option A — stdio (local agent on the same machine)
Your agent config launches the container and speaks MCP over its stdin/stdout.
Point the agent's command at docker and pass run -i --rm plus the env vars:
// Claude Desktop / Hermes MCP server config
{
"mcpServers": {
"nginx-proxy-manager": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"NPM_BASE_URL",
"-e",
"NPM_EMAIL",
"-e",
"NPM_PASSWORD",
"ghcr.io/linuskang/nginx-proxy-manager-mcp:latest",
],
"env": {
"NPM_BASE_URL": "http://your-npm-host:81",
"NPM_EMAIL": "[email protected]",
"NPM_PASSWORD": "your-password",
},
},
},
}
-i keeps stdin open so the agent can talk to the server; --rm cleans up the
container when the agent exits. No port is published because stdio doesn't need
one. Transport defaults to stdio, so you don't have to set MCP_TRANSPORT.
Option B — HTTP (remote / networked agents)
Expose a Streamable HTTP endpoint that any MCP client can POST to:
docker run -d --name npm-mcp \
-p 3000:3000 \
-e MCP_TRANSPORT=http \
-e MCP_PORT=3000 \
-e MCP_HOST=0.0.0.0 \
-e NPM_BASE_URL=http://your-npm-host:81 \
-e [email protected] \
-e NPM_PASSWORD=your-password \
ghcr.io/linuskang/nginx-proxy-manager-mcp:latest
MCP endpoint: http://localhost:3000/mcp
Verify it's up:
curl -s http://localhost:3000/mcp -X POST \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'
You should get a JSON-RPC response with serverInfo.name == "nginx-proxy-manager-mcp".
Point your agent at the URL and it will initialize, call tools/list, and
start driving your NPM instance.
Option C — docker compose
For a persistent HTTP deployment, use the bundled docker-compose.yml:
cp .env.example .env
# edit .env: set NPM_BASE_URL, NPM_EMAIL, NPM_PASSWORD,
# MCP_TRANSPORT=http, MCP_PORT=3000, MCP_HOST=0.0.0.0
docker compose up -d
Logs:
docker compose logs -f
Stop / remove:
docker compose down
Putting NPM and the MCP server on the same Docker network (recommended)
If Nginx Proxy Manager itself runs in Docker, put the MCP container on the same network so you can address NPM by service name — no published ports needed:
docker network create npm-net
docker network connect npm-mcp npm-net # if MCP created its own net
docker network connect <npm-container> npm-net # for the NPM container
Then set NPM_BASE_URL=http://<npm-service-name>:81 (e.g. http://npm:81) and
the MCP server talks to NPM over the private bridge.
Build locally (optional, same Dockerfile used by CI)
docker build -t nginx-proxy-manager-mcp .
# stdio:
docker run -i --rm \
-e NPM_BASE_URL=http://npm:81 -e NPM_EMAIL=a@b.c -e NPM_PASSWORD=secret \
nginx-proxy-manager-mcp
# http:
docker run -d -p 3000:3000 \
-e MCP_TRANSPORT=http -e MCP_PORT=3000 -e MCP_HOST=0.0.0.0 \
-e NPM_BASE_URL=http://npm:81 -e NPM_EMAIL=a@b.c -e NPM_PASSWORD=secret \
nginx-proxy-manager-mcp
Troubleshooting
npm:54/ connection refused on port 81 —NPM_BASE_URLmust point at the admin API port (81), not 80/443. If NPM is in another container, use the service name and a shared Docker network.NPM_TOKEN or both NPM_EMAIL and NPM_PASSWORD must be set— provide either a JWT (NPM_TOKEN) or an email + password pair.- Tools call returns HTTP 401 — your token expired or the credentials are
wrong. Remove
NPM_TOKENto fall back to email/password auto-refresh, or regenerate the token from the NPM UI. - Want to debug requests? Set
-e NPM_DEBUG=trueto log every request URL to stderr (docker logs -f npm-mcp).
Development
npm install # install deps
npm run dev # run from source (tsx)
npm run build # compile to dist/
npm run typecheck # typecheck only
npm run lint # eslint
npm run format # prettier write
npm run check # lint + typecheck + format:check
Project layout:
src/
config.ts # env-based configuration
types.ts # NPM API TypeScript types
client.ts # NPM REST client (auth, retry, JSON)
index.ts # MCP server + stdio/http transports
tools/
_shared.ts # tool helpers (ok/fail/guard)
proxy-hosts.ts
streams.ts
redirection-hosts.ts
dead-hosts.ts
certificates.ts
misc.ts # ping, users, audit, raw request
index.ts # aggregator
Compatibility
- Nginx Proxy Manager 2.x (REST API on port 81)
- Node.js ≥ 18 (uses global
fetch,AbortSignal.timeout) - MCP protocol version 2024-11-05 and later
Security notes
- Credentials are passed via environment variables only — never logged unless
NPM_DEBUGis on (and even then, only request URLs, never the password). - The exposed tools use your NPM admin token, so they can do anything an admin can. Run this server in a trusted environment and restrict network exposure.
- Prefer scoped NPM users if your deployment supports it.
Contributing
PRs welcome! Please open an issue first for larger changes. Run npm run check
before submitting. See CONTRIBUTING.md.
License
Licensed under Creative Commons Attribution-NonCommercial 4.0 International
(CC BY-NC 4.0) — see
LICENSE. You are free to share and adapt for non-commercial
purposes with attribution. Commercial use requires a separate license from the
author.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.