Skip to main content
Glama
ai-cooperation

Business Card MCP

README.md
# Business Card MCP

AI-native、可自架的私人名片庫。使用者在 ChatGPT/Claude 上傳名片,由既有多模態模型辨識並確認;Remote MCP 負責驗證、私人儲存、搜尋、修改、封存與匯出,不額外呼叫模型 API。

## 功能

- ChatGPT Remote MCP:建立、搜尋、讀取、更新、封存及匯出名片
- 私人管理網站:Gmail OTP 登入、卡片牆/條列檢視、受保護縮圖
- D1 FTS5:姓名、公司、職稱、電話、Email、地址、標籤、場合及備註搜尋
- R2:私人 Markdown 與 480px WebP 縮圖
- KV:每位使用者獨立的 `bc_` Connector Key
- 寫入後回傳可點擊的名片確認頁
- 縮圖為建立名片的必填欄位,避免產生無圖資料

目前是關鍵字全文搜尋,不是 embedding/向量語意搜尋。

## 架構

```text
ChatGPT / Claude
       │ Remote MCP
       ▼
Browser ── Turnstile + Gmail OTP ──┐
                                   ▼
ChatGPT / Claude ── MCP Key ── Cloudflare Worker
                                   ├── D1:聯絡人、OTP challenge、web session 與 FTS5
                                   ├── R2:Markdown、WebP 縮圖
                                   ├── KV:MCP Key
                                   ├── Email Service binding:寄送一次性驗證碼
                                   └── Static Assets:私人管理網站
```

網頁登入不使用 Google OAuth,也不依賴 Cloudflare Zero Trust。Gmail 地址由部署者設定的 allowlist 控制,Turnstile 只負責防濫用,不是登入身分來源。原始名片圖片預設不保存。

圖片處理在 ChatGPT/Claude 端完成:多模態模型在呼叫 `create_contact` 前產生 480px WebP 縮圖;Worker 只驗證 MIME、大小與 SHA-256,然後把已壓縮的 WebP 存入 R2。這個專案不呼叫 Images API、Workers AI 或線上圖片壓縮服務。

GitHub repo 只包含程式碼、migration 與合成測試資料,不包含任何使用者聯絡人。

## MCP Tools

| Tool | 用途 |
|---|---|
| `create_contact` | 寫入使用者已確認的資料、Markdown 與必要縮圖 |
| `search_contacts` | 搜尋自己的名片 |
| `get_contact` | 取得完整名片與確認頁連結 |
| `update_contact` | 更新欄位、標籤與備註 |
| `archive_contact` | 封存名片,不永久刪除 |
| `export_contact` | 匯出 Markdown 或 vCard |

## 部署需求

- Node.js 20+
- Cloudflare 帳號
- Wrangler CLI 登入正確的 Cloudflare 帳號

## 部署

### 1. 安裝與建立本機設定

```bash
npm install
cp public/config.example.js public/config.js
```

`wrangler.jsonc` 隨 repo 提供**零值佔位版**(SmallGreen 標準需要可靜態判定的資源宣告),下一步把真實 ID 填進去;填完建議 `git update-index --skip-worktree wrangler.jsonc`,避免真實 ID 被 commit。`public/config.js` 已被 Git 忽略,網頁認證不需要前端設定。

### 2. 建立 Cloudflare 資源

```bash
npx wrangler d1 create business-card-mcp
npx wrangler r2 bucket create business-card-mcp-assets
npx wrangler kv namespace create CARD_KEYS
```

把 Cloudflare 回傳的 account、D1 與 KV ID 填入 `wrangler.jsonc`,並設定:

- `PUBLIC_BASE_URL`
- R2 bucket 名稱

接著在 [Cloudflare Email Service](https://developers.cloudflare.com/email-service/) 完成寄件網域設定。寄件地址必須屬於已在 Cloudflare DNS 管理並已 onboard 的網域;單人免費方案可把自己的 Gmail 設為 Cloudflare 的 verified destination。Email Sending 對任意收件者需要 Workers Paid,但寄送到帳號內 verified destination 依 Cloudflare [pricing 文件](https://developers.cloudflare.com/email-service/platform/pricing/) 可在各方案免費使用。

設定 Gmail allowlist、OTP pepper 與 Turnstile secret;secret 只走 Wrangler,不寫進 `wrangler.jsonc`:

```bash
npx wrangler secret put ALLOWED_GMAILS       # 例如:owner@gmail.com
npx wrangler secret put OTP_PEPPER
npx wrangler secret put TURNSTILE_SECRET_KEY
```

另外把 `OTP_FROM_EMAIL`、`TURNSTILE_SITE_KEY` 與 `TURNSTILE_EXPECTED_HOSTNAME` 填入 `wrangler.jsonc` 的 vars。`AUTH_USER_ID` 可填既有資料使用的 owner ID;若留空,新的 Gmail 身分會以正規化後的 Gmail 地址作為 user ID。

### 3. Migration、測試與部署

```bash
npx wrangler types
npm run typecheck
npm test
npx wrangler d1 migrations apply business-card-mcp --remote
npx wrangler deploy
```

### 4. 連接 ChatGPT

1. 開啟部署後的網站,輸入 allowlist 內的 Gmail,完成 Turnstile,收取一次性驗證碼後登入。
2. 產生名片 MCP Key。
3. 複製完整 Connector URL;URL 內含 Key,視同密碼。
4. 在 ChatGPT 開發人員模式新增 Remote MCP。
5. 掃描工具後,以「使用名片 MCP 搜尋某某人」測試。

## 本機開發

```bash
npm run migrate:local
npm run dev
```

健康檢查:`GET /healthz`

Remote MCP:`POST /mcp`

## 安全與隱私

- 所有名片查詢都以 Gmail OTP session 或 MCP Key 擁有者限制。
- R2 bucket 維持私人;縮圖由登入保護的 API 提供。
- MCP 同時接受 Bearer token 與 Connector URL query token。
- 完整 Key 只在建立當下顯示,支援個別撤銷。
- 請勿提交 `.env`、`.dev.vars`、`wrangler.jsonc` 或 `public/config.js`。

安全問題請依 [SECURITY.md](SECURITY.md) 私下回報,不要建立公開 Issue。

## 驗證

```bash
npm test
npm run typecheck
npm audit --omit=dev
```

專案目前有單元、MCP protocol、Web API、權限、儲存及 UI 合約測試;coverage threshold 為 lines/functions/statements 80%、branches 75%。

## 已知限制

- 尚未提供向量語意搜尋。
- 既有無圖名片尚未提供補圖介面;新資料已強制縮圖必填。
- Cloudflare Email Service 的 Email Sending 需要已 onboard 的 Cloudflare DNS 網域;任意 Gmail 收件者可能需要 Workers Paid。部署前請確認寄件方案與 verified destination 狀態。
- 永久刪除預設不開放,使用封存避免誤刪。

## License

Apache-2.0。詳見 [LICENSE](LICENSE)。