mcp-cha-cha
# 侘茶點餐系統 MCP Server
以台南侘茶飲料店真實菜單為基礎的教學用 MCP Server,透過 stdio 傳輸與 LLM Client(如 Claude Desktop)溝通,完整涵蓋 MCP 三大核心概念:**Tools**、**Resources**、**Prompts**,並以 `get_menu` Tool 示範 MCP Apps 的互動式 UI 擴充。
## 特色
- **86 款飲品、11 大分類、8 種加料**,資料庫首次啟動自動 seed
- 6 個 Tools、5 個 Resources、2 個 Prompts,一站式體驗 MCP 全功能
- `get_menu` 內建互動式菜單 UI(MCP Apps),在支援的 Host 中會直接渲染 iframe
- SQLite(WAL 模式)本機持久化,免額外部署資料庫
## 技術棧
- TypeScript(ESM,`NodeNext` module resolution)
- [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk) v1.x — MCP Server SDK
- [`@modelcontextprotocol/ext-apps`](https://www.npmjs.com/package/@modelcontextprotocol/ext-apps) — MCP Apps 擴充(互動式 UI)
- `better-sqlite3` — SQLite 嵌入式資料庫
- `zod` v4 — Tool 參數 schema 驗證
- `vite` + `vite-plugin-singlefile` — UI 打包為單一 HTML
- `vitest` + `@vitest/coverage-v8` — 測試與覆蓋率
- `pnpm` 套件管理
## 環境需求
- Node.js 22(見 `.node-version`)
- pnpm
## 快速開始
```bash
# 安裝依賴
pnpm install
# 開發模式(tsx 直接執行,會自動建立並 seed data/cha-cha.db)
pnpm run dev
# 打包(先打包 UI 再編譯 TypeScript)
pnpm run build
# 執行編譯後的版本
pnpm run start
```
首次執行 `pnpm run dev` 或 `pnpm run start` 時,會自動在專案根目錄建立 `data/cha-cha.db` 並寫入完整菜單資料,無需手動初始化。
## 常用指令
| 指令 | 說明 |
| --- | --- |
| `pnpm install` | 安裝依賴 |
| `pnpm run build` | 先打包 UI(Vite)再 `tsc` 編譯到 `dist/` |
| `pnpm run build:ui` | 僅打包 UI(`ui/` → `dist/ui/menu-app.html`) |
| `pnpm run dev` | `tsx` 直接執行 `src/index.ts`(開發用) |
| `pnpm run start` | 執行編譯後的 `dist/index.js` |
| `pnpm test` | `vitest run`(執行全部測試) |
| `pnpm vitest run tests/get-orders.test.ts` | 執行單一測試檔 |
| `pnpm vitest run -t "篩選"` | 依測試名稱片段過濾 |
| `pnpm vitest run --coverage` | 產生覆蓋率報告 |
## 接入 Client
- **Claude Desktop**:見 [`docs/claude-desktop-guide.md`](docs/claude-desktop-guide.md)
- **MCP Inspector**(除錯用):見 [`docs/inspector-guide.md`](docs/inspector-guide.md)
```bash
# 快速用 Inspector 測試
pnpm build
npx @modelcontextprotocol/inspector node dist/index.js
```
## 架構
進入點 `src/index.ts` 建立 `McpServer` 後,分別呼叫三個 register 函式注入功能:
```
src/
├── index.ts 進入點:建立 McpServer、註冊 Tools/Resources/Prompts、連接 stdio
├── db.ts SQLite 初始化、菜單 seed、共用查詢 helper
├── types.ts 共用型別(MenuItem、Topping、Order)與常數(甜度、冰量選項)
├── helpers.ts 菜單格式化函式
├── tools/ 6 個 Tool:查詢與操作
├── resources/ 5 個 Resource:Client 端可主動讀取的資料
└── prompts/ 2 個 Prompt:預定義提示模板
```
資料庫檔案存放於 `data/cha-cha.db`(不納入版控)。
### MCP Apps UI
`get_menu` Tool 使用 `registerAppTool` 加掛互動式菜單 UI,支援 MCP Apps 的 Host(如 Claude Desktop)會自動渲染 iframe。UI 原始碼在 `ui/`,透過 Vite 打包為 `dist/ui/menu-app.html` 單一檔案。
## 提供的功能
### Tools
| Tool | 說明 |
| --- | --- |
| `get_menu` | 查詢菜單(分類、飲品、加料、甜度冰量選項),支援 MCP Apps 的 Host 會渲染互動式菜單 UI |
| `get_orders` | 查詢訂單,可依 ID 精確查找,或依訂購人、領取狀態、日期篩選 |
| `create_order` | 建立訂單 |
| `pickup_order` | 標記訂單為已領取 |
| `cancel_order` | 取消尚未領取的訂單 |
| `recommend_drinks` | 依心情、咖啡因、預算、杯數推薦飲品 |
### Resources
| Resource | URI | 說明 |
| --- | --- | --- |
| `menu-categories` | `cha-cha://menu/categories` | 所有菜單分類列表 |
| `menu-category`(template) | `cha-cha://menu/category/{category}` | 指定分類的飲品清單(含價格與屬性) |
| `orders-list` | `cha-cha://orders/list` | 所有訂單列表 |
| `order-detail`(template) | `cha-cha://orders/{id}` | 單筆訂單詳情 |
| `orders-unpicked` | `cha-cha://orders/unpicked` | 未領取訂單清單 |
### Prompts
| Prompt | 參數 | 說明 |
| --- | --- | --- |
| `recommend` | `mood`(可選) | 帶入完整菜單,推薦 3 杯飲品並說明理由 |
| `order_summary` | 無 | 彙整目前所有訂單:每人明細、飲品統計、總金額、未領取提醒 |
## 業務規則
- `sugar_fixed = 1` 的飲品忽略使用者甜度參數,強制設為「固定甜度」
- 單杯總價 = 飲品價格 + Σ(加料價格);加料有免費項目(小珍珠、波霸、混珠,price = 0)
- 顧客常用口語簡稱點餐(如「波霸奶綠」其實是「茉香奶綠」加「波霸」加料),呼叫 `create_order` 前建議先用 `get_menu` 確認正確品名
- Tool 錯誤統一回傳 `{ content: [{ type: 'text', text }], isError: true }`
## 測試
測試檔案放在 `tests/` 目錄,使用 vitest。Tool handler 邏輯抽為獨立可匯出函式(如 `handleGetOrders`),與 `registerXxx` 註冊函式分離,方便直接測試 handler 而不需啟動 MCP Server。
覆蓋率設定於 `vitest.config.ts`,目前 `coverage.include` 限定在 `src/tools/get-orders.ts`,新增其他模組測試時需同步調整。
```bash
pnpm test
```
## 規格文件
- [`spec/spec.md`](spec/spec.md) — 完整技術規格書(SSOT:資料庫 schema、MCP 功能設計、菜單資料)
- [`spec/change/`](spec/change/) — 變更請求(CR-001 ~ CR-004)及對應任務清單
## 授權
ISC
TDQS
Scored across 6 tools
Each tool targets a distinct action: menu browsing, recommendations, order creation, order query, pickup, and cancellation. There is no meaningful overlap; get_menu and recommend_drinks serve different selection purposes.
Most tool names follow a clear lower_snake_case verb_noun pattern (create_order, get_menu, cancel_order). pickup_order is a slight deviation since 'pickup' is used as a verb-like noun, but it remains readable and consistent in style.
Six tools is well-scoped for a focused beverage-ordering server. Each tool covers a necessary part of the workflow without redundancy.
The core ordering lifecycle is covered: menu lookup, recommendation, create, query, cancel, and pickup. A minor gap is the lack of an order update/modify tool for changing items before pickup.