Skip to content

MCP Server

phucmpham edited this page Mar 18, 2026 · 1 revision

MCP Server (AI Agent Integration)

Connect Claude Code (or any MCP client) to your Zalo conversations. The MCP server exposes 4 tools that let AI agents read, reason about, and reply to Zalo messages in real-time.

Added in v1.2.0 · Requires Node.js 18+


User Stories

🤖 "I want Claude Code to read my Zalo messages"

You're working in the terminal and want Claude to check if anyone messaged you on Zalo — without switching apps.

# 1. Start MCP server (background process)
zalo-agent mcp start

# 2. Claude Code auto-discovers the tools and can call:
#    zalo_get_messages → read buffered messages
#    zalo_list_threads → see active conversations

Config (add to .claude/settings.json):

{
  "mcpServers": {
    "zalo": {
      "command": "zalo-agent",
      "args": ["mcp", "start"]
    }
  }
}

💬 "I want Claude to reply on my behalf"

You're in a coding session and a colleague asks a quick question on Zalo. Tell Claude: "reply to that message with ..." and it calls zalo_send_message.

You: "Reply to thread X saying I'll check it after lunch"
Claude: [calls zalo_send_message with threadId, text, threadType]
→ Message sent ✓

📡 "I want to run MCP on my VPS"

Your server monitors Zalo 24/7. AI agents connect over HTTP instead of stdio.

zalo-agent mcp start --http 3847 --auth my-secret-token

MCP clients connect via POST http://your-vps:3847/mcp with Authorization: Bearer my-secret-token.

🔔 "I want Zalo group notifications when agent is offline"

When no AI agent is connected, forward message summaries to a Zalo group so you don't miss anything.

Edit ~/.zalo-agent-cli/mcp-config.json:

{
  "notify": {
    "enabled": true,
    "thread": "GROUP_ID_HERE",
    "on": ["dm"],
    "cooldown": "5m"
  }
}

🧹 "I only care about certain conversations"

Filter noise — watch only DMs, or only specific groups:

{
  "watchThreads": ["dm:*"],
  "triggerKeywords": ["@bot", "urgent"]
}

Tools Reference

Tool Description Key Params
zalo_get_messages Get buffered messages (cursor-based polling) threadId?, since, limit
zalo_send_message Send text to a thread threadId, text, threadType (0=DM, 1=Group)
zalo_list_threads List active threads with unread counts type (dm/group/all)
zalo_mark_read Discard messages up to cursor cursor

Cursor-based Polling

1st call:  zalo_get_messages()           → { messages: [...], cursor: 5, hasMore: false }
2nd call:  zalo_get_messages(since: 5)   → only new messages after cursor 5
Cleanup:   zalo_mark_read(cursor: 5)     → discard old messages from buffer

Architecture

Zalo Cloud ──WebSocket──→ zalo-agent mcp ──stdio/HTTP──→ Claude Code
                              │
                    ┌─────────┼─────────┐
                    │         │         │
              Ring Buffer  Thread    Notifier
              (per-thread)  Filter   (Zalo group)
              cursor-based  glob     batched alerts
              auto-evict    noise    cooldown window

Ring Buffer: Stores messages per thread. Auto-evicts by age (default 2h) and size (default 500). Cursor-based reads for incremental polling.

Thread Filter: Glob patterns (dm:*, group:support_123) control which threads are watched. Noise filter drops stickers, system messages, and short emoji-only messages.

Notifier: When no agent is connected, batches unread DM notifications and sends a summary to a configured Zalo group.


Configuration

Config file: ~/.zalo-agent-cli/mcp-config.json

Field Default Description
watchThreads ["dm:*", "group:*"] Glob patterns for threads to monitor
mode "manual" Polling mode
triggerKeywords ["@bot"] Keywords that trigger attention
notify.enabled false Enable group notifications
notify.thread null Group ID to send notifications to
notify.on ["dm"] Event types to notify on
notify.cooldown "5m" Batch window before sending
limits.maxMessagesPerPoll 20 Max messages per get_messages call
limits.bufferMaxAge "2h" Auto-evict messages older than this
limits.bufferMaxSize 500 Max messages per thread

Commands

# Local (stdio — for Claude Code)
zalo-agent mcp start

# HTTP (for VPS / remote agents)
zalo-agent mcp start --http 3847

# HTTP with auth
zalo-agent mcp start --http 3847 --auth your-secret-token

# Custom config
zalo-agent mcp start --config /path/to/mcp-config.json

Health Check (HTTP mode)

curl http://localhost:3847/health
# → {"status":"ok","uptime":123,"threads":5}

Security

  • stdio: No auth needed (local process, same user)
  • HTTP: Bearer token auth on all endpoints except /health
  • Reconnect: Auto re-login on WebSocket close (except duplicate session = fatal)
  • Credentials: Reuses existing zalo-agent session (no extra login)

Clone this wiki locally