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.