Skip to main content
Glama

ntfy-cf

ntfy-cf 是 ntfy API 的一个私有、基于 Workers 原生的子集。已部署的 Worker 名为 ntfy-kyeshimizu。

架构

公共的 NtfyWorker 负责校验主题、路由、请求大小以及 Authorization: Bearer ... 令牌。每个主题通过 getByName(topic) 映射到一个 SQLite Durable Object(Topic)。该对象最多存储 100 条消息、保留最长 7 天,处理轮询请求,并向休眠中的 WebSocket 广播新消息。

HTTP API 在发布、轮询和 WebSocket 订阅时都需要 bearer 令牌。Worker 服务绑定通过 NtfyWorker 调用类型化的 publish() RPC;该私有路径不需要 HTTP 令牌。

代理可以通过位于 /mcp 的、经过认证的 Streamable HTTP MCP 端点使用同一服务。它暴露了 publish_notification 和 get_notifications。

主题必须匹配 [A-Za-z0-9._-]+ 且长度不超过 128 个字符。HTTP 请求体和 RPC 通知限制为 64 KiB。发布的消息使用 ntfy 风格的 JSON 对象,包含 event、id、time、topic、message 以及可选元数据,如 title、tags、priority、click、actions、attach、filename、email、call 和 icon。

Related MCP server: mcp-gotify

本地开发

创建一个仅限本地的 .dev.vars 文件(Wrangler 会忽略它):

PUBLISH_TOKEN=replace-with-a-local-random-token

启动 Worker:

npm install
npm run types
npx wrangler dev

在下面的示例中使用与 .dev.vars 相同的值。不要提交 .dev.vars,也不要把令牌放在源代码、shell 历史或文档中。

HTTP API

将 shell 变量设置为你在本地创建或存储在密钥管理器中的令牌:

export NTFY_TOKEN='replace-with-the-token-from-your-local-environment'
export NTFY_URL='http://localhost:8787'

使用 ntfy 兼容的请求头发布纯文本:

curl -sS -X POST "$NTFY_URL/alerts" \
  -H "Authorization: Bearer $NTFY_TOKEN" \
  -H 'Title: Build finished' \
  -H 'Tags: white_check_mark,ci' \
  -H 'Priority: 4' \
  --data-raw 'release 42 is ready'

发布 JSON 元数据:

curl -sS -X POST "$NTFY_URL/alerts" \
  -H "Authorization: Bearer $NTFY_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"message":"Deploy finished","title":"Production","priority":3,"tags":["deploy"]}'

以换行分隔的 JSON 形式轮询有界主题历史。since=all(或不带 since)返回保留的历史;Unix 时间戳返回之后的消息;已有的消息 ID 返回该 ID 之后的消息。

curl -sS "$NTFY_URL/alerts/json?poll=1&since=all" \
  -H "Authorization: Bearer $NTFY_TOKEN"

检查就绪状态:

curl -i "$NTFY_URL/healthz"

WebSocket 端点是 /<topic>/ws。curl 握手可用于冒烟检查,但 curl 不是 WebSocket 客户端,无法方便地消费后续帧:

curl --http1.1 -i -N "$NTFY_URL/alerts/ws" \
  -H "Authorization: Bearer $NTFY_TOKEN" \
  -H 'Connection: Upgrade' \
  -H 'Upgrade: websocket' \
  -H 'Sec-WebSocket-Version: 13' \
  -H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==' \
  --max-time 5

如需实时订阅,请使用 websocat 等 WebSocket 客户端,并使用带 Authorization 请求头的 ws://localhost:8787/alerts/ws。第一帧是 open 事件;后续的发布会以 message 事件到达。

Bearer 令牌

该令牌是一个 Worker 密钥,不是 ntfy 用户/账户凭据。在完成 Wrangler 认证后配置它:

npx wrangler secret put PUBLISH_TOKEN --name ntfy-kyeshimizu

仅在 Wrangler 提示时粘贴令牌。该命令不应出现在 CI 日志或已提交的文件中。未携带完全匹配的 bearer 令牌的请求将收到 401 Unauthorized。

部署

已签入的 Wrangler 配置已将服务命名为 ntfy-kyeshimizu,启用了 Workers Observability,并声明了 Topic SQLite Durable Object 迁移。使用以下命令部署:

npx wrangler deploy
npx wrangler secret put PUBLISH_TOKEN --name ntfy-kyeshimizu

使用已部署的 HTTPS URL 作为 NTFY_URL,并在 WebSocket 冒烟检查中使用 wss:// 而不是 ws://。切勿打印或提交该密钥。

服务绑定与类型化 RPC

在消费方 Worker 的 wrangler.jsonc 中,绑定命名 RPC 入口点:

{
  "services": [
    {
      "binding": "NTFY",
      "service": "ntfy-kyeshimizu",
      "entrypoint": "NtfyWorker"
    }
  ]
}

使用 Wrangler 生成消费方 Worker 的绑定类型,当发布方 Worker 和本 Worker 是独立项目时,需同时包含两者的配置:

npx wrangler types -c wrangler.jsonc

生成的 Env.NTFY 类型来自导出的 NtfyWorker 入口点。调用时无需 HTTP 凭据:

const notification = await env.NTFY.publish("alerts", {
  message: "Published from another Worker",
  title: "Internal job",
  tags: ["worker"],
  priority: 3,
});

完整的发布方入口点请参阅 examples/worker-publisher.ts。服务绑定是 Worker 之间的私有调用;不要将绑定对象暴露给不受信任的请求数据。

OpenCode 插件、MCP 与代理技能

该仓库包含一个项目本地的 OpenCode 插件、MCP 配置和技能:

  • .opencode/plugins/ntfy-cf.js 自动发送生命周期通知。

  • opencode.jsonc 连接已部署的 /mcp 端点。

  • .opencode/skills/ntfy-cf/SKILL.md 指导代理何时以及如何发送通知。

在从该仓库启动 OpenCode 之前设置令牌:

export NTFY_CF_TOKEN='replace-with-your-worker-secret'
export NTFY_CF_TOPIC='agent-status'
opencode2

OpenCode 会自动发现插件、ntfy-cf 技能和 ntfy MCP 服务器。当根会话结束、遇到错误或请求权限时,插件会发送通知。子会话的完成和错误事件会被抑制。设置 NTFY_CF_URL 可覆盖已部署的 Worker URL。投递失败会被记录日志,且绝不会中断 OpenCode 会话。该插件针对 OpenCode 的 V2 事件 API;尚未暴露 ctx.event.subscribe() 的预览版构建会加载插件,但会禁用自动事件。

MCP 使用请求头认证而非 OAuth,并支持无状态的 Streamable HTTP JSON-RPC 请求。不要将令牌提交到 OpenCode 配置中。

其他 MCP 客户端可以连接到:

https://ntfy-kyeshimizu.kyeshimizu.workers.dev/mcp

在每个请求上发送 Authorization: Bearer <token>。该端点实现了 MCP 的 initialize、ping、tools/list 和 tools/call;它没有运行时 MCP 框架依赖,也不捆绑 Zod。

验证与运维

运行本地自动化冒烟测试套件和类型检查:

npm test
npm run typecheck

对于已部署的冒烟测试,请验证 /healthz,向一次性主题发布消息,使用 since=all 轮询,并执行 WebSocket 握手。确认缺少或错误的 bearer 令牌的请求返回 401,无效路由返回 404。

wrangler.jsonc 中启用了 Workers Observability,并采用全量头部采样。使用 Cloudflare 仪表板或 Wrangler 日志检查结构化事件,如 publish 和 websocket_error。Durable Object 历史是有界的,不能替代审计日志或归档存储。

兼容性限制

这不是上游 Go 服务器的直接替代品。v1 未实现:

  • 上游 Web 应用、用户账户、访问控制列表或主题管理。

  • Android FCM、iOS/APNs 转发、UnifiedPush 或其他移动端投递。

  • SSE、无限 HTTP 流式传输或长轮询订阅。

  • 附件/上传、附件存储、邮件投递、语音通话或 R2 集成。

  • 定时或延迟投递。delay 字段会被拒绝。

  • 本 README 未列出的上游服务器功能,包括完整的认证和管理 API。

该服务仅提供进程内通知历史和实时 WebSocket 投递。元数据字段包含在通知对象中;它们不会激活外部投递提供商。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    A Model Context Protocol server enabling AI systems to send real-time notifications to phones, desktops, and other devices through the ntfy publish/subscribe service.
    610 npm
    25
    Apache 2.0
  • A
    license
    B
    quality
    D
    maintenance
    MCP server for sending Gotify push notifications to your devices.
    1
    MIT
  • A
    license
    C
    quality
    D
    maintenance
    MCP server for sending notifications to ntfy.sh or self-hosted ntfy instances.
    2
    16 npm
    MIT