Skip to main content
Glama

npm-mcp

用于 Nginx Proxy Manager 的 Model Context Protocol 服务器

以对话方式管理反向代理路由、TLS 证书、访问列表和流转发——并带有护栏,假设你最终会将其指向生产环境。

Python FastMCP NPM Tests Tools Ruff


目录


Related MCP server: npm-mcp

为什么存在

Nginx Proxy Manager 有完整的 REST API,但没有 MCP 服务器。这就是那个服务器——但有趣的部分不是管道,而是约束。

反向代理是其背后所有服务的单点故障。一个拥有写权限的代理可以关闭它从未被要求触及的服务。因此设计从这一点出发:

工具是从 API 自身的 OpenAPI 文档生成的,而非手写。 文档被固定在树内,漂移测试会在上游接口变化时使 CI 失败——而不是让工具在运行时静默 404。

每个结果都经过一个失败关闭的脱敏边界。 它会对任何无法检查的内容抛出异常,而不是直接传递。

护栏经过变异测试。 每个安全控制都有一个测试,证明当控制被禁用时会变红。


工作原理

flowchart LR
    C["MCP Client"] -->|"Bearer (optional)"| S

    subgraph S["npm-mcp"]
        direction TB
        A["Bearer verifier<br/><i>hmac.compare_digest</i>"] --> G["Guardrails<br/><i>S1 · S2 · S6 · S7 · S8</i>"]
        G --> T["66 generated tools"]
        T --> R["serialize_result()<br/><i>redact + cap</i>"]
    end

    S -->|"JWT, auto-refreshed"| N["Nginx Proxy Manager"]
    P["npm-openapi.json<br/><i>pinned, in-package</i>"] -.->|generates| T

工具签名在导入时从固定的文档构建,因此 create_proxy_host 暴露了 18 个带真实枚举的类型化参数——而不是一个不透明的 **kwargs 传递。


快速开始

uv sync
cp .env.example .env    # then fill in NPM_URL / NPM_IDENTITY / NPM_SECRET
uv run npm-mcp
{
  "mcpServers": {
    "npm": {
      "command": "uv",
      "args": ["run", "npm-mcp"],
      "env": {
        "NPM_URL": "https://nginx-proxy-manager.example.net",
        "NPM_IDENTITY": "npm-mcp@example.net",
        "NPM_SECRET": "…",
        "NPM_MCP_TRANSPORT": "stdio"
      }
    }
  }
}
{
  "mcpServers": {
    "npm": {
      "type": "http",
      "url": "https://npm-mcp.example.net/mcp",
      "headers": { "Authorization": "Bearer <NPM_MCP_BEARER_TOKEN>" }
    }
  }
}

FastMCP 在 /mcp 提供服务。尾部斜杠会 307 重定向,某些客户端处理不当——不要让代理重写路径。

[!TIP] 首先调用 get_guidance。它会报告响应形状、禁用与删除的区别、当前哪些锁已打开,以及当前受保护的域名列表。


认证

两层,容易混淆:

方向

机制

入站

客户端 → npm-mcp

可选的 Authorization: Bearer … 通过 NPM_MCP_BEARER_TOKEN,使用 hmac.compare_digest 比较。未设置 ⇒ 完全没有认证。

出站

npm-mcp → NPM

账户凭据 → 短期 JWT,自动刷新。调用者永远看不到或提供它。

NPM 不颁发长期 API 密钥,这就是服务器持有凭据而不是接受令牌的原因。

[!IMPORTANT] POST /tokens两种 可能的响应:一个令牌,或一个 2FA 挑战。 如果账户启用了 2FA,请设置 NPM_TOTP_SECRET——否则服务器会 在启动时 失败,并指出两种补救措施,而不是启动后正常但在第一次工具调用时崩溃。


工具目录

66 个工具 = 65 个 API 操作 + get_guidance

家族

#

代表性工具

🔀 代理主机

7

get_proxy_hosts · create_proxy_host · update_proxy_host · delete_proxy_host · enable_proxy_host · disable_proxy_host

↪️ 重定向主机

7

*_redirection_host

🚫 404 主机

7

create_404_host · *_dead_host

🔌 流

7

*_stream

🔐 访问列表

5

get_access_lists · create_access_list · update_access_list · delete_access_list

📜 证书

10

get_certificates · create_certificate · renew_certificate · upload_certificate · validate_certificates · download_certificate · test_http_reach · get_dns_providers

👤 用户

8

get_users · create_user · update_user · update_user_auth · update_user_permissions · login_as_user

🔑 用户 2FA

5

setup_user_2fa · enable_user_2fa · disable_user_2fa · get_user_2fa_status · regen_user_2fa_codes

⚙️ 设置

3

get_settings · update_setting

📋 审计日志

2

get_audit_logs · get_audit_log

ℹ️ 元信息

4

health · check_version · reports_hosts · schema

🧭 指导

1

get_guidance

名称源自 OpenAPI operationId,因此列表操作是 get_*,而不是 list_*

[!WARNING] 三个操作被有意不暴露: requestTokenrefreshTokenloginWith2FA。它们是服务器自身的认证管道,而 requestToken 接受 任意 身份和密钥——注册它会把此服务器变成针对 NPM 的凭据测试预言机,每次尝试都归因于服务账户。

  • 不存在分页。 没有一个端点接受 limit/offset。工具接受它们并在 客户端 进行切片;工具描述中说明了这一点。

  • expand 是每个端点的枚举,不是传递——代理主机接受 access_list,owner,certificate;证书只接受 owner。超出枚举的值会在请求发送前被拒绝。


安全模型

[!CAUTION] 写入默认启用。 此服务器可以重写代理背后每个服务的路由表。设置 NPM_READ_ONLY=1 以禁用所有变更。

控制

覆盖

NPM_READ_ONLY

拒绝所有变更工具,在任何护栏读取之前检查

S1

拒绝在受保护主机上执行 delete / disable / update,以及这些主机依赖的证书和访问列表

NPM_ALLOW_SELF_MUTATION

S2

每个 DELETE 都需要 confirm: true;否则工具返回 受影响的内容且不写入任何内容

每次调用

S5

每次变更都会产生一条审计行;NPM 自身的审计日志可查询

S6

/users/settings 下的每个变更操作都被锁存

NPM_ALLOW_ACCOUNT_MUTATION

S7

拒绝修改、禁用、删除或 login_as 其自身账户

S8

download_certificate 返回 TLS 私钥,因此被锁存

NPM_ALLOW_CERT_EXPORT

  • S1 匹配 ANY 受保护域名,而不是 ALL。 ALL 会让护栏通过它所保护的 工具 被解除:向主机添加一个无关域名,保护就会消失。

  • S1 覆盖 update,而不仅仅是 delete/disable。 否则你可以从 domain_names 中剥离受保护的名称,然后干净地删除——同样的中断。

  • S1 匹配当前上游状态,绝不匹配提交的请求体。 检查请求会让剥离-然后-更新路径直接通过。

  • S1 通配符双向匹配。 NPM_PROTECTED_DOMAINS=*.example.net 必须保护 app.example.net。它曾经匹配不到任何内容 并且 抑制了“未受保护”的警告,因为该值被显式设置。

  • S2 按 HTTP 方法限定范围,而不是名称前缀。 delete_* 规则会漏掉 disable_user_2fa——一个 DELETE 会剥离某人的第二因素。

  • S6 是规则,不是列表。 枚举版本静默遗漏了 update_user,因此锁存器保持关闭,而 is_disabled: true 锁定了管理员。

  • S7 没有覆盖。 一个能删除自身凭据的服务器会永久锁定自己。


配置

变量

含义

NPM_URL

NPM 实例的基础 URL

NPM_IDENTITY

账户邮箱

NPM_SECRET

账户密码

变量

默认值

含义

NPM_MCP_BEARER_TOKEN

未设置

入站令牌。未设置 ⇒ 无入站认证

NPM_MCP_TRANSPORT

streamable-http

stdio | streamable-http

NPM_MCP_HTTP_HOST

0.0.0.0

绑定地址

NPM_MCP_HTTP_PORT

8000

绑定端口

变量

默认值

提升条件

NPM_READ_ONLY

0

—(1 阻止所有写入)

NPM_PROTECTED_DOMAINS

派生自 NPM_URL

S1 拒绝列表,逗号分隔

NPM_ALLOW_SELF_MUTATION

0

S1

NPM_ALLOW_ACCOUNT_MUTATION

0

S6

NPM_ALLOW_CERT_EXPORT

0

S8

变量

默认值

含义

NPM_TOTP_SECRET

未设置

Base32 种子;仅当账户启用了 2FA 时

NPM_TLS_VERIFY

1

验证 NPM 的证书

NPM_TIMEOUT

30

上游超时,秒

NPM_MAX_RESPONSE_CHARS

50000

截断前的响应上限

NPM_GUIDANCE_GATE

1

在早期变更时提示使用 get_guidance

LOG_LEVEL

INFO


部署

docker build -t npm-mcp:latest .
docker compose up -d

容器加入一个现有的 Docker 网络,与 NPM 同处其中,并且不发布任何端口。NPM 通过容器 DNS 访问它并终止 TLS,因此 Bearer 令牌永远不会以明文形式在网络上传输。

  • compose 文件中没有 build: 键。 compose-字符串部署(例如 Portainer)不会携带构建上下文,因此镜像需要先构建好,再通过标签引用。

  • 健康检查解析绑定主机,而不是硬编码 127.0.0.1。当使用自定义的 NPM_MCP_HTTP_HOST 时,朴素的写法会把一个完全健康的容器永远标记为不健康。它在 stdio 下也会短路,因为那里根本没有服务在监听。

  • 认证预热在服务器生命周期内运行,因此配置错误会直接导致健康检查失败,而不是先显示为绿色、然后在首次使用时才崩溃。


测试

uv run pytest              # 420 tests
uv run ruff check
uv run ruff format --check

大约 4,700 行测试对应 3,300 行源码,但数量不如形态重要:

  • 🧬 经变异验证的护栏 —— 每个安全控制都有一项测试,证明当该控制被禁用时测试会失败。这是在发现一个 asyncio.Lock 被移除后测试套件仍然全绿之后编写的。

  • 🌐 零网络访问 —— 每次上游调用都用 respx 模拟。需要网络的测试就是有问题的测试。

  • 🔍 A7 扫描 —— 全部 65 个工具都会针对一个在四个嵌套深度返回秘密的上游进行调用,并带有一个阴性对照,断言测试夹具确实包含这些秘密,从而确保扫描不会空洞地通过。

  • 📐 模式漂移防护 —— 操作数量、载荷形状和打包的数据文件都有断言,因此上游升级会在这里失败,而不是在生产环境中失败。


设计说明

文档

内容

spec.md

产品契约 —— 决策 D1–D13、控制 S1–S8、验收标准 A1–A10

docs/api-surface.md

全部 68 个操作及其请求体字段和必填性

docs/module-contract.md

内部模块接口

docs/findings.md

OpenAPI 文档中两处错误之处,已对照真实实例进行验证

npm_mcp/data/npm-openapi.json

实例 /api/schema 的逐字副本 —— 放在包内,因为它是运行时依赖,而非文档

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    Enables management of Nginx Proxy Manager instances for configuring proxy hosts, requesting Let's Encrypt SSL certificates, and managing access lists. It allows users to control their web proxy infrastructure through natural language commands in MCP-compatible environments.
    50
    3
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to manage Nginx Proxy Manager instances through natural language, covering 28 tools for proxy hosts, certificates, streams, and more.
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables natural language management of FastPanel 2 servers, including creating sites, databases, SSL certificates, and hardening nginx configurations.
    32
    2
    MIT

View all related MCP servers

Related MCP Connectors

  • Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.

  • Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/omichelbraga/nginx-proxy-manager-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server