npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sapo-storybook-mcp

v1.0.1

Published

MCP server đọc Storybook (bất kỳ) để xem thiết kế UI và hỗ trợ viết Playwright automation test

Readme

sapo-storybook-mcp

MCP server đọc Storybook (bất kỳ static build nào) để một AI agent (Codex / Kiro / Claude / Gemini) có thể:

  • Xem danh sách màn hình / component đã thiết kế trong Storybook.
  • Xem giao diện thực tế của từng story (ARIA snapshot + screenshot).
  • Trích selectorscaffold Playwright automation test trực tiếp từ DOM story đã render.

Trỏ tới Storybook nào là do bạn cấu hình qua biến môi trường STORYBOOK_BASE_URL (bắt buộc).

Yêu cầu

  • Node.js >= 18 (đã test trên Node 22).
  • Kết nối mạng tới host Storybook của bạn (giá trị STORYBOOK_BASE_URL).
  • Playwright Chromium (tự cài qua postinstall).

Cấu hình (biến môi trường)

| Biến | Bắt buộc | Ý nghĩa | |------|:---:|-----------| | STORYBOOK_BASE_URL | ✓ | Thư mục chứa index.html, iframe.html, index.json của Storybook (không cần dấu / cuối). Thiếu biến này server sẽ báo lỗi và không chạy. | | STORYBOOK_SCREENSHOT_DIR | ✗ | Nơi lưu file PNG chụp story (mặc định ./screenshots). |

Các tool

| Tool | Cần browser? | Chức năng | |------|:---:|-----------| | storybook_list_stories | ✗ | Liệt kê story từ index.json, lọc theo title/name, có phân trang. | | storybook_search_stories | ✗ | Tìm story fuzzy theo title/name/id. | | storybook_get_story_tree | ✗ | Dựng lại cây sidebar (Category → Page → các variant/màn) từ title. Xem một folder có những page nào, mỗi page có những màn nào (Đang tải, Mặc định, Biến thể, Báo lỗi, Toast...). | | storybook_get_story_url | ✗ | Trả về URL iframe (dùng cho page.goto) và URL manager (UI đầy đủ). | | storybook_get_story_snapshot | ✓ | Render story → ARIA snapshot (YAML). Hiểu bố cục + viết getByRole. | | storybook_get_story_selectors | ✓ | Render story → danh mục buttons/links/inputs/checkboxes/comboboxes/cột bảng kèm Playwright locator gợi ý. | | storybook_detect_components | ✓ | Render story → phát hiện component thiết kế màn hình đang dùng (TextField, Checkbox, IndexTable/DataGrid, SegmentedControl, AppFrame...) qua dấu vết DOM, kèm đối chiếu catalog Components/Pattern. | | storybook_get_story_screenshot | ✓ | Render story → ảnh PNG trả inline để model phân tích. Mặc định không ghi file; chỉ lưu khi truyền save: true hoặc save_path. | | storybook_generate_playwright_test | ✓ | Render + phân tích DOM → sinh sẵn file spec @playwright/test. | | storybook_open_session | ✓ (headed) | Mở cửa sổ browser hiện hình tại 1 story, giữ phiên để người dùng thao tác tay. | | storybook_read_current_state | ✓ (headed) | Đọc trạng thái live hiện tại sau khi người dùng thao tác (snapshot / selectors / screenshot). Gọi lặp lại nhiều lần. | | storybook_close_session | ✓ (headed) | Đóng cửa sổ session. |

Luồng human-in-the-loop (cho nghiệp vụ mà layout đổi theo tương tác, vd chọn "Lý do thanh toán" → hiện field khác): open_session → bạn tự thao tác trong cửa sổ → read_current_state (lặp lại sau mỗi bước) → close_session. Các tool này dùng browser headed (hiện hình), khác với các tool còn lại chạy headless ngầm.

Tất cả tool đều readOnly (không sửa gì ngoài việc lưu file screenshot).

Quy trình dùng điển hình

  1. storybook_search_stories (hoặc list) để tìm story_id.
  2. storybook_get_story_screenshot / storybook_get_story_snapshot để xem thiết kế.
  3. storybook_get_story_selectors để lấy locator ổn định.
  4. storybook_generate_playwright_test để sinh khung test, rồi hoàn thiện các TODO.

Chi tiết từng tool

Ký hiệu: 🟢 không cần browser (đọc index.json) · 🔵 render headless ngầm · 🟠 headed (hiện cửa sổ).

🟢 storybook_list_stories

Liệt kê story từ index.json.

  • Input: filter? (chuỗi con của title/name, vd "Phiếu thu"), limit? (1–500, mặc định 100), offset? (phân trang), response_format? (markdown|json).
  • Output: danh sách story gom theo title, mỗi story có name + id. JSON kèm total/has_more/next_offset.
  • Khi nào dùng: cần liệt kê nhanh/lọc phẳng theo từ khoá. Muốn thấy cây phân cấp thì dùng get_story_tree.

🟢 storybook_search_stories

Tìm story kiểu fuzzy, xếp hạng theo mức khớp trên title + name + id.

  • Input: query (nhiều từ được tách và cộng điểm), limit? (1–100, mặc định 20), response_format?.
  • Output: danh sách story xếp theo độ liên quan, kèm id.
  • Khi nào dùng: chỉ nhớ mang máng tên màn (vd "đang tải loading", "permission").

🟢 storybook_get_story_tree

Dựng lại cây sidebar (Category → … → Page → các variant/màn) từ trường title.

  • Input: path? (chuỗi con của title để giới hạn nhánh, vd "Tiền mặt/Phiếu thu", "Tạo mới"), include_variants? (mặc định true; false = chỉ xem folder), response_format?.
  • Output: cây thụt lề — folder (📁) kèm số story; page (📄) liệt kê từng variant + id.
  • Khi nào dùng: muốn biết một folder có những page nào, mỗi page có bao nhiêu màn/trạng thái (Đang tải, Mặc định, Biến thể, Báo lỗi, Toast...). Đây là tool khám phá cấu trúc chính.

🟢 storybook_get_story_url

Đổi story_id → URL.

  • Input: story_id, response_format?.
  • Output: iframe_url (dùng cho page.goto trong Playwright — render trần, không có chrome Storybook) và manager_url (mở UI Storybook đầy đủ cho người xem).
  • Khi nào dùng: cần URL để nhúng vào test hoặc mở tay trên trình duyệt.

🔵 storybook_get_story_snapshot

Render story ngầm → trả ARIA snapshot (YAML).

  • Input: story_id, viewport? (mobile|tablet|desktop|wide).
  • Output: cây accessibility (roles, tên, heading, bảng, nút, input) đúng như render; kèm cảnh báo nếu story lỗi render.
  • Khi nào dùng: hiểu bố cục màn hình và viết locator theo getByRole/getByText. Rẻ token, là nguồn phân tích chính (thường không cần chụp ảnh).

🔵 storybook_get_story_selectors

Render story ngầm → danh mục element tương tác kèm Playwright locator gợi ý.

  • Input: story_id, viewport?, response_format?.
  • Output: buttons/links/inputs/checkboxes/comboboxes + cột bảng (header + id) + số dòng + breakpoint phát hiện được. Ưu tiên locator theo role/placeholder, fallback theo id cột ổn định (vd total_amount, posted_date).
  • Khi nào dùng: cần locator sẵn để dán vào test.

🔵 storybook_detect_components

Render story ngầm → phát hiện component thiết kế mà màn hình đang dùng.

  • Input: story_id, viewport?, response_format?.
  • Output: danh sách component (TextField, Checkbox, Select, RadioButton, IndexTable/DataGrid, SegmentedControl, AppFrame, Link, Portal...) kèm bằng chứng (id UI*/AppFrame*, data-*) và số lần xuất hiện; kèm catalog Components/Pattern từ Storybook và raw signals.
  • Khi nào dùng: hiểu màn hình được ghép từ component nào để tái sử dụng khi build màn tương tự, hoặc audit.
  • Lưu ý: heuristic dựa trên DOM đã render, không phải import graph từ source.

🔵 storybook_get_story_screenshot

Render story ngầm → ảnh PNG.

  • Input: story_id, viewport?, full_page? (mặc định true), save? (mặc định false), save_path? (truyền vào ⇒ tự bật save).
  • Output: ảnh inline để model xem; mặc định không ghi đĩa — chỉ lưu khi save:true/save_path.
  • Khi nào dùng: chỉ khi cần nhìn giao diện (bố cục, màu, style). Phân tích cấu trúc/viết test thì dùng snapshot/selectors sẽ rẻ hơn.

🔵 storybook_generate_playwright_test

Render + phân tích DOM → sinh sẵn file spec @playwright/test.

  • Input: story_id, viewport?, test_title?.
  • Output: code TypeScript: page.goto(iframe_url) + assertion theo heading/button/input/cột bảng thực tế + stub tương tác (click, search) kèm TODO.
  • Khi nào dùng: khởi tạo nhanh test cho một màn; sau đó tự hoàn thiện các TODO.

🟠 storybook_open_session (headed)

Mở cửa sổ browser hiện hình tại một story và giữ phiên.

  • Input: story_id, viewport?.
  • Output: xác nhận đã mở. Cửa sổ hiện trên máy chạy MCP; giữ nguyên tới khi close_session.
  • Khi nào dùng: bắt đầu luồng human-in-the-loop. Chỉ 1 phiên tại một thời điểm; gọi lại sẽ điều hướng lại cùng cửa sổ. Cần máy có màn hình.

🟠 storybook_read_current_state (headed)

Đọc trạng thái live hiện tại của cửa sổ session (sau khi người dùng vừa thao tác).

  • Input: mode? (snapshot mặc định | selectors | screenshot), full_page? (cho screenshot), response_format? (cho selectors).
  • Output: ARIA snapshot / danh mục locator / ảnh PNG của màn hình hiện tại. Gọi lặp lại nhiều lần sau mỗi bước.
  • Khi nào dùng: sau khi tự chọn "Lý do thanh toán", mở modal, điền form... để AI đọc layout mới. Yêu cầu đã open_session.

🟠 storybook_close_session (headed)

Đóng cửa sổ session.

  • Input: không có.
  • Output: xác nhận. Gọi được cả khi chưa mở phiên.

Thêm MCP vào AI client

Server chạy qua stdio, phân phối trên npm với tên sapo-storybook-mcp. Cách chạy chuẩn:

npx -y sapo-storybook-mcp@latest

với biến môi trường STORYBOOK_BASE_URL trỏ tới Storybook của bạn. Lần chạy đầu npx tải package + Chromium (~260MB) nên hơi lâu; các lần sau dùng cache.

Chạy bản local (khi phát triển): git clone repo → npm install && npm run build → dùng command: "node", args: ["/duong-dan-tuyet-doi/dist/index.js"] thay cho npx.

Trong tất cả ví dụ dưới, thay https://your-storybook-host/path/to/storybook bằng URL Storybook thật.

Codex CLI

Sửa ~/.codex/config.toml, thêm:

[mcp_servers.storybook]
command = "npx"
args = ["-y", "sapo-storybook-mcp@latest"]
env = { STORYBOOK_BASE_URL = "https://your-storybook-host/path/to/storybook" }

Kiểm tra: codex mcp list. Restart phiên Codex sau khi thêm.

Kiro CLI

Bằng lệnh:

kiro-cli mcp add --name storybook --command npx \
  --args -y --args sapo-storybook-mcp@latest \
  --env STORYBOOK_BASE_URL=https://your-storybook-host/path/to/storybook \
  --scope global --force

Cờ: --scope global (~/.kiro/settings/mcp.json) hoặc workspace (.kiro/settings/mcp.json); --agent <name> để gắn cho 1 agent; --force ghi đè nếu trùng.

Hoặc sửa tay ~/.kiro/settings/mcp.json:

{
  "mcpServers": {
    "storybook": {
      "command": "npx",
      "args": ["-y", "sapo-storybook-mcp@latest"],
      "env": {
        "STORYBOOK_BASE_URL": "https://your-storybook-host/path/to/storybook"
      },
      "timeout": 120000
    }
  }
}

Kiểm tra: kiro-cli mcp list, hoặc trong phiên chat gõ /mcp (trạng thái) / /tools. Thêm xong cần restart phiên Kiro.

Claude Code CLI

Dùng -- để ngăn cách flag của claude với lệnh chạy server.

claude mcp add storybook --scope user \
  --env STORYBOOK_BASE_URL=https://your-storybook-host/path/to/storybook \
  -- npx -y sapo-storybook-mcp@latest

Cờ: --scope = local (mặc định, chỉ project hiện tại) · user (mọi project) · project (ghi .mcp.json chia sẻ trong repo); --env/-e KEY=VALUE lặp lại cho nhiều biến; --transport mặc định stdio (đúng cho server này).

Kiểm tra: claude mcp list, claude mcp get storybook; gỡ: claude mcp remove storybook.

Claude Desktop

Sửa ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) rồi khởi động lại app:

{
  "mcpServers": {
    "storybook": {
      "command": "npx",
      "args": ["-y", "sapo-storybook-mcp@latest"],
      "env": {
        "STORYBOOK_BASE_URL": "https://your-storybook-host/path/to/storybook"
      }
    }
  }
}

Gemini CLI

Sửa ~/.gemini/settings.json, thêm:

{
  "mcpServers": {
    "storybook": {
      "command": "npx",
      "args": ["-y", "sapo-storybook-mcp@latest"],
      "env": {
        "STORYBOOK_BASE_URL": "https://your-storybook-host/path/to/storybook"
      }
    }
  }
}

Kiểm tra: trong phiên Gemini gõ /mcp để xem trạng thái + tool. Restart phiên sau khi thêm.

Smoke test

npm run build
STORYBOOK_BASE_URL=https://your-storybook-host/path/to/storybook node scripts/smoke.mjs

Script sẽ spawn server qua stdio, list tool và gọi thử list_stories, get_story_url, get_story_selectors, generate_playwright_test. In ra SMOKE TEST OK nếu thành công.

Cấu trúc dự án

src/
├── index.ts                 # entry: đăng ký server + tool + stdio transport
├── constants.ts             # base URL, viewport presets, limits
├── types.ts                 # kiểu dữ liệu
├── schemas/index.ts         # Zod input schemas
├── services/
│   ├── storybookClient.ts   # fetch index.json + build URL
│   ├── browser.ts           # quản lý Playwright Chromium (render story)
│   ├── domAnalyzer.ts       # ARIA snapshot + trích selector
│   └── format.ts            # helper định dạng response
└── tools/                   # 1 file / tool

Ghi chú kỹ thuật

  • Story id có ký tự tiếng Việt (unicode) — server tự encodeURIComponent khi dựng URL.
  • Story render trong iframe cô lập (iframe.html?id=...&viewMode=story) nên phù hợp để page.goto trong Playwright.
  • Nếu story không có data-testid, locator ưu tiên theo role/placeholder, fallback theo id ổn định.
  • Server chỉ log ra stderr (stdout dành cho giao thức MCP).