Skip to main content
Glama
BP.json34.7 kB
{ "metadata": { "id": "BP-ios-notification-image", "group_id": "ai-magic-editor", "type": "Blueprint", "feature": "ios-notification-image", "requirement": "REQ-ios-notification-image" }, "info": { "status": "Implemented", "update_date": "2025-10-01", "implementation_date": "2025-10-01", "summary_context": "iOS Notification Service Extension 的技術架構,定義圖片下載、附加流程和組件設計。已完成實作並通過所有實機測試驗證。" }, "title": "專案藍圖 (Blueprint): iOS Push Notification 圖片顯示", "sections": [ { "id": "sec-core-data-structures", "title": "1. 核心資料結構 (Core Data Structures)", "summary": "定義圖片下載RBT和通知處理所需的核心資料結構。", "blocks": [ { "id": "blk-ds-imageinfo", "type": "code", "title": "NotificationImageInfo", "content": "struct NotificationImageInfo {\n let imageUrl: URL // 圖片 URL\n let contentType: String? // MIME type (可選)\n}" }, { "id": "blk-ds-result", "type": "code", "title": "DownloadResult", "content": "enum DownloadResult {\n case success(URL) // 本地暫存檔案 URL\n case failure // 下載失敗(含 timeout)\n}" } ], "children": [] }, { "id": "sec-component-specs", "title": "2. 組件規格 (Component Specifications)", "summary": "定義實現 Notification Service Extension 所需的三大核心組件。", "blocks": [], "children": [ { "id": "sec-spec-notificationservice", "title": "NotificationService (Extension 主體)", "summary": null, "blocks": [ { "id": "blk-ns-intro", "type": "list", "title": "簡介", "items": [ "Notification Service Extension 的主要類別,繼承 `UNNotificationServiceExtension`" ] }, { "id": "blk-ns-duty", "type": "list", "title": "職責", "items": [ "接收系統調用 `didReceive(_:withContentHandler:)`", "解析 FCM payload 取得圖片 URL", "協調 Downloader 和 Modifier 完成圖片附加", "處理 30 秒系統超時" ] }, { "id": "blk-ns-input", "type": "list", "title": "輸入", "items": [ "`request: UNNotificationRequest` (通知請求)", "`contentHandler: (UNNotificationContent) -> Void` (完成回調)" ] }, { "id": "blk-ns-output", "type": "list", "title": "輸出", "items": [ "修改後的 `UNNotificationContent`(含圖片附件或原始內容)" ] }, { "id": "blk-ns-tasks", "type": "list", "title": "實作 Tasks", "items": [ "`TASK-001-notification-service`" ] }, { "id": "blk-ns-acceptance", "type": "list", "title": "技術驗收標準", "items": [ "成功解析 FCM payload 中的圖片 URL", "正確協調 Downloader 和 Modifier", "下載/附加失敗時退回原始通知", "處理 `serviceExtensionTimeWillExpire()` 超時情況" ] } ], "children": [] }, { "id": "sec-spec-downloader", "title": "NotificationImageDownloader (圖片下載器)", "summary": null, "blocks": [ { "id": "blk-dl-intro", "type": "list", "title": "簡介", "items": [ "負責從 HTTPS URL 下載圖片到本地暫存" ] }, { "id": "blk-dl-duty", "type": "list", "title": "職責", "items": [ "使用 `URLSession.shared.downloadTask` 下載圖片", "設定 5 秒 timeout", "驗證 URL 為 HTTPS", "錯誤處理與日誌記錄" ] }, { "id": "blk-dl-input", "type": "list", "title": "輸入", "items": [ "`imageUrl: URL` (圖片 URL)", "`timeout: TimeInterval` (預設 5 秒)" ] }, { "id": "blk-dl-output", "type": "list", "title": "輸出", "items": [ "成功: 本地暫存檔案 `URL`", "失敗: `nil`(並記錄 log)" ] }, { "id": "blk-dl-tasks", "type": "list", "title": "實作 Tasks", "items": [ "`TASK-002-image-downloader`" ] }, { "id": "blk-dl-acceptance", "type": "list", "title": "技術驗收標準", "items": [ "只接受 HTTPS URL(HTTP 拒絕)", "5 秒 timeout 正確觸發", "下載成功返回有效的本地檔案 URL", "失敗時正確記錄錯誤日誌" ] } ], "children": [] }, { "id": "sec-spec-modifier", "title": "NotificationContentModifier (通知內容修改器)", "summary": null, "blocks": [ { "id": "blk-mod-intro", "type": "list", "title": "簡介", "items": [ "負責建立 `UNNotificationAttachment` 並附加到通知內容" ] }, { "id": "blk-mod-duty", "type": "list", "title": "職責", "items": [ "從本地檔案 URL 建立 `UNNotificationAttachment`", "附加到 `UNMutableNotificationContent.attachments`", "錯誤處理與日誌記錄" ] }, { "id": "blk-mod-input", "type": "list", "title": "輸入", "items": [ "`content: UNMutableNotificationContent` (可修改的通知內容)", "`imageFileUrl: URL` (本地圖片檔案 URL)" ] }, { "id": "blk-mod-output", "type": "list", "title": "輸出", "items": [ "成功: 附加圖片後的 `UNMutableNotificationContent`", "失敗: 原始 `content`(並記錄 log)" ] }, { "id": "blk-mod-tasks", "type": "list", "title": "實作 Tasks", "items": [ "`TASK-003-content-modifier`" ] }, { "id": "blk-mod-acceptance", "type": "list", "title": "技術驗收標準", "items": [ "成功建立 `UNNotificationAttachment`", "正確附加到 `content.attachments`", "附加失敗時不影響原始 content", "失敗時正確記錄錯誤日誌" ] } ], "children": [] } ] }, { "id": "sec-core-logic", "title": "3. 核心處理邏輯 (Core Processing Logic)", "summary": "詳細描述從收到通知到顯示圖片的完整處理流程。", "blocks": [], "children": [ { "id": "sec-logic-mainflow", "title": "主流程 (NotificationService)", "summary": null, "blocks": [ { "id": "blk-mf-step1", "type": "code", "title": "階段 1: 接收通知", "content": "iOS 系統收到 FCM 推播\n ↓\n檢查 payload 是否含 mutable-content: 1\n ↓\n系統啟動 NotificationService Extension\n ↓\n調用 didReceive(_:withContentHandler:)" }, { "id": "blk-mf-step2", "type": "code", "title": "階段 2: 解析 Payload", "content": "取得 request.content.userInfo\n ↓\n優先解析: userInfo[\"fcm_options\"][\"image\"] (iOS 專用)\n ↓\n備用解析: userInfo[\"notification\"][\"image\"] (通用)\n ↓\n驗證 URL 格式 (必須是 HTTPS)" }, { "id": "blk-mf-step2-note", "type": "list", "title": "⚠️ 待確認", "items": [ "FCM payload 的實際欄位名稱(待後端提供實際格式)" ] }, { "id": "blk-mf-step3", "type": "code", "title": "階段 3: 下載圖片", "content": "有效的圖片 URL?\n ├─ NO → 跳到階段 5(回傳原始內容)\n └─ YES → 調用 NotificationImageDownloader.download(imageUrl)\n ↓\n URLSession.downloadTask (5秒 timeout)\n ↓\n 成功?\n ├─ NO → 跳到階段 5(回傳原始內容 + log)\n └─ YES → 繼續階段 4" }, { "id": "blk-mf-step4", "type": "code", "title": "階段 4: 附加圖片", "content": "NotificationContentModifier.attach(imageFileUrl, to: content)\n ↓\n建立 UNNotificationAttachment\n ↓\n成功?\n ├─ NO → 跳到階段 5(回傳原始內容 + log)\n └─ YES → content.attachments.append(attachment)" }, { "id": "blk-mf-step5", "type": "code", "title": "階段 5: 回傳結果", "content": "調用 contentHandler(modifiedContent)\n ↓\niOS 系統顯示通知\n ↓\n有圖片附件 → Rich Notification(可展開查看圖片)\n無圖片附件 → 純文字通知" } ], "children": [] }, { "id": "sec-logic-timeout", "title": "超時處理", "summary": null, "blocks": [ { "id": "blk-to-flow", "type": "code", "title": null, "content": "30 秒內未完成(系統限制)\n ↓\niOS 調用 serviceExtensionTimeWillExpire()\n ↓\n立即回傳當前的 bestAttemptContent\n ↓\n即使圖片未下載完成,也顯示通知(不阻斷用戶)" } ], "children": [] } ] }, { "id": "sec-tech-details", "title": "4. 技術架構細節", "summary": null, "blocks": [], "children": [ { "id": "sec-td-files", "title": "檔案結構", "summary": null, "blocks": [ { "id": "blk-td-files-code", "type": "code", "title": null, "content": "MagicEditor/\n└── Sources/\n └── Extensions/\n └── NotificationService/\n ├── NotificationService.swift // 主體 (TASK-001)\n ├── NotificationImageDownloader.swift // 下載器 (TASK-002)\n └── NotificationContentModifier.swift // 修改器 (TASK-003)" } ], "children": [] }, { "id": "sec-td-tuist", "title": "Tuist 專案配置", "summary": null, "blocks": [ { "id": "blk-td-tuist-list", "type": "list", "title": null, "items": [ "新增 `NotificationServiceExtension` target", "Bundle ID: `{PRODUCT_BUNDLE_IDENTIFIER}.NotificationServiceExtension`", "Deployment Target: iOS 14.0+", "依賴: Foundation, UserNotifications", "Info.plist 配置: `NSExtension` 相關設定", "App Groups 共享(未來可能需要)" ] }, { "id": "blk-td-tuist-tasks", "type": "list", "title": "實作 Tasks", "items": [ "`TASK-004-tuist-configuration`" ] } ], "children": [] }, { "id": "sec-td-formats", "title": "圖片格式支援", "summary": null, "blocks": [ { "id": "blk-td-formats-list", "type": "list", "title": null, "items": [ "PNG (.png)", "JPEG (.jpg, .jpeg)", "GIF (.gif)", "其他格式由 `UNNotificationAttachment` 自動判斷" ] } ], "children": [] }, { "id": "sec-td-security", "title": "安全性考量", "summary": null, "blocks": [ { "id": "blk-td-security-list", "type": "list", "title": null, "items": [ "**只接受 HTTPS URL**(HTTP 拒絕)", "**驗證 Content-Type**(僅接受 image/* MIME types)", "**自動清理暫存檔案**(系統管理)" ] } ], "children": [] } ] }, { "id": "sec-risks", "title": "5. 風險、待辦事項與決策 (Risks, Open Questions & Decisions)", "summary": null, "blocks": [], "children": [ { "id": "sec-risks-adr", "title": "設計決策記錄 (ADR)", "summary": null, "blocks": [ { "id": "blk-risks-adr-table", "type": "table", "title": null, "content": "| 決策點 | 變更原因 | 最終實作選擇 | 記錄日期 |\n|--------|----------|----------|----------|\n| 組件拆分策略 | 未來擴充性(按鈕、自訂 UI) | 拆分為 3 個獨立檔案 | 2025-09-30 |\n| 圖片下載工具 | Extension 輕量化,不依賴第三方 | 原生 URLSession | 2025-09-30 |\n| 錯誤處理方式 | 不阻斷通知顯示 | 失敗退回純文字 + log | 2025-09-30 |\n| Timeout 時間 | 平衡速度與成功率 | 5 秒(系統總限制 30 秒) | 2025-09-30 |\n| 前景通知處理 | 降低複雜度 | 不處理(保持現有行為) | 2025-09-30 |\n| Completion Flag | 防止雙重回調風險 | 新增 isCompleted flag 和統一完成方法 | 2025-10-01 |\n| Content-Type 驗證 | 安全性與相容性平衡 | 驗證 image/* MIME type(寬鬆策略) | 2025-10-01 |" } ], "children": [] }, { "id": "sec-risks-tech", "title": "技術風險", "summary": null, "blocks": [ { "id": "blk-risks-tech-1", "type": "list", "title": null, "items": [ "1. **FCM Payload 格式不確定** (優先級: 高)", "* 風險: 解析欄位錯誤導致無法取得圖片 URL", "* 緩解: 待後端確認實際格式後更新程式碼", "* 備用方案: 同時嘗試多個可能的欄位名稱" ] }, { "id": "blk-risks-tech-2", "type": "list", "title": null, "items": [ "2. **圖片下載速度不穩定** (優先級: 中)", "* 風險: 網路不佳時 5 秒 timeout 不足", "* 緩解: 可調整 timeout 參數,或後端提供縮圖", "* 備用方案: 使用者仍收到純文字通知" ] }, { "id": "blk-risks-tech-3", "type": "list", "title": null, "items": [ "3. **30 秒系統超時** (優先級: 低)", "* 風險: 極慢網路可能觸發系統超時", "* 緩解: 5 秒下載 timeout 保留足夠緩衝", "* 備用方案: serviceExtensionTimeWillExpire 處理" ] } ], "children": [] }, { "id": "sec-risks-open", "title": "待辦事項 (Open Questions)", "summary": null, "blocks": [ { "id": "blk-risks-open-list", "type": "list", "title": null, "items": [ "[ ] **FCM Payload 格式確認**: 等待後端提供實際的 payload JSON 範例", "[ ] **後端 mutable-content 設定**: 確認後端已在 FCM 發送時設定此欄位", "[ ] **測試推播工具**: 準備測試用的圖片 URL 和推播發送方式", "[ ] **App Groups 配置**: 如果需要與主 App 共享資料(未來擴充)" ] } ], "children": [] } ] }, { "id": "sec-integration", "title": "6. 與現有架構的整合", "summary": null, "blocks": [], "children": [ { "id": "sec-int-fcm", "title": "現有 FCM 整合點", "summary": null, "blocks": [ { "id": "blk-int-fcm-appdelegate", "type": "list", "title": "AppDelegate (不需修改)", "items": [ "`Messaging.messaging().delegate = self` 已設定", "`didReceiveRegistrationToken` 已處理 token 更新", "`UNUserNotificationCenter.delegate = self` 已設定" ] }, { "id": "blk-int-fcm-manager", "type": "list", "title": "MessagingManager (不需修改)", "items": [ "Token 管理已完善", "Extension 不直接與此互動" ] }, { "id": "blk-int-fcm-foreground", "type": "list", "title": "前景通知處理 (不修改)", "items": [ "`willPresent` 保持現有邏輯", "繼續顯示 `.banner, .sound, .badge`" ] } ], "children": [] }, { "id": "sec-int-backend", "title": "後端 API 依賴", "summary": null, "blocks": [ { "id": "blk-int-backend-api", "type": "list", "title": "push-notification-api", "items": [ "需確認 `REQ-push-notification-api` 是否已包含圖片支援", "需確認後端發送 FCM 時的 payload 格式", "需確認 `mutable-content: 1` 是否已設定" ] } ], "children": [] } ] }, { "id": "sec-task-breakdown", "title": "Task 拆解與追蹤 (Post Task Breakdown & Tracking)", "summary": null, "blocks": [], "children": [ { "id": "sec-tb-overview", "title": "Task 概覽", "summary": null, "blocks": [ { "id": "blk-tb-overview-table", "type": "table", "title": null, "content": "| Task ID | 標題 | 預估工時 | 依賴 | 優先級 |\n|---------|------|---------|------|--------|\n| TASK-001 | NotificationService 主體實作 | 1.5h | - | 高 |\n| TASK-002 | NotificationImageDownloader 實作 | 1h | - | 高 |\n| TASK-003 | NotificationContentModifier 實作 | 1h | - | 高 |\n| TASK-004 | Tuist 專案配置 | 2h | TASK-001, TASK-002, TASK-003 | 高 |\n| TASK-005 | 整合測試與除錯 | 1.5h | TASK-004 | 中 |" }, { "id": "blk-tb-overview-total", "type": "list", "title": "預估總工時", "items": [ "7 小時" ] } ], "children": [] }, { "id": "sec-tb-tracking", "title": "實作進度追蹤", "summary": null, "blocks": [ { "id": "blk-tb-tracking-table", "type": "table", "title": null, "content": "| 組件名稱 | 對應 Tasks | 實作狀態 | 完成度 | 備註 |\n|----------|------------|--------|--------|------|\n| NotificationImageDownloader | TASK-002 | Done | 100% | 已實作完成 |\n| NotificationContentModifier | TASK-003 | Done | 100% | 已實作完成 |\n| NotificationService | TASK-001 | Done | 100% | 已實作完成(123 行)|\n| Tuist 專案配置 | TASK-004 | Done | 100% | 已完成,Extension target 配置成功並編譯通過 |\n| 整合測試 | TASK-005 | Done | 100% | 已完成實機測試,所有測試項目通過(2025-10-01)|\n\n---" } ], "children": [] } ] }, { "id": "sec-post-validation", "title": "實作後驗證與總結 (Post-Implementation Validation & Summary)", "summary": null, "blocks": [], "children": [ { "id": "sec-pv-completion", "title": "實作完成度", "summary": null, "blocks": [ { "id": "blk-pv-completion-code", "type": "list", "title": "程式碼實作: 100% ✅", "items": [ "NotificationImageDownloader (105 lines)", "NotificationContentModifier (47 lines)", "NotificationService (123 lines)", "Tuist 專案配置完成", "Bundle ID: `com.cardinalblue.magiceditor.notificationserviceextension`" ] }, { "id": "blk-pv-completion-test", "type": "list", "title": "整合測試: 50% 🔄", "items": [ "測試計畫已完成", "等待 Apple Developer Portal 配置", "需實機測試環境" ] }, { "id": "blk-pv-completion-total", "type": "list", "title": "總進度: 90%", "items": [ "(程式碼完成,待實機驗證)" ] } ], "children": [] }, { "id": "sec-pv-acceptance", "title": "技術驗收", "summary": null, "blocks": [], "children": [ { "id": "sec-pv-acceptance-done", "title": "已驗收項目 ✅", "summary": null, "blocks": [ { "id": "blk-pv-acceptance-done-list", "type": "list", "title": null, "items": [ "✅ NotificationService 成功解析 FCM payload(支援雙格式)", "✅ NotificationImageDownloader 正確協調 Downloader 和 Modifier", "✅ HTTPS-only URL 驗證機制", "✅ 5 秒 timeout 設定", "✅ 失敗降級機制(退回純文字通知)", "✅ 30 秒系統超時處理", "✅ Extension target 成功編譯", "✅ 所有程式碼包含追溯註解" ] } ], "children": [] }, { "id": "sec-pv-acceptance-pending", "title": "待驗收項目 ⏳", "summary": null, "blocks": [ { "id": "blk-pv-acceptance-pending-list", "type": "list", "title": null, "items": [ "⏳ 實機推播圖片顯示測試", "⏳ PNG/JPG/GIF 格式支援驗證", "⏳ 錯誤場景實機測試(HTTP URL, 404, 超時)", "⏳ 前景行為驗證", "⏳ FCM payload 實際格式確認(待後端提供)" ] } ], "children": [] } ] }, { "id": "sec-pv-lessons", "title": "知識沉澱與教訓 (Lessons Learned)", "summary": null, "blocks": [], "children": [ { "id": "sec-pv-lessons-debts", "title": "設計負債與技術債務", "summary": null, "blocks": [ { "id": "blk-pv-lessons-debts-list", "type": "list", "title": null, "items": [ "**FCM Payload 格式待確認**: 當前使用假設格式實作,需後端提供實際 payload 範例", "**日誌機制**: 使用 print 而非 os_log,未來可統一改為結構化日誌", "**Timeout 值硬編碼**: 5 秒 timeout 寫死在程式碼中,未來可考慮可配置" ] } ], "children": [] }, { "id": "sec-pv-lessons-design", "title": "低估與過度設計", "summary": null, "blocks": [ { "id": "blk-pv-lessons-design-list", "type": "list", "title": null, "items": [ "**Bundle ID 格式**: 初期使用動態變數,後改為硬編碼(實際問題較預期簡單)", "**拆分設計正確**: 三個組件(Downloader, Modifier, Service)拆分得宜,利於測試和維護", "**無過度設計**: 實作保持簡潔,未引入不必要的複雜度" ] } ], "children": [] }, { "id": "sec-pv-lessons-reusable", "title": "可復用模式/組件", "summary": null, "blocks": [ { "id": "blk-pv-lessons-reusable-1", "type": "list", "title": "Notification Service Extension 架構模式", "items": [ "組件拆分: Downloader → Modifier → Service", "錯誤處理: 失敗降級機制", "超時管理: 雙層 timeout(5s 下載 + 30s 系統)" ] }, { "id": "blk-pv-lessons-reusable-2", "type": "list", "title": "URLSession 下載處理模式", "items": [ "HTTPS-only 驗證", "Timeout 控制", "檔案暫存管理" ] }, { "id": "blk-pv-lessons-reusable-3", "type": "list", "title": "UNNotificationAttachment 建立模式", "items": [ "do-catch 錯誤處理", "優雅降級" ] } ], "children": [] } ] }, { "id": "sec-pv-suggestions", "title": "後續建議", "summary": null, "blocks": [], "children": [ { "id": "sec-pv-suggestions-immediate", "title": "立即行動(實機測試前)", "summary": null, "blocks": [ { "id": "blk-pv-suggestions-immediate-1", "type": "list", "title": "Apple Developer Portal 配置", "items": [ "建立 App ID: `com.cardinalblue.magiceditor.notificationserviceextension`", "啟用 Push Notifications capability", "建立 Development Provisioning Profile" ] }, { "id": "blk-pv-suggestions-immediate-2", "type": "list", "title": "後端協調", "items": [ "確認 FCM payload 實際格式", "確認後端發送時已設定 `mutable-content: 1`", "提供測試用圖片 URL" ] } ], "children": [] }, { "id": "sec-pv-suggestions-testing", "title": "實機測試階段 ✅", "summary": null, "blocks": [ { "id": "blk-pv-suggestions-testing-list", "type": "list", "title": null, "items": [ "✅ 安裝 App 到測試設備", "✅ 執行完整測試套件(正常 + 錯誤場景)", "✅ 記錄測試結果和截圖", "✅ 更新 TASK-005 測試覆蓋清單" ] }, { "id": "blk-pv-suggestions-results", "type": "list", "title": "測試結果 (2025-10-01)", "items": [ "✅ 實機推播圖片顯示測試通過", "✅ PNG/JPG/GIF 格式支援驗證通過", "✅ 錯誤場景實機測試通過(HTTP URL, 404, 超時)", "✅ 前景/背景行為驗證通過", "✅ FCM payload 實際格式確認通過" ] } ], "children": [] }, { "id": "sec-pv-suggestions-future", "title": "未來擴充建議", "summary": null, "blocks": [ { "id": "blk-pv-suggestions-future-list", "type": "list", "title": null, "items": [ "**App Groups 支援**: 如需與主 App 共享圖片快取", "**通知 Action 按鈕**: 自訂操作按鈕", "**圖片大小驗證**: 防止下載過大檔案", "**進階日誌**: 整合 Firebase Analytics 或 Crashlytics" ] } ], "children": [] } ] }, { "id": "sec-pv-summary", "title": "開發效率總結", "summary": null, "blocks": [ { "id": "blk-pv-summary-hours", "type": "list", "title": "預估工時", "items": [ "7 小時" ] }, { "id": "blk-pv-summary-actual", "type": "list", "title": "實際工時", "items": [ "~3 小時(程式碼實作 + 實機測試 + bug 修復)" ] }, { "id": "blk-pv-summary-reasons", "type": "list", "title": "效率提升原因", "items": [ "Task 拆分清晰,無相依阻塞", "使用 task-coding-agent 並行執行 TASK-001~003", "Tuist 配置已預先準備", "SwiftLint 自動修正節省時間" ] }, { "id": "blk-pv-summary-factors", "type": "list", "title": "關鍵成功因素", "items": [ "Blueprint 設計完整,減少返工", "組件拆分得宜,易於實作", "追溯註解完整,便於未來維護", "實機測試發現並修復 URL-encoded 路徑問題" ] }, { "id": "blk-pv-summary-timeline", "type": "list", "title": "實作完成時間線", "items": [ "2025-09-30: 完成 TASK-001~004 程式碼實作", "2025-10-01: 完成 TASK-005 實機測試與驗證", "2025-10-01: 修復檔名解析 bug 並移除 debug logs" ] } ], "children": [] }, { "id": "sec-pv-deploy", "title": "生產環境部署狀態 ✅", "summary": null, "blocks": [ { "id": "blk-pv-deploy-prs", "type": "list", "title": "Pull Requests", "items": [ "PR #377: iOS NotificationServiceExtension → `dev` branch", "PR #378: Backend Push Notification System → `dev` branch" ] }, { "id": "blk-pv-deploy-checklist", "type": "list", "title": "部署檢查清單", "items": [ "✅ 程式碼實作完成", "✅ 所有測試通過", "✅ SwiftLint 驗證通過", "✅ Apple Developer Portal 配置完成", "✅ Provisioning Profiles 建立完成", "✅ 實機測試驗證完成", "✅ 文檔更新完成" ] }, { "id": "blk-pv-deploy-final", "type": "paragraph", "title": "功能已達到生產環境標準,可以準備上線。", "content": "" } ], "children": [] } ] } ] }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/leo7nel23/KnowkedgeSmith-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server