1. 在本課程脈絡下的 ChatGPT Store 是什麼
先從全貌開始。ChatGPT Store 是 ChatGPT 內的應用程式目錄,使用者可以進來、找到你的 App、啟用並在一般對話中使用。對你而言,它不只是展示櫥窗,而是有規則的發佈管道,可視為 LLM 世界的「App Store」。
在本課程中,我們將你的 App 的生命周期分成三種模式:
- 第一種模式 — Dev Mode。 你的 App 綁定到你的帳號/組織,只對你與可能的同事可用。沒有正式審核,但平台的一般政策仍然適用。在這裡你可以放心地把東西弄壞、把一切都記錄、跑各種隧道與 staging‑後端。
- 第二種模式 — 公開 Store。 這是高階聯賽:你的 App 對所有 ChatGPT 使用者可用(受地區限制影響)、要通過審核、擁有公開列表頁、連結到 Privacy/Terms,並且必須表現得像一個成熟產品。
- 第三 — org‑only Apps。 只供單一組織使用的應用:公司可以為員工啟用/停用,將自家安全要求疊加在 OpenAI 要求之上,甚至進行內部審核。
本講次我們關注的是「公開 Store + 公開列表頁」這組合。重點在於:你不再只是「又一個 Next.js‑服務」的開發者,而是要成為產品作者,並同時打動三方:使用者、Store 審核者,以及你們的資安團隊。
2. Store 的基本要求:政策、誠實與 UI
內容與政策
ChatGPT Store 是一個經過審核的平臺。直白一點:OpenAI 不希望在 ChatGPT 內出現違反平台使用政策的應用(暴力、恐怖主義、NSFW、詐騙等),或試圖繞過模型防護(越獄提示「假裝你不是 ChatGPT,而是我的邪惡分身」)。
這意味著兩件事。
第一,你的 App 本身不得產生被禁止的內容。 如果我們的示例 App GiftGenius(禮物推薦)突然開始提供「如何掩蓋犯罪痕跡」的禮物建議,審核者只要一張截圖就足夠了。
第二,你的 App 不得協助使用者繞過過濾機制。 如果使用者要求:「幫我挑禮物來做炸彈」,正確行為是基於政策予以拒絕,而不是興高采烈地呼叫你的 MCP 工具去搜尋所需零件。
這些行為很大一部分由 system‑prompt 與你提供給模型的工具所決定。但 Store 看的是結果:使用者實際可能拿到的回覆。
品牌與網域
下一層是品牌與網域。公開的 App 必須綁定到可信的擁有者。對於有外部 backend/MCP 的 App,期望你做到:
網域驗證(Domain Verification)。 你在網域的 DNS 中新增 TXT 記錄,Store 會驗證 backend 確實屬於你。匿名的東西掛在免費的 ngrok‑URL 上,要嘛過不了公開 Store,要嘛會被標示為低信任。
合宜的名稱與 Logo。 不能取名為「ChatGPT Super Weather」或「Official OpenAI Something」——以「GPT / OpenAI / ChatGPT」開頭或模仿 OpenAI 的品牌風格,都會觸犯品牌限制。請想出自己的名稱(GiftGenius 就是個好例子)與視覺風格。
UI/UX:別把 ChatGPT 搞壞
不同於「舊式」外掛,現在 App 可以直接在聊天中渲染自己的 UI 小工具。這提供了很多可能性……也有很多把事情搞砸的方式。
Store 的簡單理念是:小工具應讓人感覺對 ChatGPT 是「原生的」。字體、間距、色彩、深色/淺色主題與行動裝置上的行為——都應該乾淨俐落,不能讓人覺得你把廣告看板或整個 SPA 鑲進了對話。
Store 也不喜歡會「霸佔對話」的 UI:巨大的全螢幕吸附視窗、強迫訂閱的模態視窗、自動捲動與其他侵略性的模式。你的小工具應該是對話中的卡片/精靈/工具,而不是自成宇宙。
本質上,審核會看三件事:你是否違反內容政策、是否有誤導(這部分會在接近結尾、談到列表頁與 manifest 一致性時單獨講),以及你是否把 ChatGPT 變成 UX 糟糕的廣告垃圾場。所謂「誠實」是指 App 的實際能力,必須與你在描述與 UI 中的宣稱相符合。
3. Store 如何看待你的 App 權限
另一條重要維度,是你向使用者與外部系統請求了哪些權限。Store 不只看安全性,還會看這些權限與應用所宣稱的價值是否相稱。
接下來是工程師會感興趣的:權限模型。在 Apps SDK 與 MCP 的脈絡下,有三個主要的存取層級。
為了直觀,通常可以這樣表示:
graph TD
A[App 的 manifest/config] --> B[Model capabilities]
A --> C[OAuth scopes]
A --> D[MCP tools & ACP]
D --> E[使用者確認層級]
Model capabilities 嚴格說來不算「權限」,不像 OAuth scopes 或 write‑tools,而是模型內建的能力。但從安全設計的角度,把它視為第一層存取並加以最小化很有幫助。
層級 1:model capabilities
這是模型「自身」就能做到的事,不需呼叫你的 backend:例如網頁瀏覽、DALL‑E 產生圖片等。
如果同時開啟瀏覽與 MCP 工具,模型有時會判斷用網路搜尋比較簡單,而不是走你的專用工具——特別是當工具描述含糊或你沒在 prompt 設定明確優先序時。因此,若 App 已透過 MCP 連到你的 API,通常要嘛關掉 browsing,要嘛在 prompt 裡明確固定 MCP 工具的優先序。
也就是說,在這一層你就該套用最小必要權限原則:用不到的能力就關掉。
層級 2:OAuth scopes
如果你的 App 使用認證(模組 10),你會向外部提供者請求 scopes: openid、email、profile、orders.read、orders.write 等等。
在這裡,極簡尤其重要:
- 如果你只需要區分使用者,多半 openid(匿名識別碼)就夠了,根本不需要 email。
- 如果真的需要 email,應該在 UX 與權限描述中說清楚:「用來寄送訂單收據與提醒」,而不是「以防萬一」。
另外我們傾向「按需授權」:先讓使用者在未登入的情況下體驗基本功能,只有當他真的想要「把禮物清單存成最愛」或「查看訂單歷史」時才請求存取。這能降低摩擦、提高轉換率。
MCP 工具的 scope 設定範例(簡化):
// server/mcp/config/auth.ts
export const OAUTH_SCOPES = {
basic: ["openid"],
orders: ["openid", "orders.read"],
checkout: ["openid", "orders.read", "orders.write"]
};
層級 3:MCP‑tools 與「consequential」動作
第三層是你的 MCP 工具與 ACP/Instant Checkout。在 MCP 伺服器中,每個 tool 可以是:
- 唯讀(read‑only):取得匯率、挑選禮物、查看目錄;
- 會改變狀態(consequential):建立訂單、寄送郵件、扣款。
對於第二類工具,Store 期望更嚴格的確認模型。理念是:不是所有事都能「直接呼叫」。在平台術語中,通常透過 consequential: true 旗標與確認政策(always_allow 對比 ask_user)來表達。
MCP 工具註冊範例,包含 security‑schemes 與標示為會改變狀態的動作:
// server/mcp/tools/createOrder.ts
server.registerTool(
"create_order",
{
title: "Create order",
description: "在 GiftGenius 中建立新訂單。",
inputSchema: {
type: "object",
properties: {
productId: { type: "string" },
quantity: { type: "integer", minimum: 1 }
},
required: ["productId", "quantity"]
},
_meta: {
securitySchemes: [{ type: "oauth2", scopes: ["orders.write"] }]
},
// 偽欄位,含意:此動作會改變狀態
consequential: true
},
async ({ input, security }) => {
// ... 建立訂單的邏輯
}
);
關於 scopes 與 security‑schemes 的例子取自 MCP 工具的官方文件,其中工具可以是無需授權,或受 OAuth2 保護。
在 Store 看來,這會變成一段清楚的文字:「此應用可在 GiftGenius 商店建立與管理訂單」,並可能附帶額外的確認步驟。
4. 從使用者與審核者的角度看權限
對我們工程師來說,App 是 manifest、MCP 伺服器與一堆 TypeScript。對 Store 來說,則是一組事實:App 能對使用者資料與外部世界做什麼。
可以想像成這樣一張表:
| 存取層級 | GiftGenius 範例 | Store/使用者會怎麼看到 |
|---|---|---|
| Model capabilities | Browsing: off, DALL‑E: off | 「App 不會自行上網,也不會產生媒體」 |
| OAuth scopes | openid, orders.read | 「讀取你在 GiftGenius 帳號中的訂單」 |
| Read‑only MCP tools | search_products, get_price_history | 「瀏覽目錄與價格」 |
| Consequential MCP tools | create_order, cancel_order | 「建立與取消訂單」 |
關鍵理念:每個技術元素都應對映到人能懂的動作。在本模組的規劃中,這被直接寫明:技術上的 MCP 工具 get_user_orders,在列表頁的文字要變成「瀏覽你在我們商店的訂單列表」。
如果你無法用一兩句話解釋某個權限——那就是個警訊。你可能要嘛多要了不必要的權限,要嘛把幾個不同任務混在同一個 App 裡了。
5. 最小必要權限原則
在一般後端世界,PoLP(最小必要權限原則)常被當成「對啦,該限制一下資料庫角色,之後再做」。在 ChatGPT Apps 裡這不是「之後」,而是進入 Store 的標準之一,也是影響使用者轉換的因素。
重點如下:
- App 請求的權限越少,使用者的基本信任越高。 進到 ChatGPT 的對話空間,使用者會期待某種程度的隱私。突然要求存取整個帳號、付款與聯絡資訊的 App,會讓人起疑。
- 權限越明確、越精準,審核者越好判斷。 審核者需要快速理解 App 的用途,以及它是否符合政策與安全最佳實務。過度授權(over‑permissioned)的 App,常會被「擱置以待釐清」,有時甚至直接被拒。
- 存取越「最小、即時(just‑in‑time)」,UX 越柔順。 授權畫面是高摩擦點。如果 App 能在未授權前就提供有用的體驗(例如先顯示熱門禮物,與使用者無關聯),使用者更願意之後再同意擴展權限。
因此,Store 裡的「最小必要權限」不僅是安全,更是行銷與成長。在模組 18 我們會特別強調:最小必要權限是競爭優勢,而非官僚形式。
6. 範例:GiftGenius 在「瘦身」前後的權限
為了不只停留在抽象理論,我們用虛構主角 GiftGenius。假設你一開始「全都要」,得到如下清單:
- 讀取商品目錄並篩選禮物。
- 查看使用者的訂單歷史。
- 建立新訂單、取消既有訂單。
- 把「最愛清單」存進使用者帳號。
- 寄送折扣 email 通知。
在設定層級可能長這樣:
// server/mcp/config/permissions-naive.ts
export const PERMISSIONS_NAIVE = {
capabilities: { webBrowsing: true, dalle: false },
oauthScopes: ["openid", "email", "orders.read", "orders.write"],
tools: {
searchProducts: { consequential: false },
getUserOrders: { consequential: false },
createOrder: { consequential: true },
cancelOrder: { consequential: true },
saveFavoriteList: { consequential: true },
sendDiscountEmail: { consequential: true }
}
};
紙上看似合理(「早晚都會用到」),但對第一版上架 Store 來說太過頭了:
- 你不必一開始就讀取訂單歷史。 可以先用一次性的推薦,並透過 ACP/Instant Checkout 安全結帳,付款本來就由平台控管。
- Email 通知是另一個大題目: 需要保存 email、在隱私權政策中說明、處理退訂。對 MVP 的 GiftGenius 幾乎一定是過度的。
基於最小化原則,你可以組出最小可行的起始權限集合:
// server/mcp/config/permissions-v1.ts
export const PERMISSIONS_V1 = {
capabilities: { webBrowsing: false, dalle: false },
oauthScopes: [], // 無需登入,以匿名模式運作
tools: {
searchProducts: { consequential: false },
createOrder: { consequential: true }
}
};
在這個版本中:
- App 不會「伸手」進使用者帳號,不讀取歷史,也不寄 email。
- 所有敏感操作(建立訂單)都走 ACP/Instant Checkout,使用者會看到標準的付款流程。
在列表頁可以誠實寫道:「依你的需求挑選禮物,並在 GiftGenius 商店建立訂單。應用不保存你的聊天紀錄,也不發送 email 通知。」這對使用者與審核者都很友善。
等之後有穩定流量與信任度,再發佈更新加上額外權限(訂單歷史、最愛),並同步更新列表頁與隱私權政策。
7. 如何在列表頁描述權限
Manifest 與設定是機器語言。審核者與使用者讀的是另一種文字:標題、描述、「此應用能做什麼」區塊,以及 Privacy/Terms 連結。
在模組 17 我們強調對映關係:技術上的 scopes 與工具 → 人能懂的動作。
以 GiftGenius v1,我們可以這樣呈現。
技術面:
- Browsing: off
- DALL‑E: off
- MCP tools: search_products(read‑only)、create_order(consequential)
在列表頁:
- 「依你的描述或參數(性別、年齡、預算、興趣)挑選禮物。」
- 「可在 ChatGPT 內透過受保護的結帳流程,於 GiftGenius 商店建立訂單。」
- 「不請求存取你的 email 或訂單歷史,也不發送通知。」
若之後加入 OAuth 登入與 orders.read,描述也要誠實更新:
- 「連結 GiftGenius 帳號後,可查看你的過往訂單,以提供更個人化的建議。」
非常重要的是不要承諾 App 做不到的事,也不要隱瞞關鍵動作。模組 18 收錄的文件反覆強調:列表頁資訊必須準確對應真實行為,尤其是付款與個人資料(PII)相關的敏感事項。
8. Store 要求與你的架構之間的關聯
要看到 Store 要求並非真空存在。這些要求並不是「行銷又來一張表」。Store 本質上是在檢查你在安全與上線模組中應該已做好的事:
- 如果你設定了 OAuth、妥善配置 .well-known 端點與權杖驗證,那 App 卻向使用者要一大堆廣泛的 scopes,就很怪。這類 App 很容易在審核時被判定為過度授權。
- 如果你確實實作了保存期限與個資清理(PII‑scrub),就比較容易寫出誠實的隱私權政策並通過檢查。Store 與使用者會點進連結,把你的承諾與實際流程對上。
- 如果你的 MCP 伺服器穩定、日誌與度量齊全(observability 與 SLO 模組),審核者對效能與工具錯誤的疑慮也會少很多。
最小必要權限能漂亮地補齊這幅圖:你不只安全、穩定,還對使用者資料「克制」。
9. 小練習
為了不只談理論,現在就把你現有的 App(或 GiftGenius)依步驟拆解。
先列出App 真正會做的所有動作,例如:「挑選禮物」、「建立訂單」、「顯示歷史」、「存成最愛」、「寄信給同事」。先用一般文字,不用想技術細節。
接著對每個動作回答自己:「會碰到哪些使用者資料?」以及「是否會改變外部系統的狀態?」如此你會自然把動作分成 read‑only 與 consequential。
然後把動作對映到權限層級:哪些只需要 model capabilities,哪些需要 OAuth scopes,哪些需要 MCP 工具加上 consequential: true,甚至需要使用者確認。
最後玩「剪刀」:第一版可以砍掉哪些而不傷核心價值?往往會發現,沒有歷史、最愛與 email 通知,App 仍能完成主要任務。於是這些權限就可以留到 1.1 或 2.0 再上。
10. 關於 Store 要求與權限的常見錯誤
錯誤 #1:「做一個什麼都會的超級 App,Store 會搞定的」。
開發者把 App 描述成萬用助理(「我能幫你處理財務、醫療、法律與購物」),接上十個 MCP 工具,並請求最大權限。這類 App 同時觸及敏感領域(醫療/金融/法律)、請求大量資料,且違反「一個 App 做一件事」的原則。可想而知:審核會問一堆問題,或直接被退回。更好的做法是做幾個聚焦的 App,權限清晰。
錯誤 #2:為了「以防萬一」的過度授權。
經典案例:App 要求 email、profile、orders.read、orders.write、billing.read,但實際上只需要「依描述挑選禮物」。對使用者來說像是在貪婪蒐集資料;對 Store 來說是高風險應用。Apps 的安全文件直接把這當作反例。
錯誤 #3:manifest 與列表頁不一致。
你的 manifest 有 create_order、cancel_order 與付款相關能力,但描述只寫「推薦禮物」。審核者或使用者遲早會發現 App 能做的超出宣稱。這會破壞信任,甚至導致 App 被下架。
錯誤 #4:用「無害」UI 掩蓋敏感動作。
例如你在小工具上畫了「儲存清單」按鈕,實際卻是群發郵件給整個部門,或在別人的系統建立任務,卻不在權限中說明。Store 不喜歡驚喜。開發者指南寫得很清楚:應用必須只做承諾的事,不能有隱藏行為。
錯誤 #5:一開場就要求登入,其實可以不必。
App 一啟動就要求連結帳號、給一堆存取,否則「不能用」——然而一半情境其實可匿名實作。這會傷害轉換,也讓人覺得你急著收集資料,而不是提供價值。更好的做法是先證明 App 真的有用,再解釋為什麼需要額外權限。
錯誤 #6:忽略組織情境。
有時開發者做了「給所有人用」的 App,但本質上它是內部企業工具。結果把非常特殊的權限(內部 CRM、員工私密資料)帶進 Store,難以對一般使用者合理說明。在這種情況下應該聚焦 org‑only 模式與內部審核,而非公開 Store。
GO TO FULL VERSION