vn-skills
Teach your AI agent to work with VietQR, e-invoices, the new 34-province addresses and more — with one command.
Tiếng Việt · 5-minute quickstart
Coding agents (Claude Code, Codex, Cursor, …) get Vietnam-specific tasks wrong: they invent bank BINs, use the pre-2025 provinces and districts, misread amounts in words, or confuse the Chinese and Vietnamese lunar calendars. vn-skills fixes that with three layers built on one offline core:
What it is: an offline toolkit. No accounts or API keys; it builds, parses and validates VietQR payloads and images. What it is not: a payment gateway. It does not collect payments or confirm transfers, and never calls bank or NAPAS APIs; pair it with a payment gateway for that.
Skills
Bulk-convert stored addresses (one per line → NDJSON, or a CSV column; exit code 2 if some rows fail):
vn-skills address convert-file addresses.txt
vn-skills address convert-file customers.csv --csv --column address > converted.csv
vn-skills address convert-file customers.csv --csv --province-column province --district-column district --ward-column ward > converted.csv
Install the skills
Claude Code plugin (all skills + the MCP server, one command):
/plugin marketplace add beiryu/vn-skills
/plugin install vn-skills@vn-skills
Claude Code (project or user scope):
git clone https://github.com/beiryu/vn-skills
cp -r vn-skills/skills/vietqr ~/.claude/skills/ # or .claude/skills/ inside your project
Then ask: "tạo QR chuyển 500k vào VCB số tài khoản 0011001234567" → Claude runs the skill and returns qr.png.
Or use the CLI (skills are bundled in the package):
npx -y @vn-skills/cli install vietqr --agent claude # .claude/skills/vietqr (project)
npx -y @vn-skills/cli install all --agent cursor --global # ~/.cursor/skills/*
--agent is claude, cursor, codex, agents or copilot (.github/skills/, or ~/.copilot/skills/ with --global). Existing folders are not overwritten without --force; --dry-run prints
the actions only.
Cursor / Codex / other agents: copy the same folders into the agent's skills directory
(.cursor/skills/, .codex/skills/, or wherever your agent discovers SKILL.md). The skills only need Node.js 22+ because
they call npx -y @vn-skills/cli. .agents/skills/ is read by Codex (docs), Cursor (docs), Gemini CLI (docs) and GitHub Copilot in VS Code, Copilot CLI and the cloud agent (docs); install there with --agent agents. For the Copilot cloud agent, install in project scope (--agent agents without --global), because the cloud agent does not load personal skills.
Inside this repository run node packages/cli/dist/index.js … instead of npx -y @vn-skills/cli … to get clean JSON. pnpm vn-skills … also works but adds wrapper output (the echoed command and [ELIFECYCLE] on failures).
MCP server
claude mcp add vn-skills -- npx -y @vn-skills/mcp
Setup for other clients is in MCP client setup. Or in any MCP client config:
{ "mcpServers": { "vn-skills": { "command": "npx", "args": ["-y", "@vn-skills/mcp"] } } }
The server exposes 34 tools, grouped by skill. All tools are declared read-only and offline (readOnlyHint: true, openWorldHint: false).
MCP Apps hosts (Claude, ChatGPT, VS Code, …) show VietQR results (built with image: true) as an inline VietQR card with bank, account, amount and copy buttons; other clients see the usual JSON and image.
When a client declares the MCP elicitation capability, the address converter asks the user to pick the new ward if the old ward was split, and reports chosenBy (user or default).
Prompts
The server also offers prompt templates, shown as / commands in clients that support MCP prompts: tao-vietqr, doi-dia-chi-moi, kiem-tra-mst, doc-cccd, so-tien-bang-chu, ngay-lam-viec, doi-am-duong, kiem-tra-hoa-don.
Resources
Read-only data that clients can attach without a tool call (all application/json):
MCP client setup
Requires Node.js 22+. Each client has its own file and shape; check the linked docs for the exact location.
claude mcp add vn-skills -- npx -y @vn-skills/mcp
Claude Desktop — claude_desktop_config.json:
{ "mcpServers": { "vn-skills": { "command": "npx", "args": ["-y", "@vn-skills/mcp"] } } }
Cursor — .cursor/mcp.json (project) or ~/.cursor/mcp.json (global), same mcpServers shape:
{ "mcpServers": { "vn-skills": { "command": "npx", "args": ["-y", "@vn-skills/mcp"] } } }
VS Code — .vscode/mcp.json (top-level servers, not mcpServers):
{
"servers": {
"vn-skills": { "type": "stdio", "command": "npx", "args": ["-y", "@vn-skills/mcp"] }
}
}
Codex — ~/.codex/config.toml:
[mcp_servers.vn-skills]
command = "npx"
args = ["-y", "@vn-skills/mcp"]
Docker
Build the image from this repository (the server is offline and needs no env vars):
docker build -t vn-skills-mcp .
Then point your client at it (it runs docker run -i --rm vn-skills-mcp):
{
"mcpServers": {
"vn-skills": { "command": "docker", "args": ["run", "-i", "--rm", "vn-skills-mcp"] }
}
}
Other clients: use the generic mcpServers block above. AI agents (e.g. Cline) can follow llms-install.md.
HTTP mode
For a shared or remote server, run the opt-in Streamable HTTP transport (stateless, POST /mcp):
npx -y @vn-skills/mcp --http --port 3000 # http://127.0.0.1:3000/mcp
It binds to 127.0.0.1 by default; use --host 0.0.0.0 to expose it (e.g. docker run -p 3000:3000 vn-skills-mcp --http --host 0.0.0.0). Requests with a non-localhost Origin header get 403 unless you pass --allow-origin <origin> (repeatable). Without --http the server uses stdio.
Library
import {
buildVietQR,
convertAddress,
validateTaxId,
moneyToWords,
lunarInfo,
computeTotals,
} from '@vn-skills/core';
buildVietQR({ bank: 'VCB', account: '0011001234567', amount: 500000, note: 'don 123' }).payload;
convertAddress('12 Nguyễn Huệ, P. Bến Nghé, Q.1, TP.HCM').new.formatted; // "12 Nguyễn Huệ, Phường Sài Gòn, Thành phố Hồ Chí Minh"
validateTaxId('0100233488-001').kind; // "branch"
moneyToWords(1_200_000).words; // "một triệu hai trăm nghìn đồng"
lunarInfo(29, 1, 2025).text; // "Mùng 1 tháng Giêng năm Ất Tỵ"
Every function returns { ok: true, ... } or { ok: false, error: { code, message, hint } } — no exceptions for bad input.
Google Sheets
packages/sheets (private, not on npm) builds Apps Script custom functions from @vn-skills/core:
pnpm --filter ./packages/sheets build writes packages/sheets/dist/vn-skills.gs, vn-skills-lite.gs and appsscript.json.
- In a Google Sheet open Extensions → Apps Script and paste the contents of one
.gsfile. - Set the time zone to
Asia/Ho_Chi_Minh(Project Settings, or use thetimeZoneinappsscript.json). - Save and use the functions in cells. Each accepts one value or a range and returns the same shape; a bad cell returns the error text.
Bundle sizes (as measured by the build): vn-skills.gs ≈ 2520 KiB (includes the address data), vn-skills-lite.gs ≈ 39 KiB (no address functions). If the full bundle is too large for your project, use the lite bundle.
Development
pnpm install && pnpm build && pnpm test
pnpm build-data # refresh bundled datasets from pinned upstream commits (network)
Data sources, licenses and dates are listed in packages/core/data/SOURCES.md. See CONTRIBUTING.md.
Roadmap
Next up: a Python port and real e-invoice sandbox adapters. Full list with acceptance criteria: ROADMAP.md.
Community
Contributing · Governance · Code of Conduct · Security · Name & brand policy · Sponsor
Disclaimer
This project provides technical tooling only. It is not tax, legal or accounting advice, does not query or scrape any government system, and does not guarantee that a tax ID is registered or that an address is accepted by a carrier. Verify with the competent authority where it matters.
VietQR and NAPAS are trademarks of the National Payment Corporation of Vietnam (NAPAS); bank names belong to their owners. vn-skills is not affiliated with, endorsed by or certified by NAPAS, any bank or any Vietnamese authority.
License
MIT. Bundled data is derived from MIT-licensed community datasets (see SOURCES.md and their licences in THIRD_PARTY_NOTICES.md); the lunar calendar is an independent implementation of the formulas in Jean Meeus, Astronomical Algorithms.