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.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。