Quick links

Give your AI agent a way to reach your phone.

Zona MCP is a small stdio server with three tools. When a long job ends, your agent callszona_notify and the alert is waiting in your Zona inbox. The source token is read from a file on your machine and never enters the conversation.

v1.0.0 · Node 20+ · MIT · 16.5 KB

You

Run the release build, then tell me on Zona when it finishes.

Agent

calls zona_notify

{
  "title": "Build complete",
  "body": "The release finished.",
  "category": "build",
  "severity": "medium"
}
Result

ok · 202idempotentReplay: false · error: null

Inbox
Illustrative exchange. The arguments are the README example; the source name is whatever you call the source in the app.

Three tools, nothing else

The descriptions below are the server's own text, word for word. It is what your agent reads when it lists the tools. None of them takes a token argument.

zona_notify

Send a Zona notification

Send an inbox notification to the owner's Zona app. Title 1-120 chars, body 1-2000. Optional category, severity (low|medium|high|critical), up to five PNG/JPEG/WebP attachment paths, and an idempotency key. Do not put secrets in title, body, or data.

Input

FieldTypeRule
titlerequiredstring1–120 characters
bodyrequiredstring1–2000 characters
categoryoptionalstring1–80 characters
severityoptionalenumlow · medium · high · critical
idempotencyKeyoptionalstring8–128 characters: letters, digits and . _ : -, starting with a letter or digit (the tool accepts 1–128, but /notify rejects other keys with 400 INVALID_IDEMPOTENCY_KEY); defaults to mcp-<uuid>
attachmentsoptionalstring[]Up to five local PNG, JPEG or WebP file paths

Returns

  • ok
  • status
  • notificationId
  • sourceName
  • idempotentReplay
  • attachmentAccepted
  • pushAttempted
  • pushAccepted
  • error

With attachments the server sends multipart/form-data, one attachment part per file. Without them it sends JSON. Every send carries data: { "sender": "zona-mcp" }.

zona_status

Zona MCP status

Check that the local Zona source-token file exists. Never returns the token.

Input

No arguments.

Returns

  • tokenFile
  • tokenPath
  • notifyUrl
  • hint

zona_ping

Ping Zona

Send a short test notification to confirm the local token and /notify path work.

Input

titlestring, optional
1–120 characters; defaults to “Zona ping” and the UTC time
bodystring, optional
1–2000 characters; defaults to “MCP ping from this machine.”

Returns

  • ok
  • status
  • notificationId
  • sourceName
  • idempotentReplay
  • pushAccepted
  • error

Download the server

One zip with the server, its lockfile, the README, the agent skill and the license. No node_modulesinside: npm ci installs the pinned dependencies.

Check the SHA-256 before you run it
# macOS or Linux
shasum -a 256 zona-mcp-1.0.0.zip

# Windows PowerShell
Get-FileHash .\zona-mcp-1.0.0.zip -Algorithm SHA256
Version
1.0.0
Size
16,846 bytes
SHA-256
b4ac394e0e1a26598a443d60f2c755c13ef7b6bf6697cdee3e43fdaab2bfb3f6
Runtime
Node.js 20+
Transport
stdio
Dependencies
  • @modelcontextprotocol/sdk 1.30.0 · MIT
  • zod 3.25.76 · MIT
Contents
  • zona-mcp/server.mjs
  • zona-mcp/package.json
  • zona-mcp/package-lock.json
  • zona-mcp/README.md
  • zona-mcp/SKILL.md
  • zona-mcp/LICENSE

Install in five steps

You need Node.js 20 or later and the Zona app on your iPhone for the source token.

  1. Unzip it somewhere permanent

    Your host starts the server from its absolute path, so keep the zona-mcp folder where it will stay.

    Extract
    unzip zona-mcp-1.0.0.zip
    
    # Windows PowerShell
    Expand-Archive .\zona-mcp-1.0.0.zip -DestinationPath .
  2. Install dependencies

    Node.js 20+ provides fetch, FormData and crypto.randomUUID, which the server uses directly.

    Install from the lockfile
    cd zona-mcp
    npm ci
  3. Save your source token

    In the Zona app, open Sources, create a source (or a new key), copy thezona_live_... token once, and save it as a single line in the token file with your editor. Treat it like a password.

    Token file location
    # macOS or Linux: one zona_live_... line, no quotes
    ~/.zona/token
    
    # Windows
    %USERPROFILE%\.zona\token

    You can also set ZONA_SOURCE_TOKEN. When it is set, the server uses it instead of the file.

  4. Add it to your host

    Register a server named zona that runs node with the absolute path toserver.mjs. Restart the CLI after changing MCP config.

    Configuration for your host
  5. Check, then ping

    Ask your agent to run zona_status. It reports tokenFile: true when a token is configured, without returning the token. Then ask for zona_ping: a short test alert with categorydemo arrives in your inbox.

Configure your host

Replace the path with the absolute path to server.mjs on your machine. Forward slashes work on Windows too. Restart the CLI after changing MCP config.

Claude Code

Add it once with the CLI so it is available in every project, or commit the JSON as .mcp.json at a project root to share it with that project.

Terminal
claude mcp add --scope user zona -- node /absolute/path/to/zona-mcp/server.mjs
.mcp.json
{
  "mcpServers": {
    "zona": {
      "command": "node",
      "args": ["/absolute/path/to/zona-mcp/server.mjs"]
    }
  }
}

Claude Desktop

Open Settings, then Developer, then Edit Config. That opens claude_desktop_config.json: ~/Library/Application Support/Claude/ on macOS, %APPDATA%\Claude\ on Windows.

claude_desktop_config.json
{
  "mcpServers": {
    "zona": {
      "command": "node",
      "args": ["/absolute/path/to/zona-mcp/server.mjs"]
    }
  }
}

Merge the zona entry into any mcpServers object that already exists, then quit and reopen the app.

Cursor

Use ~/.cursor/mcp.json for every workspace, or .cursor/mcp.json inside one project.

mcp.json
{
  "mcpServers": {
    "zona": {
      "command": "node",
      "args": ["/absolute/path/to/zona-mcp/server.mjs"]
    }
  }
}

Codex

Codex CLI reads MCP servers from ~/.codex/config.toml.

~/.codex/config.toml
[mcp_servers.zona]
command = "node"
args = ["/absolute/path/to/zona-mcp/server.mjs"]

Grok

Add the server table to your Grok CLI config.toml.

config.toml
[mcp_servers.zona]
command = "node"
args = ["/absolute/path/to/zona-mcp/server.mjs"]
enabled = true

# Windows with MSYS only
[mcp_servers.zona.env]
MSYS = "noglob"

On Windows, add the env table with MSYS = "noglob" only if you use MSYS.

Other stdio hosts

Any MCP host that launches stdio servers from an mcpServers map accepts the same block.

MCP config
{
  "mcpServers": {
    "zona": {
      "command": "node",
      "args": ["/absolute/path/to/zona-mcp/server.mjs"]
    }
  }
}

The server block is the one the Zona MCP README documents. Config file locations belong to each host and can move between versions, so check your host's MCP documentation if yours differs.

Try it in plain words

You never name a tool or a token. Say what you want to hear about, and the agent picks the call.

  • Prompt: “Is Zona set up on this machine?”

    Calls zona_status

    Reports whether a token is configured, where the server looks for it and which endpoint it will call. The token itself never comes back.

  • Prompt: “Send me a Zona ping.”

    Calls zona_ping

    A short test alert with category demo, to prove the token and the /notify path work end to end.

  • Prompt: “Run the full test suite. When it finishes, send me a Zona alert with the pass and fail counts, severity high if anything failed.”

    Calls zona_notify

    The agent writes the title and body from the real result and picks the severity you asked for.

  • Prompt: “Render the chart, then send it to Zona with the PNG attached.”

    Calls zona_notify

    The attachments argument takes up to five local PNG, JPEG or WebP paths, sent as multipart.

Teach it when to send

The zip includes SKILL.md, the prompt for AI CLIs that answers to /zona. Copy it into your host's skills directory. It tells the agent:

  • Prefer the MCP tools over hand-written HTTP whenever the zona server is connected.
  • Use the qualified tool name the host exposes, and never invent a token argument.
  • Send only when you asked for an alert, or when a long job you asked to hear about has finished.
  • Keep title and body short, and never put secrets in them.
  • On a missing token file or INVALID_TOKEN, ask you to create a new source key in the app instead of searching the workspace for tokens.
  • Quiet hours still save the alert in the inbox; only the phone banner is skipped.
Read SKILL.md
zona-mcp/SKILL.md
---
name: zona
description: >
  Send inbox notifications through Zona and operate the Zona MCP.
  Use when the user wants a Zona ping, phone alert, /notify send, agent
  notification, source token, attachments on a Zona send, or runs /zona.
---

# Zona

Zona is a private notification inbox. Agents send an HTTPS request with a
source token. Keep copy short and never include secrets.

## Secrets

- Token file: `~/.zona/token` (one `zona_live_...` line). Windows:
  `%USERPROFILE%\.zona\token`.
- Optional override: env `ZONA_SOURCE_TOKEN`.
- Never print, log, commit, or put the token in URLs, README, or tool args.
- If the file is missing or `/notify` returns `INVALID_TOKEN`, ask the owner to
  create a new source key in the app and replace the file. Do not search the
  workspace for tokens.

## Prefer the MCP

When the `zona` MCP server is connected, use its tools instead of curling:

| Tool | When |
| --- | --- |
| `zona_status` | Check a token is configured (it does not return the token). |
| `zona_notify` | Real send: title, body, optional category, severity, up to five image paths. |
| `zona_ping` | Connectivity check. |

Call the host's MCP tool with the `zona__…` qualified name it exposes. Do not
invent a token argument.

## Direct HTTP (MCP unavailable)

```
POST https://gerncrjtrdjtjvybvseb.supabase.co/functions/v1/notify
Authorization: Bearer <token from the file, never logged>
Idempotency-Key: <required unique key>
```

JSON body: `title` (1–120), `body` (1–2000), optional `category` (≤80),
`severity` (`low|medium|high|critical`), `data` object ≤4 KiB.

Images: `multipart/form-data`, repeat the `attachment` part once per PNG/JPEG/WebP
file, max five.

Quiet hours still save the alert in the inbox; only the phone banner is skipped.

## When to send

Send after a user-asked Zona alert or a completed long job the owner asked to
be notified about. Keep copy short and non-secret.

Built so the token never leaks

The server is a single readable file, server.mjs. Read it before you run it; these are the rules it keeps.

  • The token stays on your disk

    The server reads ZONA_SOURCE_TOKEN or ~/.zona/token each time it sends. It never writes the token to stdout, stderr or a tool result, and it refuses a value that does not start with zona_live_.

  • Never paste a token into a prompt

    No tool takes a token argument, so there is never a reason to put one in the conversation, a URL, a README or a commit. If a token has been exposed, revoke that key in the app, create a new one and replace the file.

  • Errors are scrubbed

    When a send fails locally, the error message is cleaned before the agent sees it: anything shaped like zona_live_… becomes zona_live_[redacted], and your home directory is shortened to ~.

  • Nothing secret in the alert

    Title and body appear in push banners and are stored in your inbox. Tell your agent to keep them short and free of credentials, keys and personal data.

  • Attachments are local files

    The server reads each attachment path from your disk and uploads it. Only let the agent attach images you mean to send: up to five PNG, JPEG or WebP files.

  • Retries do not duplicate

    Each send carries an Idempotency-Key. Pass your own durable idempotencyKey, such as a job ID, and a retried call with the same content returns the stored alert instead of creating a second one. Without one, the server generates mcp-<uuid> per call.

Environment

VariableBehaviour
ZONA_SOURCE_TOKENOptional. Used instead of the token file when set.
ZONA_NOTIFY_URLOptional. Overrides the endpoint, which defaults to https://gerncrjtrdjtjvybvseb.supabase.co/functions/v1/notify.

Requests time out after 15 seconds. Zona MCP 1.0.0 runs on Node.js 20+. For how Zona handles data on the server, read the security overview.

Every token starts in the app.

Create a source in Zona on your iPhone, save its token, and your agent can reach you.