nginx-proxy-manager-mcp-server 0.5.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nginx_proxy_manager_mcp_server-0.5.1/LICENSE +21 -0
- nginx_proxy_manager_mcp_server-0.5.1/PKG-INFO +313 -0
- nginx_proxy_manager_mcp_server-0.5.1/README.md +293 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/__init__.py +0 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/auth.py +55 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/npm_client.py +101 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/py.typed +0 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/server.py +70 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/tools/__init__.py +0 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/tools/access_lists.py +100 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/tools/payloads.py +50 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/tools/previews.py +15 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/tools/proxy_hosts.py +246 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/tools/redirection_hosts.py +141 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/tools/ssl_certs.py +55 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/tools/streams.py +124 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp/validation.py +134 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp_server.egg-info/PKG-INFO +313 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp_server.egg-info/SOURCES.txt +33 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp_server.egg-info/dependency_links.txt +1 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp_server.egg-info/entry_points.txt +3 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp_server.egg-info/requires.txt +2 -0
- nginx_proxy_manager_mcp_server-0.5.1/nginx_proxy_manager_mcp_server.egg-info/top_level.txt +1 -0
- nginx_proxy_manager_mcp_server-0.5.1/pyproject.toml +42 -0
- nginx_proxy_manager_mcp_server-0.5.1/setup.cfg +4 -0
- nginx_proxy_manager_mcp_server-0.5.1/tests/test_access_lists.py +95 -0
- nginx_proxy_manager_mcp_server-0.5.1/tests/test_auth.py +99 -0
- nginx_proxy_manager_mcp_server-0.5.1/tests/test_npm_client.py +124 -0
- nginx_proxy_manager_mcp_server-0.5.1/tests/test_proxy_hosts.py +189 -0
- nginx_proxy_manager_mcp_server-0.5.1/tests/test_redirection_hosts.py +89 -0
- nginx_proxy_manager_mcp_server-0.5.1/tests/test_server.py +51 -0
- nginx_proxy_manager_mcp_server-0.5.1/tests/test_ssl_certs.py +60 -0
- nginx_proxy_manager_mcp_server-0.5.1/tests/test_streams.py +90 -0
- nginx_proxy_manager_mcp_server-0.5.1/tests/test_update_readonly_fields.py +108 -0
- nginx_proxy_manager_mcp_server-0.5.1/tests/test_validation.py +123 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 euisuh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nginx-proxy-manager-mcp-server
|
|
3
|
+
Version: 0.5.1
|
|
4
|
+
Summary: MCP server for Nginx Proxy Manager: proxy hosts, certificates, streams and access lists with dry-run previews
|
|
5
|
+
Author: Euisuh Jeong
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/euisuh/nginx-proxy-manager-mcp
|
|
8
|
+
Project-URL: Repository, https://github.com/euisuh/nginx-proxy-manager-mcp
|
|
9
|
+
Project-URL: Issues, https://github.com/euisuh/nginx-proxy-manager-mcp/issues
|
|
10
|
+
Keywords: mcp,nginx-proxy-manager,homelab,reverse-proxy
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Topic :: System :: Systems Administration
|
|
14
|
+
Requires-Python: >=3.12
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: fastmcp>=2.0.0
|
|
18
|
+
Requires-Dist: httpx>=0.27.0
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# Nginx Proxy Manager MCP
|
|
22
|
+
|
|
23
|
+
<!-- mcp-name: io.github.euisuh/nginx-proxy-manager-mcp -->
|
|
24
|
+
|
|
25
|
+
[](https://github.com/euisuh/nginx-proxy-manager-mcp/actions/workflows/ci.yml)
|
|
26
|
+
[](https://github.com/euisuh/nginx-proxy-manager-mcp/actions/workflows/docker.yml)
|
|
27
|
+
[](https://github.com/euisuh/nginx-proxy-manager-mcp/actions/workflows/python-package.yml)
|
|
28
|
+
[](LICENSE)
|
|
29
|
+
|
|
30
|
+
An MCP server for [Nginx Proxy Manager](https://nginxproxymanager.com/). It lets Claude and other MCP clients manage reverse-proxy hosts, Let's Encrypt certificates, and access lists through typed tools instead of clicking through the NPM admin UI.
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
"Point blog.example.com at the container on port 3000 with HTTPS"
|
|
34
|
+
│
|
|
35
|
+
▼
|
|
36
|
+
Claude / MCP client ──► Nginx Proxy Manager MCP ──HTTP + JWT──► NPM API
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
The demo calls `create_proxy_host_with_letsencrypt(dry_run=True)` against a mocked NPM API and prints both request previews. No real NPM instance or credentials are used. To record it again, install the development dependencies and VHS, then run `vhs docs/demo.tape` from the repository root; [`docs/demo.py`](docs/demo.py) uses the same respx mocking approach as the tests.
|
|
42
|
+
|
|
43
|
+
## Why this exists
|
|
44
|
+
|
|
45
|
+
Reverse-proxy changes are repetitive homelab work: create a host, point it at a container, attach a certificate, maybe restrict it to an access list. That is exactly the kind of operational task an AI assistant can handle well when it has narrow, typed tools and a local admin boundary.
|
|
46
|
+
|
|
47
|
+
This server runs either:
|
|
48
|
+
|
|
49
|
+
- as an SSE Docker sidecar next to an existing NPM container, or
|
|
50
|
+
- as a stdio MCP server for local clients.
|
|
51
|
+
|
|
52
|
+
## Features
|
|
53
|
+
|
|
54
|
+
- 30 MCP tools for common NPM operations.
|
|
55
|
+
- `dry_run` on all mutating tools to preview NPM requests before applying them;
|
|
56
|
+
- One-shot `create_proxy_host_with_letsencrypt` requests a certificate, then creates an HTTPS-forced proxy host.
|
|
57
|
+
- JWT auth against the NPM API with in-memory token caching and automatic re-authentication on `401`.
|
|
58
|
+
- Docker sidecar deployment that binds the MCP port to localhost by default.
|
|
59
|
+
- Offline pytest suite with mocked NPM API responses.
|
|
60
|
+
- Ruff quality gate and contributor templates for public maintenance.
|
|
61
|
+
- Python wheel build validation and MCP directory metadata for promotion readiness.
|
|
62
|
+
- No token persistence and no hardcoded credentials.
|
|
63
|
+
|
|
64
|
+
## Tools
|
|
65
|
+
|
|
66
|
+
| Category | Tools |
|
|
67
|
+
|---|---|
|
|
68
|
+
| Workflows | `create_proxy_host_with_letsencrypt` |
|
|
69
|
+
| Proxy hosts | `list_proxy_hosts`, `get_proxy_host`, `create_proxy_host`, `update_proxy_host`, `delete_proxy_host`, `enable_proxy_host`, `disable_proxy_host` |
|
|
70
|
+
| Redirection hosts | `list_redirection_hosts`, `get_redirection_host`, `create_redirection_host`, `update_redirection_host`, `delete_redirection_host`, `enable_redirection_host`, `disable_redirection_host` |
|
|
71
|
+
| Streams | `list_streams`, `get_stream`, `create_stream`, `update_stream`, `delete_stream`, `enable_stream`, `disable_stream` |
|
|
72
|
+
| SSL certs | `list_certificates`, `create_letsencrypt_cert`, `renew_certificate` |
|
|
73
|
+
| Access lists | `list_access_lists`, `get_access_list`, `create_access_list`, `update_access_list`, `delete_access_list` |
|
|
74
|
+
|
|
75
|
+
All mutating tools expose `dry_run=True`. Previews contain `method` and `path`, plus `json` when the request has a body; the HTTPS workflow returns two previews in `steps`. The flag suppresses mutating requests, though some previews read current state. Update tools send only the fields in NPM's PUT schema (fixes [#19](https://github.com/euisuh/nginx-proxy-manager-mcp/issues/19)); this is covered by mocked tests and not yet checked against a live NPM instance.
|
|
76
|
+
|
|
77
|
+
## Compared to other NPM MCP servers
|
|
78
|
+
|
|
79
|
+
Competitor facts below come only from their linked READMEs fetched with `gh api repos/<owner>/nginx-proxy-manager-mcp/readme` on 2026-10-13. “not documented” means the README does not establish the capability, not that it is absent. Auth guard means inbound MCP client authentication, distinct from NPM API login.
|
|
80
|
+
|
|
81
|
+
| Repository | Tool count documented | Dry-run support | Transport | Auth guard |
|
|
82
|
+
|---|---:|---|---|---|
|
|
83
|
+
| [euisuh (this server)](https://github.com/euisuh/nginx-proxy-manager-mcp) | 30 | `dry_run` on all mutating tools | stdio, SSE | Optional SSE bearer token (`MCP_BEARER_TOKEN`); `/healthz` exempt |
|
|
84
|
+
| [b3nw](https://github.com/b3nw/nginx-proxy-manager-mcp/blob/725d323b96c5d4e88790b8c88ea790a1133fc2d1/README.md) | 14 named tools (13 catalog rows plus `list_instances`) | not documented | stdio, HTTP | HTTP bearer token (`NPM_MCP_AUTH_TOKEN`) |
|
|
85
|
+
| [omichelbraga](https://github.com/omichelbraga/nginx-proxy-manager-mcp/blob/c6568f0f090c8a087ac9f3a56ac468c139e0a3cb/README.md) | 66 | DELETE without `confirm: true` previews affected resources; general `dry_run` not documented | stdio, Streamable HTTP | Optional bearer token (`NPM_MCP_BEARER_TOKEN`); unset means no inbound auth |
|
|
86
|
+
| [drmogie](https://github.com/drmogie/nginx-proxy-manager-mcp/blob/91c4176b544de6b64b9d16ff6dc891a352951145/README.md) | 4 named tools (`npm_status`, `npm_hosts`, `npm_audit_log`, `npm_call`) | Changes show what will be sent and require `confirm`; `dry_run` not documented | not documented | not documented |
|
|
87
|
+
|
|
88
|
+
This server's implementations expose `dry_run` on every mutating tool, provide the one-shot `create_proxy_host_with_letsencrypt` workflow, and publish the Docker sidecar at `127.0.0.1:8000:8000`. These are verified in [`tools/`](nginx_proxy_manager_mcp/tools/), [`server.py`](nginx_proxy_manager_mcp/server.py), and [`docker-compose.yml`](docker-compose.yml). They do not establish that other servers lack equivalent capabilities.
|
|
89
|
+
|
|
90
|
+
## Quick start: Docker sidecar
|
|
91
|
+
|
|
92
|
+
The bundled `docker-compose.yml` starts both Nginx Proxy Manager and this MCP sidecar from source. If you already run NPM, copy only the `nginx-proxy-manager-mcp` service into your existing compose file.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git clone https://github.com/euisuh/nginx-proxy-manager-mcp.git
|
|
96
|
+
cd nginx-proxy-manager-mcp
|
|
97
|
+
cp .env.example .env
|
|
98
|
+
# edit .env — NPM_EMAIL / NPM_PASSWORD must be an existing NPM admin account
|
|
99
|
+
docker compose up -d
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`NPM_URL` defaults to `http://app:81`, the NPM admin API on the internal Docker network. Leave it as-is when both services share a compose stack; point it at your NPM host otherwise.
|
|
103
|
+
|
|
104
|
+
To use the published GHCR image instead of building locally:
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
services:
|
|
108
|
+
nginx-proxy-manager-mcp:
|
|
109
|
+
image: ghcr.io/euisuh/nginx-proxy-manager-mcp:latest
|
|
110
|
+
restart: unless-stopped
|
|
111
|
+
environment:
|
|
112
|
+
NPM_URL: http://app:81
|
|
113
|
+
NPM_EMAIL: ${NPM_EMAIL}
|
|
114
|
+
NPM_PASSWORD: ${NPM_PASSWORD}
|
|
115
|
+
MCP_TRANSPORT: sse
|
|
116
|
+
MCP_HOST: 0.0.0.0
|
|
117
|
+
MCP_PORT: 8000
|
|
118
|
+
MCP_BEARER_TOKEN: ${MCP_BEARER_TOKEN:-}
|
|
119
|
+
ports:
|
|
120
|
+
- "127.0.0.1:8000:8000"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Register the SSE server with Claude Code:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
claude mcp add npm http://localhost:8000/sse
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Or add it manually to an MCP client config:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"mcpServers": {
|
|
134
|
+
"nginx-proxy-manager": {
|
|
135
|
+
"url": "http://localhost:8000/sse"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
More examples live in [`examples/`](examples/): Claude Desktop, Claude Code, Cursor, and Windsurf.
|
|
142
|
+
|
|
143
|
+
## Quick start: uvx / pipx
|
|
144
|
+
|
|
145
|
+
If you do not want Docker, run it from PyPI (package `nginx-proxy-manager-mcp-server`):
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
NPM_URL=http://localhost:81 \
|
|
149
|
+
NPM_EMAIL=admin@example.com \
|
|
150
|
+
NPM_PASSWORD=... \
|
|
151
|
+
MCP_TRANSPORT=stdio \
|
|
152
|
+
uvx nginx-proxy-manager-mcp-server
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Or from a local checkout:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
git clone https://github.com/euisuh/nginx-proxy-manager-mcp.git
|
|
159
|
+
cd nginx-proxy-manager-mcp
|
|
160
|
+
|
|
161
|
+
NPM_URL=http://localhost:81 \
|
|
162
|
+
NPM_EMAIL=admin@example.com \
|
|
163
|
+
NPM_PASSWORD=... \
|
|
164
|
+
MCP_TRANSPORT=stdio \
|
|
165
|
+
uvx --from . nginx-proxy-manager-mcp
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Or install it into an isolated environment:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
pipx install nginx-proxy-manager-mcp-server
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Quick start: stdio
|
|
175
|
+
|
|
176
|
+
Use stdio when you want the MCP client to launch the server process directly instead of talking to a sidecar.
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
python -m venv .venv
|
|
180
|
+
. .venv/bin/activate
|
|
181
|
+
pip install -e .
|
|
182
|
+
NPM_URL=http://localhost:81 \
|
|
183
|
+
NPM_EMAIL=admin@example.com \
|
|
184
|
+
NPM_PASSWORD=... \
|
|
185
|
+
MCP_TRANSPORT=stdio \
|
|
186
|
+
nginx-proxy-manager-mcp
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Example client config:
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"mcpServers": {
|
|
194
|
+
"nginx-proxy-manager": {
|
|
195
|
+
"command": "/path/to/nginx-proxy-manager-mcp/.venv/bin/python",
|
|
196
|
+
"args": ["-m", "nginx_proxy_manager_mcp.server"],
|
|
197
|
+
"env": {
|
|
198
|
+
"NPM_URL": "http://localhost:81",
|
|
199
|
+
"NPM_EMAIL": "admin@example.com",
|
|
200
|
+
"NPM_PASSWORD": "...",
|
|
201
|
+
"MCP_TRANSPORT": "stdio"
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Configuration
|
|
209
|
+
|
|
210
|
+
| Variable | Required | Default | Description |
|
|
211
|
+
|---|---:|---|---|
|
|
212
|
+
| `NPM_URL` | yes | — | Base URL of the NPM admin API (`http://app:81` inside Docker) |
|
|
213
|
+
| `NPM_EMAIL` | yes | — | NPM admin account email |
|
|
214
|
+
| `NPM_PASSWORD` | yes | — | NPM admin account password |
|
|
215
|
+
| `MCP_TRANSPORT` | no | `sse` | MCP transport: `sse` or `stdio` |
|
|
216
|
+
| `MCP_HOST` | no | `127.0.0.1` | Bind address for SSE mode; Docker Compose sets `0.0.0.0` inside the container while publishing only to localhost |
|
|
217
|
+
| `MCP_PORT` | no | `8000` | Bind port for SSE mode |
|
|
218
|
+
| `MCP_BEARER_TOKEN` | no | — | Optional bearer token required for SSE HTTP requests |
|
|
219
|
+
|
|
220
|
+
Missing required variables make the server exit with a clear error at startup rather than fail on the first API call.
|
|
221
|
+
|
|
222
|
+
SSE mode also exposes `GET /healthz`, an unauthenticated liveness endpoint that returns a small JSON response. It does not contact NPM or validate credentials; use it for container and reverse-proxy health checks only.
|
|
223
|
+
|
|
224
|
+
## Architecture
|
|
225
|
+
|
|
226
|
+
```text
|
|
227
|
+
┌───────────────┐ MCP over SSE/stdio ┌──────────────────────────┐
|
|
228
|
+
│ Claude/Cursor │ ─────────────────────► │ Nginx Proxy Manager MCP │
|
|
229
|
+
│ / MCP client │ │ server.py + tools/ │
|
|
230
|
+
└───────────────┘ └───────────┬──────────────┘
|
|
231
|
+
│ HTTP + Bearer JWT
|
|
232
|
+
▼
|
|
233
|
+
┌──────────────────────────┐
|
|
234
|
+
│ Nginx Proxy Manager API │
|
|
235
|
+
│ app:81 / localhost:81 │
|
|
236
|
+
└──────────────────────────┘
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
- `nginx_proxy_manager_mcp/server.py` validates required env vars, builds the FastMCP app, registers every tool module, and serves either SSE or stdio.
|
|
240
|
+
- `nginx_proxy_manager_mcp/npm_client.py` wraps `httpx`, exchanges the admin email/password for a JWT on first use, caches the token in memory, and re-authenticates on `401`.
|
|
241
|
+
- `nginx_proxy_manager_mcp/tools/` keeps one module per NPM resource. Adding a resource means adding one `register_*_tools(mcp, client)` function and one registration line.
|
|
242
|
+
|
|
243
|
+
## Development
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
python -m venv .venv
|
|
247
|
+
. .venv/bin/activate
|
|
248
|
+
pip install -e . -r requirements-dev.txt
|
|
249
|
+
pytest -q
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Tests mock the NPM API with [respx](https://lundberg.github.io/respx/), so the suite runs offline and touches no real infrastructure. CI runs the same command on every push and pull request.
|
|
253
|
+
|
|
254
|
+
## Releases
|
|
255
|
+
|
|
256
|
+
Tagged releases (`vX.Y.Z`) publish the `nginx-proxy-manager-mcp-server` package to PyPI via trusted publishing (`.github/workflows/publish.yml`) and multi-architecture Docker images to GitHub Container Registry:
|
|
257
|
+
|
|
258
|
+
- `ghcr.io/euisuh/nginx-proxy-manager-mcp:<version>` for tags such as `v0.2.0`
|
|
259
|
+
- `ghcr.io/euisuh/nginx-proxy-manager-mcp:<major>.<minor>` for semver tags
|
|
260
|
+
- `ghcr.io/euisuh/nginx-proxy-manager-mcp:latest` for the newest tagged release
|
|
261
|
+
|
|
262
|
+
The Docker workflow also builds pull requests without pushing an image, so packaging changes are validated before release.
|
|
263
|
+
|
|
264
|
+
## Security
|
|
265
|
+
|
|
266
|
+
Anything that can reach this MCP server has admin-level control over your proxy hosts and certificates.
|
|
267
|
+
|
|
268
|
+
- Do not expose the MCP endpoint publicly.
|
|
269
|
+
- Keep the Docker port bound to `127.0.0.1` unless you have another trusted network boundary.
|
|
270
|
+
- Bare SSE runs bind to `127.0.0.1` by default; set `MCP_HOST=0.0.0.0` only behind a trusted network boundary.
|
|
271
|
+
- Set `MCP_BEARER_TOKEN` for SSE deployments that can be reached by anything beyond the local machine, and configure clients to send `Authorization: Bearer YOUR_TOKEN`.
|
|
272
|
+
- Use environment variables or a secrets manager for NPM credentials; do not commit `.env`.
|
|
273
|
+
- The NPM admin JWT lives in process memory and is never written to disk.
|
|
274
|
+
- The container runs as a non-root user.
|
|
275
|
+
|
|
276
|
+
See [SECURITY.md](SECURITY.md) for reporting and deployment guidance.
|
|
277
|
+
|
|
278
|
+
## Roadmap
|
|
279
|
+
|
|
280
|
+
See [ROADMAP.md](ROADMAP.md). Near-term priorities are PyPI publishing, MCP directory submission, broader NPM resource coverage, and integration tests.
|
|
281
|
+
|
|
282
|
+
## Directory metadata
|
|
283
|
+
|
|
284
|
+
- [`smithery.yaml`](smithery.yaml) describes stdio launch configuration for Smithery-style MCP directories.
|
|
285
|
+
- [`glama.json`](glama.json) declares the repository maintainer for Glama MCP registry verification.
|
|
286
|
+
|
|
287
|
+
## Limitations
|
|
288
|
+
|
|
289
|
+
- Covers proxy hosts, redirection hosts, streams, certificates, and access lists only. 404 hosts, users, audit log, and settings are not implemented yet.
|
|
290
|
+
- Certificate creation supports Let's Encrypt HTTP-01 only — no DNS-01 challenge and no custom certificate upload yet.
|
|
291
|
+
- One NPM instance per server process; there is no multi-tenant or multi-host routing.
|
|
292
|
+
- Optional SSE bearer-token auth protects the HTTP endpoint, but there is no per-tool authorization after a client is authenticated.
|
|
293
|
+
- `/healthz` reports only process liveness, not NPM reachability.
|
|
294
|
+
- Written against the NPM v2 API; older or forked NPM builds may differ.
|
|
295
|
+
|
|
296
|
+
## Contributing
|
|
297
|
+
|
|
298
|
+
Issues and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md). Adding a new NPM resource follows a fixed shape:
|
|
299
|
+
|
|
300
|
+
1. Create `nginx_proxy_manager_mcp/tools/<resource>.py` with a `register_<resource>_tools(mcp, client)` function.
|
|
301
|
+
2. Register it in `build_server()` in `nginx_proxy_manager_mcp/server.py`.
|
|
302
|
+
3. Add `tests/test_<resource>.py` covering each tool with respx-mocked NPM responses.
|
|
303
|
+
4. Run `ruff check .` and `pytest -q`.
|
|
304
|
+
|
|
305
|
+
Commits follow [Conventional Commits](https://www.conventionalcommits.org/).
|
|
306
|
+
|
|
307
|
+
## Author
|
|
308
|
+
|
|
309
|
+
Built and maintained by [Euisuh Jeong](https://github.com/euisuh) to manage a homelab reverse proxy from Claude Code.
|
|
310
|
+
|
|
311
|
+
## License
|
|
312
|
+
|
|
313
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# Nginx Proxy Manager MCP
|
|
2
|
+
|
|
3
|
+
<!-- mcp-name: io.github.euisuh/nginx-proxy-manager-mcp -->
|
|
4
|
+
|
|
5
|
+
[](https://github.com/euisuh/nginx-proxy-manager-mcp/actions/workflows/ci.yml)
|
|
6
|
+
[](https://github.com/euisuh/nginx-proxy-manager-mcp/actions/workflows/docker.yml)
|
|
7
|
+
[](https://github.com/euisuh/nginx-proxy-manager-mcp/actions/workflows/python-package.yml)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
An MCP server for [Nginx Proxy Manager](https://nginxproxymanager.com/). It lets Claude and other MCP clients manage reverse-proxy hosts, Let's Encrypt certificates, and access lists through typed tools instead of clicking through the NPM admin UI.
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
"Point blog.example.com at the container on port 3000 with HTTPS"
|
|
14
|
+
│
|
|
15
|
+
▼
|
|
16
|
+
Claude / MCP client ──► Nginx Proxy Manager MCP ──HTTP + JWT──► NPM API
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
The demo calls `create_proxy_host_with_letsencrypt(dry_run=True)` against a mocked NPM API and prints both request previews. No real NPM instance or credentials are used. To record it again, install the development dependencies and VHS, then run `vhs docs/demo.tape` from the repository root; [`docs/demo.py`](docs/demo.py) uses the same respx mocking approach as the tests.
|
|
22
|
+
|
|
23
|
+
## Why this exists
|
|
24
|
+
|
|
25
|
+
Reverse-proxy changes are repetitive homelab work: create a host, point it at a container, attach a certificate, maybe restrict it to an access list. That is exactly the kind of operational task an AI assistant can handle well when it has narrow, typed tools and a local admin boundary.
|
|
26
|
+
|
|
27
|
+
This server runs either:
|
|
28
|
+
|
|
29
|
+
- as an SSE Docker sidecar next to an existing NPM container, or
|
|
30
|
+
- as a stdio MCP server for local clients.
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
- 30 MCP tools for common NPM operations.
|
|
35
|
+
- `dry_run` on all mutating tools to preview NPM requests before applying them;
|
|
36
|
+
- One-shot `create_proxy_host_with_letsencrypt` requests a certificate, then creates an HTTPS-forced proxy host.
|
|
37
|
+
- JWT auth against the NPM API with in-memory token caching and automatic re-authentication on `401`.
|
|
38
|
+
- Docker sidecar deployment that binds the MCP port to localhost by default.
|
|
39
|
+
- Offline pytest suite with mocked NPM API responses.
|
|
40
|
+
- Ruff quality gate and contributor templates for public maintenance.
|
|
41
|
+
- Python wheel build validation and MCP directory metadata for promotion readiness.
|
|
42
|
+
- No token persistence and no hardcoded credentials.
|
|
43
|
+
|
|
44
|
+
## Tools
|
|
45
|
+
|
|
46
|
+
| Category | Tools |
|
|
47
|
+
|---|---|
|
|
48
|
+
| Workflows | `create_proxy_host_with_letsencrypt` |
|
|
49
|
+
| Proxy hosts | `list_proxy_hosts`, `get_proxy_host`, `create_proxy_host`, `update_proxy_host`, `delete_proxy_host`, `enable_proxy_host`, `disable_proxy_host` |
|
|
50
|
+
| Redirection hosts | `list_redirection_hosts`, `get_redirection_host`, `create_redirection_host`, `update_redirection_host`, `delete_redirection_host`, `enable_redirection_host`, `disable_redirection_host` |
|
|
51
|
+
| Streams | `list_streams`, `get_stream`, `create_stream`, `update_stream`, `delete_stream`, `enable_stream`, `disable_stream` |
|
|
52
|
+
| SSL certs | `list_certificates`, `create_letsencrypt_cert`, `renew_certificate` |
|
|
53
|
+
| Access lists | `list_access_lists`, `get_access_list`, `create_access_list`, `update_access_list`, `delete_access_list` |
|
|
54
|
+
|
|
55
|
+
All mutating tools expose `dry_run=True`. Previews contain `method` and `path`, plus `json` when the request has a body; the HTTPS workflow returns two previews in `steps`. The flag suppresses mutating requests, though some previews read current state. Update tools send only the fields in NPM's PUT schema (fixes [#19](https://github.com/euisuh/nginx-proxy-manager-mcp/issues/19)); this is covered by mocked tests and not yet checked against a live NPM instance.
|
|
56
|
+
|
|
57
|
+
## Compared to other NPM MCP servers
|
|
58
|
+
|
|
59
|
+
Competitor facts below come only from their linked READMEs fetched with `gh api repos/<owner>/nginx-proxy-manager-mcp/readme` on 2026-10-13. “not documented” means the README does not establish the capability, not that it is absent. Auth guard means inbound MCP client authentication, distinct from NPM API login.
|
|
60
|
+
|
|
61
|
+
| Repository | Tool count documented | Dry-run support | Transport | Auth guard |
|
|
62
|
+
|---|---:|---|---|---|
|
|
63
|
+
| [euisuh (this server)](https://github.com/euisuh/nginx-proxy-manager-mcp) | 30 | `dry_run` on all mutating tools | stdio, SSE | Optional SSE bearer token (`MCP_BEARER_TOKEN`); `/healthz` exempt |
|
|
64
|
+
| [b3nw](https://github.com/b3nw/nginx-proxy-manager-mcp/blob/725d323b96c5d4e88790b8c88ea790a1133fc2d1/README.md) | 14 named tools (13 catalog rows plus `list_instances`) | not documented | stdio, HTTP | HTTP bearer token (`NPM_MCP_AUTH_TOKEN`) |
|
|
65
|
+
| [omichelbraga](https://github.com/omichelbraga/nginx-proxy-manager-mcp/blob/c6568f0f090c8a087ac9f3a56ac468c139e0a3cb/README.md) | 66 | DELETE without `confirm: true` previews affected resources; general `dry_run` not documented | stdio, Streamable HTTP | Optional bearer token (`NPM_MCP_BEARER_TOKEN`); unset means no inbound auth |
|
|
66
|
+
| [drmogie](https://github.com/drmogie/nginx-proxy-manager-mcp/blob/91c4176b544de6b64b9d16ff6dc891a352951145/README.md) | 4 named tools (`npm_status`, `npm_hosts`, `npm_audit_log`, `npm_call`) | Changes show what will be sent and require `confirm`; `dry_run` not documented | not documented | not documented |
|
|
67
|
+
|
|
68
|
+
This server's implementations expose `dry_run` on every mutating tool, provide the one-shot `create_proxy_host_with_letsencrypt` workflow, and publish the Docker sidecar at `127.0.0.1:8000:8000`. These are verified in [`tools/`](nginx_proxy_manager_mcp/tools/), [`server.py`](nginx_proxy_manager_mcp/server.py), and [`docker-compose.yml`](docker-compose.yml). They do not establish that other servers lack equivalent capabilities.
|
|
69
|
+
|
|
70
|
+
## Quick start: Docker sidecar
|
|
71
|
+
|
|
72
|
+
The bundled `docker-compose.yml` starts both Nginx Proxy Manager and this MCP sidecar from source. If you already run NPM, copy only the `nginx-proxy-manager-mcp` service into your existing compose file.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git clone https://github.com/euisuh/nginx-proxy-manager-mcp.git
|
|
76
|
+
cd nginx-proxy-manager-mcp
|
|
77
|
+
cp .env.example .env
|
|
78
|
+
# edit .env — NPM_EMAIL / NPM_PASSWORD must be an existing NPM admin account
|
|
79
|
+
docker compose up -d
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`NPM_URL` defaults to `http://app:81`, the NPM admin API on the internal Docker network. Leave it as-is when both services share a compose stack; point it at your NPM host otherwise.
|
|
83
|
+
|
|
84
|
+
To use the published GHCR image instead of building locally:
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
services:
|
|
88
|
+
nginx-proxy-manager-mcp:
|
|
89
|
+
image: ghcr.io/euisuh/nginx-proxy-manager-mcp:latest
|
|
90
|
+
restart: unless-stopped
|
|
91
|
+
environment:
|
|
92
|
+
NPM_URL: http://app:81
|
|
93
|
+
NPM_EMAIL: ${NPM_EMAIL}
|
|
94
|
+
NPM_PASSWORD: ${NPM_PASSWORD}
|
|
95
|
+
MCP_TRANSPORT: sse
|
|
96
|
+
MCP_HOST: 0.0.0.0
|
|
97
|
+
MCP_PORT: 8000
|
|
98
|
+
MCP_BEARER_TOKEN: ${MCP_BEARER_TOKEN:-}
|
|
99
|
+
ports:
|
|
100
|
+
- "127.0.0.1:8000:8000"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Register the SSE server with Claude Code:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
claude mcp add npm http://localhost:8000/sse
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or add it manually to an MCP client config:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"nginx-proxy-manager": {
|
|
115
|
+
"url": "http://localhost:8000/sse"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
More examples live in [`examples/`](examples/): Claude Desktop, Claude Code, Cursor, and Windsurf.
|
|
122
|
+
|
|
123
|
+
## Quick start: uvx / pipx
|
|
124
|
+
|
|
125
|
+
If you do not want Docker, run it from PyPI (package `nginx-proxy-manager-mcp-server`):
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
NPM_URL=http://localhost:81 \
|
|
129
|
+
NPM_EMAIL=admin@example.com \
|
|
130
|
+
NPM_PASSWORD=... \
|
|
131
|
+
MCP_TRANSPORT=stdio \
|
|
132
|
+
uvx nginx-proxy-manager-mcp-server
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Or from a local checkout:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
git clone https://github.com/euisuh/nginx-proxy-manager-mcp.git
|
|
139
|
+
cd nginx-proxy-manager-mcp
|
|
140
|
+
|
|
141
|
+
NPM_URL=http://localhost:81 \
|
|
142
|
+
NPM_EMAIL=admin@example.com \
|
|
143
|
+
NPM_PASSWORD=... \
|
|
144
|
+
MCP_TRANSPORT=stdio \
|
|
145
|
+
uvx --from . nginx-proxy-manager-mcp
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Or install it into an isolated environment:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pipx install nginx-proxy-manager-mcp-server
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Quick start: stdio
|
|
155
|
+
|
|
156
|
+
Use stdio when you want the MCP client to launch the server process directly instead of talking to a sidecar.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
python -m venv .venv
|
|
160
|
+
. .venv/bin/activate
|
|
161
|
+
pip install -e .
|
|
162
|
+
NPM_URL=http://localhost:81 \
|
|
163
|
+
NPM_EMAIL=admin@example.com \
|
|
164
|
+
NPM_PASSWORD=... \
|
|
165
|
+
MCP_TRANSPORT=stdio \
|
|
166
|
+
nginx-proxy-manager-mcp
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Example client config:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"mcpServers": {
|
|
174
|
+
"nginx-proxy-manager": {
|
|
175
|
+
"command": "/path/to/nginx-proxy-manager-mcp/.venv/bin/python",
|
|
176
|
+
"args": ["-m", "nginx_proxy_manager_mcp.server"],
|
|
177
|
+
"env": {
|
|
178
|
+
"NPM_URL": "http://localhost:81",
|
|
179
|
+
"NPM_EMAIL": "admin@example.com",
|
|
180
|
+
"NPM_PASSWORD": "...",
|
|
181
|
+
"MCP_TRANSPORT": "stdio"
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Configuration
|
|
189
|
+
|
|
190
|
+
| Variable | Required | Default | Description |
|
|
191
|
+
|---|---:|---|---|
|
|
192
|
+
| `NPM_URL` | yes | — | Base URL of the NPM admin API (`http://app:81` inside Docker) |
|
|
193
|
+
| `NPM_EMAIL` | yes | — | NPM admin account email |
|
|
194
|
+
| `NPM_PASSWORD` | yes | — | NPM admin account password |
|
|
195
|
+
| `MCP_TRANSPORT` | no | `sse` | MCP transport: `sse` or `stdio` |
|
|
196
|
+
| `MCP_HOST` | no | `127.0.0.1` | Bind address for SSE mode; Docker Compose sets `0.0.0.0` inside the container while publishing only to localhost |
|
|
197
|
+
| `MCP_PORT` | no | `8000` | Bind port for SSE mode |
|
|
198
|
+
| `MCP_BEARER_TOKEN` | no | — | Optional bearer token required for SSE HTTP requests |
|
|
199
|
+
|
|
200
|
+
Missing required variables make the server exit with a clear error at startup rather than fail on the first API call.
|
|
201
|
+
|
|
202
|
+
SSE mode also exposes `GET /healthz`, an unauthenticated liveness endpoint that returns a small JSON response. It does not contact NPM or validate credentials; use it for container and reverse-proxy health checks only.
|
|
203
|
+
|
|
204
|
+
## Architecture
|
|
205
|
+
|
|
206
|
+
```text
|
|
207
|
+
┌───────────────┐ MCP over SSE/stdio ┌──────────────────────────┐
|
|
208
|
+
│ Claude/Cursor │ ─────────────────────► │ Nginx Proxy Manager MCP │
|
|
209
|
+
│ / MCP client │ │ server.py + tools/ │
|
|
210
|
+
└───────────────┘ └───────────┬──────────────┘
|
|
211
|
+
│ HTTP + Bearer JWT
|
|
212
|
+
▼
|
|
213
|
+
┌──────────────────────────┐
|
|
214
|
+
│ Nginx Proxy Manager API │
|
|
215
|
+
│ app:81 / localhost:81 │
|
|
216
|
+
└──────────────────────────┘
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
- `nginx_proxy_manager_mcp/server.py` validates required env vars, builds the FastMCP app, registers every tool module, and serves either SSE or stdio.
|
|
220
|
+
- `nginx_proxy_manager_mcp/npm_client.py` wraps `httpx`, exchanges the admin email/password for a JWT on first use, caches the token in memory, and re-authenticates on `401`.
|
|
221
|
+
- `nginx_proxy_manager_mcp/tools/` keeps one module per NPM resource. Adding a resource means adding one `register_*_tools(mcp, client)` function and one registration line.
|
|
222
|
+
|
|
223
|
+
## Development
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
python -m venv .venv
|
|
227
|
+
. .venv/bin/activate
|
|
228
|
+
pip install -e . -r requirements-dev.txt
|
|
229
|
+
pytest -q
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Tests mock the NPM API with [respx](https://lundberg.github.io/respx/), so the suite runs offline and touches no real infrastructure. CI runs the same command on every push and pull request.
|
|
233
|
+
|
|
234
|
+
## Releases
|
|
235
|
+
|
|
236
|
+
Tagged releases (`vX.Y.Z`) publish the `nginx-proxy-manager-mcp-server` package to PyPI via trusted publishing (`.github/workflows/publish.yml`) and multi-architecture Docker images to GitHub Container Registry:
|
|
237
|
+
|
|
238
|
+
- `ghcr.io/euisuh/nginx-proxy-manager-mcp:<version>` for tags such as `v0.2.0`
|
|
239
|
+
- `ghcr.io/euisuh/nginx-proxy-manager-mcp:<major>.<minor>` for semver tags
|
|
240
|
+
- `ghcr.io/euisuh/nginx-proxy-manager-mcp:latest` for the newest tagged release
|
|
241
|
+
|
|
242
|
+
The Docker workflow also builds pull requests without pushing an image, so packaging changes are validated before release.
|
|
243
|
+
|
|
244
|
+
## Security
|
|
245
|
+
|
|
246
|
+
Anything that can reach this MCP server has admin-level control over your proxy hosts and certificates.
|
|
247
|
+
|
|
248
|
+
- Do not expose the MCP endpoint publicly.
|
|
249
|
+
- Keep the Docker port bound to `127.0.0.1` unless you have another trusted network boundary.
|
|
250
|
+
- Bare SSE runs bind to `127.0.0.1` by default; set `MCP_HOST=0.0.0.0` only behind a trusted network boundary.
|
|
251
|
+
- Set `MCP_BEARER_TOKEN` for SSE deployments that can be reached by anything beyond the local machine, and configure clients to send `Authorization: Bearer YOUR_TOKEN`.
|
|
252
|
+
- Use environment variables or a secrets manager for NPM credentials; do not commit `.env`.
|
|
253
|
+
- The NPM admin JWT lives in process memory and is never written to disk.
|
|
254
|
+
- The container runs as a non-root user.
|
|
255
|
+
|
|
256
|
+
See [SECURITY.md](SECURITY.md) for reporting and deployment guidance.
|
|
257
|
+
|
|
258
|
+
## Roadmap
|
|
259
|
+
|
|
260
|
+
See [ROADMAP.md](ROADMAP.md). Near-term priorities are PyPI publishing, MCP directory submission, broader NPM resource coverage, and integration tests.
|
|
261
|
+
|
|
262
|
+
## Directory metadata
|
|
263
|
+
|
|
264
|
+
- [`smithery.yaml`](smithery.yaml) describes stdio launch configuration for Smithery-style MCP directories.
|
|
265
|
+
- [`glama.json`](glama.json) declares the repository maintainer for Glama MCP registry verification.
|
|
266
|
+
|
|
267
|
+
## Limitations
|
|
268
|
+
|
|
269
|
+
- Covers proxy hosts, redirection hosts, streams, certificates, and access lists only. 404 hosts, users, audit log, and settings are not implemented yet.
|
|
270
|
+
- Certificate creation supports Let's Encrypt HTTP-01 only — no DNS-01 challenge and no custom certificate upload yet.
|
|
271
|
+
- One NPM instance per server process; there is no multi-tenant or multi-host routing.
|
|
272
|
+
- Optional SSE bearer-token auth protects the HTTP endpoint, but there is no per-tool authorization after a client is authenticated.
|
|
273
|
+
- `/healthz` reports only process liveness, not NPM reachability.
|
|
274
|
+
- Written against the NPM v2 API; older or forked NPM builds may differ.
|
|
275
|
+
|
|
276
|
+
## Contributing
|
|
277
|
+
|
|
278
|
+
Issues and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md). Adding a new NPM resource follows a fixed shape:
|
|
279
|
+
|
|
280
|
+
1. Create `nginx_proxy_manager_mcp/tools/<resource>.py` with a `register_<resource>_tools(mcp, client)` function.
|
|
281
|
+
2. Register it in `build_server()` in `nginx_proxy_manager_mcp/server.py`.
|
|
282
|
+
3. Add `tests/test_<resource>.py` covering each tool with respx-mocked NPM responses.
|
|
283
|
+
4. Run `ruff check .` and `pytest -q`.
|
|
284
|
+
|
|
285
|
+
Commits follow [Conventional Commits](https://www.conventionalcommits.org/).
|
|
286
|
+
|
|
287
|
+
## Author
|
|
288
|
+
|
|
289
|
+
Built and maintained by [Euisuh Jeong](https://github.com/euisuh) to manage a homelab reverse proxy from Claude Code.
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
MIT — see [LICENSE](LICENSE).
|
|
File without changes
|