AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Zalo Agent

mcp-vuhai2002-zalo-agent · by vuhai2002

Self-hosted AI agent living inside Zalo (personal account). Multi-account, 15 tools + external MCP servers, web dashboard, scheduler, durable memory, rich-text messages. Provider-agnostic: any OpenAI-compatible endpoint or Anthropic. TypeScript + SQLite. MIT.

— No reviews yet
0 installs
6 views
0.0% view→install

Install

$ agentstack add mcp-vuhai2002-zalo-agent

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ● Network access Used
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ● Environment & secrets Used
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-vuhai2002-zalo-agent)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 27d ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Zalo Agent? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Agent AI thường trú trên Zalo. Chạy được trên hai loại kênh: tài khoản Zalo cá nhân (qua zca-js) và tài khoản Zalo Bot chính thức (qua Zalo Bot API). Nhiều account chạy chung một tiến trình, mỗi account một "não" riêng, 15 công cụ, dashboard web đầy đủ. Tự host, không phụ thuộc nhà cung cấp LLM nào.

Cài đặt • Hai loại kênh • Tính năng • Dashboard • An toàn • Kiến trúc • English


Luồng một lượt: tin Zalo -> lọc (allowlist, @mention) -> gộp theo thread -> agent loop (LLM tự gọi tool) -> làm sạch + dịch định dạng -> cắt theo trần byte -> gửi.

Không có bước nào chạy code do model sinh ra. Nội dung lấy từ web luôn bị bọc trong thẻ đánh dấu là dữ liệu, không phải mệnh lệnh.

Hai loại kênh

Một tiến trình chạy được cả hai loại tài khoản cùng lúc, trộn lẫn tùy ý. Chọn loại lúc tạo account trên dashboard, không đổi được sau đó.

| | Tài khoản cá nhân | Tài khoản Zalo Bot chính thức | |---|---|---| | Thư viện / API | zca-js (không chính thức) | Zalo Bot API - bot-api.zaloplatforms.com (chính thức) | | Đăng nhập | quét QR ngay trên dashboard | dán Bot Token vào dashboard | | Nhận tin | WebSocket listener + tự kết nối lại | long polling getUpdates | | Rủi ro khóa tài khoản | có - chỉ dùng nick phụ | không | | Ai nhắn được | phải là bạn bè | ai có link cũng nhắn được | | Công cụ dùng được | đủ 15 | 7 trong 15 (xem bảng dưới) | | Định dạng chữ | định dạng gốc Zalo (textProperties) | chữ trơn | | Trần một tin | theo cấu hình (mặc định 2000 ký tự) | 2000 ký tự, server ép cứng | | Gửi file / ảnh / thả cảm xúc / tag | có | không có method trên API | | Lịch hẹn | có | có | | Allowlist mặc định | mở | đóng (mode: "list") |

> [!IMPORTANT] > Zalo Bot API KHÁC Zalo OA API. Hai sản phẩm này bị nhầm lẫn khắp nơi, kể cả trong tài liệu > bên thứ ba. Chính sách "chỉ được nhắn trong 7 ngày kể từ tương tác cuối" và biểu phí gửi tin là > của OA API (openapi.zalo.me), không áp cho Bot API mà dự án này dùng.

Tạo tài khoản Zalo Bot

  1. Mở Zalo, tìm Official Account "Zalo Bot Manager".
  2. Chọn "Tạo bot" (mở mini app Zalo Bot Creator). Tên bot bắt buộc bắt đầu bằng "Bot".
  3. Token được gửi vào tin nhắn Zalo cho bạn.
  4. Dashboard > Accounts > Thêm account > Loại kênh = Tài khoản bot chính thức > dán token.

Server kiểm token với Zalo trước khi lưu (gọi getMe) - token sai thì không lưu gì cả, tránh dựng ra một account trông như đã cấu hình xong mà không bao giờ chạy. Lưu xong account tự khởi động lại ngay.

Vì sao 8 công cụ không chạy trên kênh Bot

Không phải chọn cho an toàn - là đo trên API sống: dò 17 method, 13 cái trả {"ok":false,"description":"Not Found","error_code":404}. Không tồn tại sendDocument / sendFile / sendVideo / sendAudio / editMessageText / deleteMessage / setMessageReaction / forwardMessage / getChat / getChatMember.

Những công cụ đó bị gỡ khỏi schema gửi cho model (model không biết chúng tồn tại, không tốn token mô tả, không thể bị prompt injection dụ gọi) và persona được ghép thêm một luật nói rõ đây là giới hạn nền tảng chứ agent không hỏng - ai nhờ thì agent trả lời thẳng là tài khoản bot không gửi được, mời nhắn qua tài khoản cá nhân. Ẩn công cụ mà không nói lý do thì người nhắn tưởng agent bị lỗi.

> Trước đây danh sách này có 8 công cụ - schedule_task nằm trong đó. Nó là mục duy nhất > không dẫn được một số đo 404 nào: Bot API gửi chủ động tốt (đo: 10 tin trong 416ms), chỉ là > bộ hẹn lịch khóa cứng vào zca-js nên tài khoản bot không có đường gửi. Đã nối ở V3.19.

Agent làm được gì

15 công cụ, bật/tắt từng cái theo account ngay trên dashboard.

| Công cụ | Làm gì | Kênh Bot | |---|---|---| | web_search | Tìm web theo chuỗi nguồn (Brave -> DuckDuckGo). DuckDuckGo không cần key | có | | web_fetch | Đọc 1 URL công khai. Chặn IP nội bộ và metadata cloud (chống SSRF) | có | | kb_search | Tra tài liệu chủ agent tự nạp (chính sách, bảng giá, hướng dẫn) - FTS5 + bm25, hợp nhất bằng RRF | có | | save_memory | Ghi nhớ lâu dài về người dùng, sống qua nhiều phiên chat | có | | get_datetime | Ngày giờ chính xác theo múi giờ cấu hình | có | | read_image | Nhìn kỹ lại ảnh với câu hỏi cụ thể: đếm số lượng, đọc chữ nhỏ, soi chi tiết | có | | create_image | Vẽ ảnh AI mới, hoặc SỬA ảnh người dùng vừa gửi - phần còn lại giữ nguyên từng pixel | không | | create_word_document | Soạn .docx (tiêu đề, đoạn văn, bảng, hai cột) rồi gửi thẳng trong chat | không | | create_excel_file | Soạn .xlsx nhiều sheet, có công thức kèm sẵn kết quả nên xem trước trên điện thoại vẫn thấy số | không | | send_file | Gửi file từ kho data/shared-files/ hoặc tải từ URL công khai | không | | schedule_task | Đặt/xem/sửa/hủy lịch để agent tự nhắn lại đúng cuộc trò chuyện này | có | | tag_member | @mention đúng người trong nhóm | không | | get_group_info | Tên nhóm, số thành viên, danh sách thành viên | không | | add_reaction | Thả cảm xúc vào tin nhắn | không | | tai_video | Tải video TikTok/Facebook bản không watermark rồi gửi thẳng vào chat | không |

Bộ công cụ thật của một lượt là phần giao giữa hai danh sách tắt: agent khai năng lực ("vai này biết làm gì"), account áp chính sách ("nick này được phép làm gì"). Không bên nào bật ngược lại được bên kia, nên thêm một agent mới không bao giờ nới rộng quyền của một nick.

Lượt chạy theo lịch còn hẹp hơn nữa: 10 công cụ bị loại khỏi lượt đó, vì lượt theo lịch chạy cô lập khỏi lịch sử chat và 6 trong số đó gửi thẳng ra Zalo, né mất trần "số tin chủ động mỗi ngày".

Tin nhắn có định dạng thật

Trên kênh cá nhân, agent không trả về một khối chữ phẳng. Markdown của model được dịch thành định dạng gốc của Zalo (textProperties), không phải bị xóa đi:

  • In đậm, in nghiêng, ~~gạch ngang~~, gạch chân, tiêu đề cỡ lớn
  • Bốn màu chữ (đỏ, cam, vàng, xanh lá) cho thư mời và thông báo trang trọng
  • Emoji dẫn dòng chọn theo đúng nghĩa của dòng

Toàn bộ đã đo trên máy thật, cả Zalo Web lẫn Zalo điện thoại - hai client render khác nhau ở vài chỗ, và những chỗ đó đã bị loại khỏi thiết kế. Zalo còn từ chối cả tin khi chữ cộng định dạng vượt một ngưỡng byte, nên bộ gửi tự co trần ký tự cho vừa ngân sách rồi mới cắt.

Kênh Bot gửi chữ trơn - không phải vì sợ lỗi, mà vì chữ tới đường gửi đã hết markdown rồi (lớp dịch đã bóc dấu ra thành Style[] ở tầng trên), nên xin server dựng lại chỉ có thể bớt ký tự.

Kho tri thức (RAG)

Nạp tài liệu để agent tra cứu bằng công cụ kb_search - chính sách công ty, bảng giá, hướng dẫn nội bộ, FAQ.

  • Định dạng: .docx, .xlsx, .pdf, .txt, .md hoặc gõ tay thẳng trên dashboard
  • Tìm bằng SQLite FTS5 + bm25, hợp nhất nhiều truy vấn bằng RRF (chừa sẵn chỗ cho lớp vector sau)
  • Nội dung nạp bằng công cụ, KHÔNG nhét sẵn vào prompt - giữ nguyên khoản đầu tư prompt cache

của những lượt không đụng tới kho

  • Mỗi agent chỉ đọc được nguồn đã gán tường minh cho nó. Mặc định không nguồn nào
  • Kiểm chữ ký thật của file (magic bytes) cho docx/xlsx/pdf, không tin đuôi tên
  • Đọc file + cắt đoạn chạy trong worker thread riêng, có hai cầu dao: tài liệu quay CPU vô hạn

bị terminate() cắt, tài liệu phình heap bị chặn bằng trần RAM đặt trên dashboard

  • Đọc docx/xlsx bằng SAX theo luồng, không phải regex bắt cặp thẻ: đo được cặp regex cũ khóa

cứng event loop 38,09 giây trên một bom XML 1,7 KB nén (ReDoS bậc hai). Số đó nằm trong test hồi quy

MCP client (cắm server ngoài)

Bot làm MCP client: cắm các server MCP bên ngoài (chỉ transport HTTP, không stdio - VPS hạn chế chạy lệnh tùy ý) để agent tự khám phá và gọi tool của chúng, xếp chồng lên 15 công cụ built-in.

  • Gán theo từng agent, mặc định TẮT (default-deny): phải gán server cho agent cụ thể trên

dashboard, agent chưa gán không thấy tool ngoài nào - người lạ chat với agent chưa cấu hình không chạm được tool ngoài

  • Kết quả tool ngoài bọc như nội dung không tin cậy, cùng hàng rào với web_fetch; nhánh hỏng

không ném lỗi ra ngoài

  • Header xác thực (token, API key server MCP) mã hóa AES-256-GCM như mọi secret khác trong dự án
  • Fingerprint drift: chụp "dấu vân tay" bộ tool lúc người vận hành duyệt - server đổi tool

ngầm sau đó thì rơi về trạng thái "chờ duyệt lại", không nạp tool cho tới khi duyệt lại

  • Mọi tool ngoài xếp nhóm action (không tin annotation server tự khai) và bị loại khỏi lượt chạy

theo lịch

  • MCP_ENABLED là kill-switch runtime - tắt trên dashboard là chặn ngay, không cần xóa từng gán

Quản lý ở tab MCP trên dashboard. Sơ đồ kiến trúc đầy đủ: [docs/mcp-client-architecture.html](docs/mcp-client-architecture.html).

Lịch hẹn (agent tự nhắn)

Ba loại lịch: once, every, cron. Đặt bằng lời ngay trong chat hoặc trên dashboard.

  • Loại message: gửi nguyên văn, 0 token
  • Loại agent: chạy một lượt AI riêng, cô lập khỏi lịch sử chat (tra cứu rồi báo cáo)
  • Hai lớp chống spam: chặn lịch lặp quá dày lúc tạo, và trần số tin chủ động mỗi ngày
  • Lịch trễ vẫn GỬI kèm nhãn "(nhắc trễ, lịch gốc HH:MM)" thay vì im lặng nuốt
  • Không nhận chuỗi ngày giờ dạng tự do - chỉ {date, time} rời hoặc {inMinutes}, vì chuỗi naive

qua new Date() bị hiểu theo giờ hệ điều hành. Mọi quy đổi múi giờ đi qua một đường duy nhất

Trí nhớ

  • Lịch sử hội thoại trong SQLite, theo account + thread
  • Rolling summary: phần rơi khỏi cửa sổ replay được tóm tắt lại chứ không mất
  • Ngân sách token thật cho ngữ cảnh (đặt riêng được cho từng agent), không chỉ đếm số tin -

vượt ngân sách thì bỏ ảnh cũ trước, rồi mới bỏ tin cũ

  • Fact bền qua save_memory, có luật riêng tư bất đối xứng giữa chat riêng và nhóm
  • Ảnh nhận được lưu lại, mô tả bằng model vision phụ và cache lại để lượt sau khỏi trả tiền lần nữa

Dashboard

Hono + React + Tailwind, phục vụ ngay từ chính tiến trình agent tại http://127.0.0.1:3900.

| Trang | Dùng để | |---|---| | Tổng quan | Token vào/ra theo ngày, gộp mọi account | | Accounts | Thêm tài khoản Zalo, chọn loại kênh (cá nhân / bot chính thức), quét QR login ngay trên web hoặc dán Bot Token, bật/tắt từng account | | Agents | Mỗi account một "não": persona riêng, model riêng, bộ công cụ riêng, nguồn tri thức riêng | | Sessions | Đọc lại từng cuộc trò chuyện, xem tóm tắt agent tự dựng, bật/tắt agent theo thread, xóa sạch ngữ cảnh một cuộc trò chuyện | | Contacts | Danh bạ đã gặp | | Memory | Xem, sửa, xóa từng điều agent đã nhớ | | Kho tri thức | Nạp tài liệu (upload hoặc gõ tay), xem đoạn đã cắt, gán nguồn cho từng agent để kb_search tra | | Lịch hẹn | Danh sách lịch, chạy thử ngay, lịch sử từng lần chạy | | Tools | Bật/tắt 15 công cụ theo account, cấu hình vẽ ảnh và model vision. Chọn một account bot thì công cụ nền tảng không hỗ trợ hiện rõ lý do | | MCP | Thêm/sửa/xóa MCP server ngoài (chỉ HTTP), gán server cho từng agent (mặc định tắt), duyệt lại khi bộ tool đổi (drift) | | Cấu hình | 70 tham số vận hành chỉnh nóng, không cần khởi động lại, chia 13 nhóm | | Trace | Xem lại từng bước của một lượt agent: model nghĩ gì, gọi tool nào, tham số ra sao | | Logs | Nhật ký hệ thống |

13 nhóm cấu hình: Nhà cung cấp LLM, Chung, Lượt trả lời (9), Ngữ cảnh & Trí nhớ (6), Tra cứu web (2), Tạo file Word/Excel (5), Tải video (6), Vẽ ảnh (4), Gửi tin trên Zalo (11), Trace và dọn dẹp (4), Lịch hẹn (9), Kho tri thức (9), MCP server ngoài (4).

Thứ tự ưu tiên cấu hình ở mọi nơi: dashboard (DB) > .env > mặc định trong schema. Thiếu cấu hình LLM không chặn boot - phải vào được dashboard mới nhập được.

Vì sao đáng tin

Đây là phần khó thấy từ ảnh chụp màn hình, nhưng là phần chiếm nhiều công nhất.

Chịu được lỗi thật của môi trường thật

  • Mọi lời gọi LLM đi qua streaming. Router nằm sau Cloudflare, mà Cloudflare cắt bằng 524 nếu

origin chưa trả byte đầu trong 100 giây. Đo trên router thật với prompt sinh 4000 chữ: non-stream chết ở giây 125, streaming xong ở giây 135 với byte đầu ở giây 7,5

  • Gộp tin theo thread: người ta nhắn ngắt quãng ba tin thì agent trả lời một lần, không đẻ ra

ba lượt làm lại từ đầu

  • Chèn tin giữa lượt: nhắn thêm trong lúc agent đang chạy thì tin đó được kéo vào ngay ở ranh

giới bước, không phải đợi lượt sau

  • Câu trả lời bị Zalo từ chối vì định dạng thì gửi lại dạng chữ trơn - mất định dạng chứ

không mất nội dung

  • Chống lặp vòng tool ba tầng, trần thời gian mỗi lượt, trần token đầu ra
  • Phân loại lỗi nhà cung cấp thay vì thử lại mù: hết quota tôn trọng Retry-After thật, tràn ngữ

cảnh cắt sâu hơn rồi thử lại, sai khóa thì KHÔNG thử lại và báo câu riêng

Phòng prompt injection nghiêm túc (agent đọc tin của người lạ)

  • Nội dung web bọc trong thẻ `` có nonce ngẫu nhiên sinh mỗi lần gọi, persona

dạy rõ đó là dữ liệu chứ không phải lệnh. Kẻ tấn công soạn nội dung trước khi biết nonce nên không thể viết ra thẻ đóng giả

  • web_fetch và send_file chặn loopback, mạng nội bộ, endpoint metadata của cloud
  • Không có tool chuyển tiền hay thanh toán - cố ý không làm, dù thư viện có sẵn
  • Tool tạo file chỉ nhận dữ liệu (tiêu đề, đoạn văn, bảng), tuyệt đối không chạy code model sinh ra
  • Câu trả lời rò system prompt bị chặn hẳn trước khi ra Zalo
  • Mọi biểu thức chính quy chạm nội dung ngoài đều tuyến tính (chống ReDoS)

Bảo mật tại chỗ

  • Cookie Zalo và Bot Token mã hóa AES-256-GCM, khóa nằm ngoài DB
  • Bot Token nằm trong ĐƯỜNG DẪN của Zalo Bot API (/bot{token}/{method}), nên client che token

trong mọi chuỗi sắp vào thông điệp lỗi - ba lớp che, vì đã dựng lại được đường token đi từ trang lỗi của cổng trung gian vào dashboard và vào file log

  • Mật khẩu dashboard băm bằng scrypt, có rate-limit đăng nhập
  • Toàn bộ dữ liệu nằm trên máy bạn: SQLite trong data/, không gửi đi đâu ngoài nhà cung cấp LLM bạn chọn

Cài đặt

corepack enable
pnpm install
copy .env.example .env

.env chỉ có 2 dòng phải điền:

| Biến | Lấy ở đâu | |---|---| | CREDENTIALS_ENCRYPTION_KEY | node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" | | DASHBOARD_PASSWORD | tự đặt, tối thiểu 8 ký tự |

Mọi thứ còn lại nhập trên dashboard: nhà cung cấp LLM + model + API key (Cấu hình > Nhà cung cấp LLM, làm trước tiên), rồi tài khoản Zalo (trang Accounts - quét QR cho tài khoản cá nhân, hoặc dán Bot Token cho tài khoản bot). Không cần file config/accounts.json - DB là nguồn sự thật.

Chạy

pnpm dev                    # agent (watch mode) + dashboard
pnpm build:web              # build UI -> web/dist, tiến trình tự serve tại http://127.0.0.1:3900
pnpm dev:web                # dev UI dashboard (Vite, proxy vào API)
pnpm zalo-login acc-chinh   # login QR bằng CLI (cách cũ - trên web tiện hơn; chỉ dùng cho tài khoản CÁ NHÂN)
pnpm zalo-bot-check         # dò Zalo Bot API bằng token thật, in ra method nào sống method nào 404
pnpm test                   # 2657 test
pnpm typecheck              # bắt buộc chạy trước khi báo hoàn thành
pnpm eval                   # 17 case chạy MODEL THẬT, không tin nào ra Zalo thật

Nhà cung cấp LLM

Cắm rời qua LLM_PROVIDER, đổi được lúc chạy từ dashboard:

  • openai-compatible - bất kỳ endpoint nào theo chuẩn OpenAI (router proxy, OpenRouter, LM Studio, Ollama...)
  • anthropic - gọi thẳng API gốc của Anthropic
  • google - gọi thẳng API gốc của Google (Gemini). Phải đi đường này chứ không

qua lớp giả OpenAI của họ: lớp giả làm rơi thought_signature nên mọi lượt có gọi công cụ sẽ lỗi

Vẽ ảnh và model vision phụ cấu hình riêng, cũng theo chuẩn OpenAI-compatible.

An toàn - đọc trước khi chạy

> [!WARNING] > zca-js là API không chính thức. Zalo có thể khóa tài khoản. > Chỉ dùng nick phụ. Đừng dùng tài khoản chính hay tài khoản có giá trị. > Rủi ro này không áp cho tài khoản Zalo Bot chính thức - đó là API công khai của Zalo.

  • data/ chứa cookie Zalo và Bot Token (đã mã hóa) cùng toàn bộ lịch sử - không commit, không chia sẻ
  • Mỗi tài

…

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.