Viber MCP Server
Allows sending and reading Viber messages by automating the Viber Desktop application on macOS, including tools for sending messages, replying to the current chat, opening conversations, reading visible chat via OCR, listing chats and contacts, and saving notes to 'My Notes'.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Viber MCP Serversend a message to Mom saying I'll be late"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Viber MCP (macOS)
An MCP server that lets an AI assistant (e.g. Claude) send and read Viber messages by driving your already-running, signed-in Viber Desktop app on macOS.
Viber has no local/public API and its message database is encrypted, so this works entirely through UI automation:
Send — open the chat via the
viber://URL scheme, paste the text, and click the send button.Receive — capture the visible Viber window and OCR it with Apple's Vision framework.
⚠️ Unofficial. Not affiliated with, endorsed by, or supported by Viber / Rakuten. It automates the desktop UI on your own machine and account. UI automation is inherently version-sensitive and may break when Viber updates. Use at your own risk and review your account's terms of service.
Why it works this way
Three hard constraints shaped the design (all verified on Viber v28.2.0):
The message DB is unreadable.
~/Library/Application Support/ViberPC/<number>/viber.dbis encrypted with a Botan page codec (random header, notSQLite format 3), with no public key-derivation recipe. So history can't be read from disk.The accessibility tree is unusable. Viber is a Qt app; AX queries hang, so there's no element tree to read or click.
Qt ignores ordinary synthetic input. Every click/keystroke must be generated from a real HID event source (
CGEventSourceCreate(kCGEventSourceStateHIDSystemState)) — plainCGEvents and System Events keystrokes are silently dropped by Qt's input widgets.
What's left — and what this uses — is the viber:// URL scheme, HID-sourced input, and screen OCR.
Related MCP server: MCP Remote macOS Control Server
Tools
Tool | Description |
| Open the chat for |
| Send |
| Bring a conversation to the foreground without sending. |
| Open a conversation and return its visible text in one step. |
| OCR the currently-visible Viber window and return its text. |
| Save a note to Viber's private "My Notes" self-chat (opens it via search, then sends). |
| Open the "My Notes" self-chat without saving. |
| List the sidebar chats (names, previews, times, unread counts) via OCR — a quick inbox overview. |
| Paste |
| Search Viber by name and open the best-matching contact/chat (exact/prefix beats substring). Returns |
| Return the name → number aliases from |
to is either an E.164 number (+639171234567) or a name defined in contacts.json.
Unknown names error out rather than guess a recipient. send_message returns verified: true when
the sent message is confirmed on screen (false = not seen, null = couldn't check).
Requirements
macOS (tested on macOS 15/26, Apple Silicon)
Viber Desktop installed, running, and signed in
uv(Python is managed byuv)
Install
git clone <your-fork-url> viber-mcp
cd viber-mcp
uv sync
cp contacts.example.json contacts.json # then edit with your real contactsmacOS permissions (required)
Grant these to the app that launches the server (your terminal — iTerm/Terminal — or Claude), in System Settings → Privacy & Security:
Accessibility — synthetic clicks/keystrokes (sending).
Screen Recording — window capture (reading + send verification).
The first send/read fails with a clear message until these are granted. After granting, fully quit and reopen the host app so the permission binds.
If you get
not allowed to send keystrokes(error 1002) while the toggle already looks on, reset the stuck TCC entry and relaunch:tccutil reset Accessibility <your-terminal-bundle-id>(e.g.com.googlecode.iterm2,com.apple.Terminal).
Configure contacts
contacts.json maps friendly names to E.164 numbers (it is git-ignored — it holds real numbers):
{
"Me": "+639171234567",
"Mom": "+639181234567"
}Names that aren't in the file must be given as full E.164 numbers.
Use it from Claude Code
Register the server (user scope):
claude mcp add --transport stdio --scope user viber -- \
uv --directory "$(pwd)" run server.pyCheck with claude mcp list (should show viber … ✓ Connected). After editing the server code,
reconnect so Claude reloads it (/mcp → reconnect viber, or restart Claude Code). Remove with
claude mcp remove viber.
/viber-reply slash command (optional convenience)
Copy commands/viber-reply.md into ~/.claude/commands/ (user scope) or your project's
.claude/commands/. It reads the open chat, drafts a reply in your voice, and pastes it into the
compose box without sending — you review and send.
/viber-reply
/viber-reply keep it short and warm; say I'll call tonightUse it standalone (no Claude)
A small MCP client is included for testing:
uv run client.py list # advertise tools
uv run client.py contacts # show alias map
uv run client.py open "Mom" # open a chat
uv run client.py send "Mom" "hello" --dry-run # fill box, don't send
uv run client.py send "Mom" "hello" # actually send
uv run client.py draft "a reply to review" # drop draft in open chat (not sent)
uv run client.py read # OCR the open chatHow it works (details)
Send:
open viber://chat?number=<E164>opens the chat (desktop navigation takes a few seconds, so the window is polled via OCR until the recipient's chat is confirmed — and the send is refused if the number "isn't on Viber"). Then: click the compose box, clear any draft, paste the clipboard text (emoji/unicode/newlines survive), click the send button, and OCR-verify the bubble appeared. The clipboard is saved and restored around the paste.Receive: the largest on-screen window owned by "Rakuten Viber" is captured with
screencapture -l <id>and OCR'd byVNRecognizeTextRequest. It only sees what's on screen.
Automation constraints
Because there's no API — only synthetic input + OCR against a Qt app — a few non-obvious rules make
or break reliability. Keep these in mind when running the tools or editing viber_send.py:
Synthetic input must use a real HID event source. Qt silently drops plain
CGEvents and System Events keystrokes; the code posts every click/keystroke fromCGEventSourceCreate(kCGEventSourceStateHIDSystemState).Sidebar, search box, send button, and panel-close ✕ are targeted by fixed PIXEL offsets from the window edges — not fractions. The sidebar and side panels have fixed pixel widths, so fraction-based clicks miss on wide/maximized windows.
Any right-side panel (chat-info or sticker "Settings") must be closed before sending — it shifts the send button. The code detects and closes it automatically.
Sending clicks the send button; it does not press Return ("Send message on Enter" may be off).
viber://chat navigation is slow and mobile-first — the code polls via OCR until the target chat is confirmed, and refuses to send if the number "isn't on Viber". You cannot message your own number ("cannot add yourself"); My Notes is a separate chat.Keep Viber in a normal window on the main desktop — not macOS fullscreen. Fullscreen puts it on a separate Space, causing window-ID churn and blank captures. Don't resize it mid-operation, and prefer keeping side panels closed.
OCR sees only on-screen text and can garble small/emoji text or interleave the sidebar with the open conversation; the returned
verifiedflag is best-effort (false negatives are common).
Project layout
File | Purpose |
| FastMCP stdio server; defines the tools |
| platform-neutral recipient resolution, send pipeline, search scoring |
| platform-neutral formatting of OCR observations into read results |
|
|
| macOS backend — the only file with OS APIs (Quartz/Vision/AppKit) + Viber layout |
|
|
| standalone MCP client for testing |
| your name → number map (git-ignored) |
| template to copy |
| optional Claude Code slash command |
Porting: add backends/<os>.py implementing Backend, wire it into get_backend(), and
re-tune that platform's UI-element locations. All domain logic and tools are shared. (Windows can
likely target elements via UI Automation instead of coordinates; Linux/Wayland restricts capture and
synthetic input, so X11 is easier.)
Limitations & caveats
OCR sees only on-screen text — scroll to bring older messages into view; it can garble text or interleave the sidebar's chat previews with the conversation.
No message history from disk (encrypted DB).
Names resolve from
contacts.json— Viber's own contact list can't be read.Version-sensitive: a Viber UI/layout change can require small coordinate tweaks.
Messaging your own number is blocked by Viber ("cannot add yourself"); "My Notes" is separate.
Privacy & security
Runs entirely locally; it does not send your messages or contacts anywhere except into Viber.
contacts.jsonis git-ignored so real numbers don't get committed.Requires powerful macOS permissions (Accessibility, Screen Recording) for the host app — grant only if you understand and trust that.
License
MIT — see LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/wawimundo/viber-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server