关于 ntfy
ntfy 是连接 ntfy 通知服务的 MCP 服务,面向需要通过兼容客户端收发通知的用户。它支持读取缓存消息、原位更新通知,以及使用管理员凭据管理账户和主题访问权限。
主要功能
- 01向一个或多个主题发布通知
- 02按条件读取缓存消息
- 03原位更新通知内容
- 04管理账户和主题访问权限
- 05配置工具范围及只读模式
适用场景
- 01发送部署进度通知
- 02查看提醒主题中的缓存消息
- 03授予账户指定主题的访问权限
MCP 相关
它向 MCP 客户端提供 ntfy 发布、消息读取与更新、账户和主题访问管理工具。可通过环境变量配置主题范围、凭据和可用工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @ni-c/ntfy-mcpNTFY_URLBase URL of the ntfy server, e.g. https://ntfy.example.net. There is deliberately no default.NTFY_TOKEN密钥ntfy access token (tk_...). Optional: an open instance needs no credentials. Mutually exclusive with NTFY_USERNAME/NTFY_PASSWORD.NTFY_USERNAMEUsername for basic authentication. Must be set together with NTFY_PASSWORD.NTFY_PASSWORD密钥Password for basic authentication. Must be set together with NTFY_USERNAME.NTFY_TOPICSComma-separated topics the server may use. The first is the default when a tool omits one, and the list restricts every read and write tool.NTFY_READ_ONLYSet to exactly true to register only the six read tools (default: false — ntfy exists to publish)NTFY_INSECURE_TLSSet to true to accept a self-signed certificate from the ntfy server (default: false)NTFY_ALLOW_TOOLSComma-separated tool names or list_* prefixes to register; 'essential' selects a curated preset (default: all tools)NTFY_DENY_TOOLSComma-separated tool names or list_* prefixes to remove from whatever the allow list left本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
13收录的工具列表 · 更新于 4 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | string | 否 | 仅返回此 ID 对应的消息。 |
| tags | array | 否 | 用于筛选的标签——消息必须包含所有这些标签。请注意,这与匹配任意标签的 "priority" 相反。 |
| limit | integer | 否 | 要返回的最新消息数量(默认 50)。 |
| since | string | 否 | 读取多早之前的内容:"all"、"latest"、"none"、12 个字符的消息 ID(不含该 ID)、Unix 时间戳,或 "24h" 之类的时长。默认为 "24h"。 |
| title | string | 否 | 标题的精确匹配筛选条件。 |
| topics | array | 否 | 要轮询的主题。默认为 NTFY_TOPICS 的第一项。 |
| message | string | 否 | 消息正文的精确匹配筛选条件。 |
| priority | array | 否 | 要包含的优先级——匹配其中任意一项。 |
| scheduled | boolean | 否 | 同时包含尚未投递的延迟消息。 |
详细介绍
ntfy-mcp
一个适用于 ntfy 的模型上下文协议(MCP)服务。ntfy 是一款发布-订阅通知服务,只需发送一个 HTTP 请求,就能向手机推送消息。
它允许 Claude Code、Claude Desktop 或 Codex 等 MCP 客户端向你发送通知、读取已发送的内容、在任务运行期间原地修改通知;如果使用管理员账号,还能创建账号并授予或撤销其对主题的访问权限。否则,这些操作需要在服务器上使用 ntfy 命令行完成。
工具数量上限是十三个,而非最低要求:设置 NTFY_ALLOW_TOOLS=essential 只会注册精心挑选的六个工具。模型从六个工具中挑选正确工具的可靠性远高于从十三个中挑选。请参阅选择要加载的工具。

特点
进度报告始终只对应一条通知。 publish_message 返回的 id 同时也是该通知的序列 id,而 update_message 会原地替换通知内容。订阅者看到的是一条通知从“构建中”变为“已部署”,而不是收到五条通知。
NTFY_TOPICS 是访问边界。 在 ntfy 中,主题名称就是持有者凭证:知道名称通常就意味着拥有全部访问权限。通过一个变量即可指定此服务允许访问的主题,并在工具未指定主题时提供默认值,这样主题名称就不会出现在工具参数或模型上下文中。
要求
- Node.js ≥ 24
- 可访问的 ntfy 服务。凭据为可选项:允许匿名访问的实例无需凭据。
配置
| 变量 | 必填 | 描述 |
|---|---|---|
NTFY_URL | 是 | 基础 URL,例如 https://ntfy.example.net。此处故意不提供默认值——如果配置错误,https://ntfy.sh 会将内容发布到公共互联网。 |
NTFY_TOKEN | 否 | 访问令牌(tk_…)。不能与下面两项同时使用。 |
NTFY_USERNAME | 否 | Basic Auth 用户名。必须与 NTFY_PASSWORD 一起设置。 |
NTFY_PASSWORD | 否 | Basic Auth 密码。 |
NTFY_TOPICS | 否 | 此服务可使用的主题,以逗号分隔。工具未指定主题时,使用第一个主题作为默认值;此列表会限制每个工具的读取和写入权限,包括访问授权。 |
NTFY_READ_ONLY | 否 | true、1 或 yes(不区分大小写)表示仅注册六个读取工具。默认值为 false。 |
NTFY_ALLOW_TOOLS | 否 | 以逗号分隔的工具名称、list_* 前缀,或用于精选预设的 essential |
NTFY_DENY_TOOLS | 否 | 语法相同;从 NTFY_ALLOW_TOOLS 保留的工具中移除 |
NTFY_INSECURE_TLS | 否 | true 表示接受自签名证书(仅对当前连接生效) |
如果同时设置 NTFY_TOKEN 和 NTFY_USERNAME/NTFY_PASSWORD,服务会在启动时拒绝启动,而不是通过优先级规则来决定使用哪项凭据:当前使用的凭据绝不能含糊不清。
请使用
https://。 使用普通 http 时,凭据会以未加密的方式传输——Basic Auth 使用的是 Base64,而非加密——并且除非主机位于本地,否则服务会打印警告。对于自签名证书,建议使用合适的内部 CA,而不是NTFY_INSECURE_TLS。
未配置时,服务仍会启动并列出其工具(以便注册表和检查器进行检查),但所有调用都会失败并显示设置说明,而不会访问 API。
默认启用写入
NTFY_READ_ONLY 的默认值为 false。ntfy 的用途是发布消息;若默认设为只读,部署出来的通知服务就无法发送通知——这与 imap-mcp 恰好相反,因为邮箱是不可替代的存档,所以同一个变量在 imap-mcp 中的默认值为 true。
有两点值得注意:
- 拼写错误仍会默认放行。 无论大小写,
true、1和yes都会被视为只读——保护开关特意采用宽松的解析方式。但NTFY_READ_ONLY=ture不属于其中任何一种;由于默认值允许写入,写入工具仍会启用,而在 imap-mcp 中则会默认拒绝。 - 除非另行设置,否则能发布的客户端可以在此实例的任何主题上发布。 确认令牌对此无济于事——发布不是破坏性操作。控制这一点的是
NTFY_TOPICS。
对于任何无人值守的场景,建议采用以下配置:
NTFY_TOPICS=deploys # the server can only touch this topic
NTFY_ALLOW_TOOLS=essential # or:
NTFY_DENY_TOOLS=delete_messages,create_user,delete_user,manage_user_access
如果是自托管实例,也请为服务端提供一个专用的 ntfy 账号,并仅授予其对所需主题的 write-only 访问权限。
选择要加载的工具
NTFY_ALLOW_TOOLS 和 NTFY_DENY_TOOLS 接受以逗号分隔的工具名称;末尾的 * 可匹配整个系列。essential 是一个精心挑选的预设,包含 get_server_info、check_topic_access、publish_message、list_messages、get_message 和 update_message;工具参考中也标明了这些工具。六个工具中有四个是读取工具,因此在 NTFY_READ_ONLY=true 时,这个预设仍然实用。
NTFY_ALLOW_TOOLS=essential
NTFY_ALLOW_TOOLS=publish_message,list_messages
NTFY_DENY_TOOLS=delete_*,create_user,manage_user_access
如果某个条目未匹配任何工具,启动就会中止并指出该条目,因此拼写错误不会悄悄隐藏工具——没人会想到去环境变量中追查一个缺失的工具。经过筛选的工具永远不会注册,因此它既不会出现在 tools/list 中,也无法通过 tools/call 调用;这与 NTFY_READ_ONLY 下的写入工具完全一样。
如果你同时运行多个此类服务,mcp-hub 是另一种解决方案——它的 /hub 端点会将每个服务的工具替换为六个元工具。
安装
Claude Code
claude mcp add ntfy-mcp -- npx -y @ni-c/ntfy-mcp
Claude Desktop
{
"mcpServers": {
"ntfy-mcp": {
"command": "npx",
"args": ["-y", "@ni-c/ntfy-mcp"],
"env": {
"NTFY_URL": "https://ntfy.example.net",
"NTFY_TOKEN": "…",
"NTFY_TOPICS": "deploys"
}
}
}
}
Codex
[mcp_servers.ntfy-mcp]
command = "npx"
args = ["-y", "@ni-c/ntfy-mcp"]
env = { NTFY_URL = "https://ntfy.example.net", NTFY_TOKEN = "…", NTFY_TOPICS = "deploys" }
Docker
docker run -i --rm \
-e NTFY_URL=https://ntfy.example.net -e NTFY_TOPICS=deploys \
ghcr.io/ni-c/ntfy-mcp
通过 mcp-hub
无法启动本地进程的客户端——ChatGPT 连接器、网页版 Claude、Cursor、LibreChat——可通过 mcp-hub 连接 ntfy-mcp:一个容器即可通过 Streamable HTTP 提供多个 stdio MCP 服务,并通过单一密码进行 OAuth 2.1 登录,同时为无法使用 OAuth 的客户端提供长期令牌。它的 /hub 端点会将每个服务放在六个元工具之后,因此一个连接器就能访问所有服务,无需在模型上下文中加入 N×工具模式;它还支持两个协议修订版本——此服务提出的问题会经由它传递给远端的用户。
它的 /config/mcp.json 使用 Claude Code 的格式,因此你已有的条目可以直接使用:
{
"mcpServers": {
"ntfy-mcp": {
"command": "npx",
"args": ["-y", "@ni-c/ntfy-mcp"],
"env": {
"NTFY_URL": "https://ntfy.example.net",
"NTFY_TOKEN": "…",
"NTFY_TOPICS": "alerts",
"NTFY_ALLOW_TOOLS": "essential"
},
"denyTools": ["delete_messages"]
}
}
}
其中的 allowTools 和 denyTools 是 hub 自己针对每个服务的筛选项,与 env 中的 *_ALLOW_TOOLS 并不相同——有关两者区别及其容易引发的错误,请参阅客户端指南。
工具
* 标记 essential 预设。
| 工具 | 描述 |
|---|---|
list_messages * | 根据筛选条件轮询一个或多个主题的缓存消息,并获取下次调用所用的游标 |
get_message * | 获取一条完整消息,包括其操作按钮和附件 |
check_topic_access * | 检查凭据是否可以订阅某个主题 — 请参阅下方说明 |
get_server_info * | 查看运行状况、功能、用量,以及是否值得尝试管理工具 |
get_account | 查看已配置凭据的身份、角色、限制和用量 |
list_users | 查看所有账户及其各主题的授权情况(管理员) |
publish_message * | 向一个或多个主题发送通知 |
update_message * | 原地修改通知,让进度报告始终保留为同一条通知 |
mark_messages_read | 清除订阅者设备上的通知 |
delete_messages 👤 | 删除通知并取消已安排的通知 |
create_user 👤 | 创建非管理员账户(管理员) |
delete_user 👤 | 删除账户及其授权(管理员) |
manage_user_access 👤 | 授予、拒绝或撤销对某个主题或模式的访问权限(管理员) |
👤 通过 MCP elicitation 向用户征求确认 · 如果客户端无法显示对话框,
则改用两次调用的 confirm_token。
结构化输出
每个工具都声明了 outputSchema,并在文本块之外通过 structuredContent
返回结果,因此客户端无需解析文字说明即可使用结果:
{
"untrusted": true,
"source": "ntfy",
"topics": ["alerts"],
"count": 2,
"next_since": "TmkVCUCmDdWL",
"messages": [{ "id": "TmkVCUCmDdWL", "topic": "alerts", "title": "…" }],
}
untrusted 标记是一个字段,而不只是一句文本,因为如果客户端读取结构化部分而忽略文本,就会得到发布者的文字,却没有任何上下文说明。以下四个用于报告他人所写内容的工具都带有此标记:list_messages、get_message、get_account 和
list_users。get_server_info 不带此标记 — 其中各部分是实例自身的配置和计数器。
此服务构建的字段都有精确定义;此服务只是从 ntfy 传递过来的文档(/v1/config、/v1/stats、发布者的附件元数据)则声明为没有固定形状的对象。比数据更严格的架构并不是更好的契约:SDK 会根据架构验证每个结果,因此上游版本一旦新增字段,整个工具就会无法使用,而不是仅仅显示一个你没预料到的字段。
关于 ntfy 的两件令人意外的事
每个主题的读取和写入权限分别授予。 只有写入权限的发布令牌无法轮询它发布消息的主题;这是正确的配置,并非故障。check_topic_access 只检查_读取_权限,因此检查被拒绝并不意味着发布会失败 — 工具会在结果中说明这一点。
无法列出服务器上的主题。 主题之所以存在,是因为有人向其发布了内容;在开放实例上,主题名称本身就是全部的访问控制。请将主题名称视为机密信息;get_account 和 list_users 是显示现有主题名称的唯一位置。
有意未实现
- 从已发布的消息发送电子邮件或拨打电话。 ntfy 支持这两种操作;一个能根据模型输出向任意地址发送邮件的 MCP 工具,会成为由可注入内容驱动的垃圾邮件中继,而
call会拨出真实且需要付费的电话。 - 创建、读取或交换访问令牌。 这类端点都会返回有效凭据,随后这些凭据就会留在对话记录中。
- 流式订阅(
/sse、/ws、/raw)。工具调用采用请求/响应模式,并受超时限制;list_messages返回相同的数据,但数量有上限。 - 上传附件。 要么通过模型的上下文传输 Base64,要么暴露本地文件系统,而本服务没有理由访问它。实际需要通过 URL 的场景由
attach覆盖。 - 预订、计费、Web 推送、电子邮件和电话验证,以及 Matrix 网关。
GET /v1/account无论如何都会返回其中好几项;get_account会丢弃这些内容,而不是传递本工具中没有工具会用到的载荷。
有意不暴露
不提供主题枚举——ntfy 没有这类 API,其他任何东西也没有。主题之所以存在,是因为有人向其发布过消息;在采用默认访问规则的实例上,主题名称就是全部访问控制,因此列表端点会变成凭据列表。get_account 会列出账户订阅的主题,list_users 会列出每个主题的授权;这才是两种实事求是的回答。
安全
- 先征求用户确认,而不只是告知。 如果客户端支持 MCP 征询,
delete_messages、delete_user、manage_user_access、create_user和update_message会弹出真实对话框,模型无法代替用户作答。如果不支持,则会回退到绑定精确目标指纹的短时令牌——并明确说明这一点,而不会暗示有人已经批准。针对一个目标的确认不能用于执行另一个目标、更长的列表,或在manage_user_access中以不同顺序传入的同一组三个参数。参见征求用户确认。 NTFY_TOPICS也会限制访问控制工具。manage_user_access会拒绝超出列表范围的模式,包括*:授权会永久授予对其覆盖的所有主题的访问权,而有限的允许列表无法覆盖通配符。list_users只会报告各账户针对允许主题的授权,因为授权模式就是主题名称,而主题名称就是持有者凭据。- 确认提示绝不引用 ntfy 中的内容。 提示只会提及主题、数量或用户名,不会包含其他内容,因为模型会读取这些文本。也绝不会提及
create_user收到的密码:它是有效凭据,因此既不会出现在提示中,也不会绑定到令牌。 - 返回的内容会标记为不可信数据,因为它确实不可信:通知中的所有内容都是有权向该主题发布消息的人写入的。
get_account采用允许列表,而非拒绝列表来作答。 它会报告身份、角色、层级、限制、用量以及每个访问令牌的 元数据,并丢弃 ntfy 发送的其他所有内容——包括 ntfy 以明文形式返回的令牌值,以及电话号码、计费标识符、预订和订阅主题名称。未来 ntfy 新增的字段会被丢弃,无需在此处修改代码。- 调用方提供的 URL 必须使用
http或https。click、icon、attach和操作按钮的 URL 会由接收者的设备打开,而不是由服务打开;ntfy 会保存收到的任何内容——包括javascript:URL。 - 发布者可控制的每个字段都有长度限制。 ntfy 将消息正文限制为 4096 字节,但不限制标题或标签列表,因此这里会为它们设置上限。
NTFY_READ_ONLY=true时根本不会注册写入工具,而NTFY_DENY_TOOLS会沿相同原则进行更精细的控制——经过筛选的工具不会被创建,而不是在调用时才被拒绝。
文档
完整指南、工具参考和安全说明请见
ntfy-mcp.ni-c.de(源文件位于 docs/)。
开发
npm install
npm run build
npm run lint && npm run typecheck && npm run test:coverage
架构图和社交卡片由程序生成:编辑
docs/assets/architecture.source.svg 或 docs/assets/og.json,然后运行
npm run assets,不要修改 docs/public/ 下的渲染文件。CI 会运行
npm run assets:check,如果生成文件与源文件不一致,就会失败。
文档站点有自己的清单,因此其工具链不会进入容器镜像或测试矩阵:
cd docs && npm install && npm run build
发布
发布由标签驱动。更新 package.json 中的版本,将 CHANGELOG.md 中
[Unreleased] 下的说明移到新版本标题下,提交,然后运行:
git tag -s vX.Y.Z -m "vX.Y.Z"
git push origin main vX.Y.Z
发布工作流通过 Trusted Publishing(OIDC,并提供溯源信息)发布到 npm, 将多架构容器镜像推送到 GHCR,根据 CHANGELOG 中的章节创建 GitHub 发布,并更新官方 MCP 注册表中的条目。
参与贡献
欢迎提交问题、参与讨论和发起拉取请求——请参阅 CONTRIBUTING.md。如需报告漏洞,请使用 私下报告, 而非公开提交问题;相关政策见 SECURITY.md。
许可证
MIT © Willi Thiel
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。