Zeph Docs
MCP Server

Tools & Resources

Every MCP tool the Zeph server exposes, with its parameters and return shape.

Push titles are automatically prefixed with the project directory name — myapp · Build complete — so the phone feed stays scannable when several sessions push at once.

One-way tools

zeph_notify

Send a one-way push notification. An optional URL auto-switches the push to link type.

title:          "Build complete"
body:           "All 42 tests passed"
url:            "https://github.com/org/repo/actions/runs/123"  (optional)
priority:       "low" | "normal" | "high" | "urgent"
targetDeviceId: "dev_..."  (optional, overrides ZEPH_DEVICE_ID)

zeph_clipboard

Copy text to the user's device clipboard.

text:           "npm install @zeph-to/mcp-server"
targetDeviceId: "dev_..."  (optional)

zeph_file

Send a file to the user's device. Either filePath, for a file already on disk, or content, for text you generated, is required.

filePath:       "/abs/path/screenshot.png"  (images, PDFs, logs — anything on disk)
content:        "{\"status\": \"ok\"}"       (text only; requires fileName)
fileName:       "report.json"               (required with content; defaults to basename of filePath)
title:          "Build Report"              (optional, defaults to fileName)
targetDeviceId: "dev_..."                   (optional)

Images are delivered with their real mime type and render inline on the device. Never base64 a binary file into content — pass filePath and the server reads the bytes off disk.

Returns { pushId: "...", fileKey: "...", fileSize: 42 }.

zeph_broadcast

Send a notification to all subscribers of a channel.

channelId: "ch_..."
title:     "Deploy complete"
body:      "v2.1.0 is live"
url:       "https://..."  (optional)
priority:  "normal"

Interactive tools

These three block until the user responds or the timeout expires, and all require ZEPH_HOOK_ID.

zeph_ask

Ask a question with optional quick-reply buttons and a text input field, combined in one notification.

title:       "What should we do?"
body:        "3 tests failed in auth module"  (optional)
actions:     [{ id: "fix", label: "Fix now", style: "primary" },
              { id: "skip", label: "Skip", style: "secondary" }]  (optional, 1-4)
placeholder: "Or type a custom response..."  (optional)
inputType:   "text" | "multiline"  (default: text)
timeout:     120    (seconds, default: 120, max: 600)
fallback:    "skip" (auto-select on timeout, optional)

Returns { actionId: "fix", timedOut: false } or { value: "custom text", timedOut: false }.

The user can also attach screenshots or files to their answer. Those are downloaded to ~/.zeph/attachments/hook-<eventId>/ and the result gains an attachments array of absolute local paths, alongside the button or the text:

{ value: "look at this", attachments: ["/Users/you/.zeph/attachments/hook-hevt_1/screen.png"],
  attachmentsNote: "The user attached 1 file(s) to this answer. Read each path above to see them.",
  timedOut: false }

Reading those paths is part of reading the answer. Hook attachments are never end-to-end encrypted — the same limitation as the question itself, since the hook route carries no sender key.

zeph_prompt

Ask the user to choose from 2 to 4 options.

title:    "Deploy to production?"
body:     "3 migrations pending"
actions:  [{ id: "yes", label: "Deploy", style: "primary" },
           { id: "no",  label: "Cancel", style: "danger" }]
timeout:  120        (seconds, default: 120, max: 300)
fallback: "no"       (auto-select on timeout, optional)

Returns { actionId: "yes", timedOut: false }.

zeph_input

Request free-form text input.

title:       "Commit message"
body:        "Summarize the changes"
placeholder: "feat: ..."
inputType:   "text" | "password" | "multiline"
timeout:     120    (seconds, default: 120, max: 600)

Returns { value: "feat: add clipboard sync", timedOut: false }, plus attachments when the user attached files, exactly as in zeph_ask.

Client timeouts

zeph_ask, zeph_prompt, and zeph_input block until the user responds, up to their timeout of at most 600 seconds. With ZEPH_WS_URL configured the response arrives over WebSocket the instant it is submitted; otherwise the server polls. Either way the MCP request stays open the whole time.

To keep the client from giving up early, the server emits a notifications/progress every 5 seconds while waiting. Clients must either set a per-request timeout above the tool's timeout, or reset their timeout on progress notifications. Claude Code does the latter by default.

Housekeeping tools

zeph_list

List recent push notifications.

limit: 5         (1-20, default: 5)
type:  "note"    (optional filter: note, link, file, clipboard, hook)

Returns { pushes: [...], total: 5, hasMore: true }.

zeph_dismiss

Mark a specific push as read.

pushId: "push_01HX..."

zeph_dismiss_all

Clear all notifications at once. No parameters. Returns { dismissed: 12, badge: 0 }.

zeph_session_rename

Set a custom display name for the current agent session, shown in the Zeph app under Streams → Agents. This lets an agent label what it is working on — "Prod deploy", "Auth refactor" — so parallel sessions are easy to tell apart on your phone.

It renames the session this server runs in, resolved from the listener device id plus the tmux session name, and the name persists until changed.

alias: "Prod deploy watcher"   (1-60 chars)

Returns { renamed: true, session: "zeph-myapp", alias: "Prod deploy watcher" }, or { renamed: false, reason: "..." } when there is no active session to rename — that is, when it is not running inside a zeph listener tmux session.

Resources

zeph://devices

Lists connected devices with online status. Use it to check which devices will receive notifications.

zeph://channels

Lists channels the user owns or subscribes to. Use it to find a channelId for zeph_broadcast.

On this page