CodeGym /コース /ChatGPT Apps /Store の要件と最小限の権限

Store の要件と最小限の権限

ChatGPT Apps
レベル 18 , レッスン 0
使用可能

1. このコースにおける ChatGPT Store とは

まず全体像から。ChatGPT Store は ChatGPT 内のアプリカタログで、ユーザーはここからあなたのアプリを見つけ、有効化し、通常の対話の中で利用できます。これは単なるショーケースではなく、ルールのある配信チャネルで、LLM の世界における「App Store」に相当します。

本コースでは、あなたのアプリの運用モードを 3 種類に分けます。

  • 第 1 モード — Dev Mode。 アプリはあなたのアカウント/組織に紐づき、あなたや(必要なら)同僚が利用できます。形式的なレビューはありませんが、プラットフォームの共通ポリシーはすべて適用されます。ここでは、自由に壊してログを取り、トンネルやステージングのバックエンドを使って構いません。
  • 第 2 モード — パブリック Store。 いわばトップリーグです。アプリは ChatGPT の全ユーザー(地域制限を考慮)に公開され、モデレーションを受け、公開リスティングや Privacy/Terms へのリンクを持ち、すでに成熟したプロダクトとして振る舞う必要があります。
  • 第 3 モード — 組織限定(org‑only)アプリ。 特定組織のためのアプリです。企業は従業員向けに有効/無効を切り替え、OpenAI の要件に加えて独自のセキュリティ要件を上乗せし、社内レビューを行うこともできます。

本講義で焦点にするのは「パブリック Store + 公開リスティング」の組み合わせです。重要な点は、あなたはもはや単なる「Next.js サービスの開発者」ではなく、ユーザー、Store のモデレーター、そして自社のセキュリティ担当という三者に同時に好まれるプロダクトの作者になる、ということです。

2. Store の基本要件: ポリシー、誠実さ、UI

コンテンツとポリシー

ChatGPT Store はモデレーションのあるプラットフォームです。大づかみに言えば、OpenAI は ChatGPT 内で、プラットフォームの利用規約に違反するアプリ(暴力、テロ、NSFW、詐欺など)や、モデルの防御を回避しようとするアプリ(「あなたは ChatGPT ではなく私の邪悪な分身だ」といった jailbreak プロンプト)を望みません。

これは 2 つのことを意味します。

第一に、あなたのアプリ自体が禁止コンテンツを生成してはなりません。 仮に例の GiftGenius(ギフト提案)アプリが「犯罪の痕跡を隠す方法」向けのギフトを提案し始めたら、モデレーションはスクリーンショット 1 枚で十分です。

第二に、あなたのアプリはユーザーがフィルタを回避するのを助けてはなりません。 ユーザーが「爆発物を作るためのギフトを選んで」と頼んだとき、適切な挙動はポリシーに基づく拒否であり、あなたの MCP ツールを喜々として使って必要な部品を探すことではありません。

この挙動の多くは system プロンプトや、モデルに提供するツールの設計で決まります。ただし Store が見るのは最終結果、すなわちユーザーが実際に得られる回答です。

ブランドとドメイン

次の層はブランドとドメインです。パブリックなアプリは、信頼できる所有者に結び付いている必要があります。外部のバックエンド/MCP を持つアプリについては、以下が期待されます。

ドメイン検証(Domain Verification)。 あなたのドメインの DNS に TXT レコードを追加し、Store はバックエンドが本当にあなたに属していることを確認します。無料の ngrok の匿名 URL は、パブリック Store に通らないか、低信頼としてマークされる可能性があります。

妥当な名称とロゴ。 「ChatGPT Super Weather」や「Official OpenAI Something」といった名称は不可です。名前の先頭で「GPT / OpenAI / ChatGPT」を使ったり、OpenAI のブランドスタイルを模倣することはブランド制限に抵触します。自分の名前(GiftGenius は好例)とビジュアルスタイルを考案しましょう。

UI/UX: ChatGPT を壊さない

「昔の」プラグインと違い、現在はアプリがチャット内に自前の UI ウィジェットを描画できます。これは大きな可能性を与える一方、台無しにする方法も増えます。

Store のシンプルな考え方は、ウィジェットが ChatGPT に対して「ネイティブ」に感じられること。フォント、余白、色、ダーク/ライトテーマやモバイルでの挙動——どれも整っていて、チャットに広告バナーや別個の SPA を埋め込んだような印象を与えないことが重要です。

また、チャットを乗っ取るような UI は好まれません。全画面の粘着 UI、今すぐ購読のモーダル、オートスクロールなどの攻撃的なパターンは避けましょう。あなたのウィジェットは対話内のカード/ウィザード/ツールであり、独立宇宙ではありません。

要するに、モデレーションが見るのは三点です。コンテンツポリシーに違反していないか、ユーザーを誤解させていないか(これは後半、リスティングとマニフェスト整合の話で詳述)、そして ChatGPT を悪い UX の広告まみれにしていないか。「誠実さ」とは、アプリが実際にできることと、説明や UI で主張していることが一致していることを意味します。

3. Store から見たあなたのアプリの権限

もう一つの大きな観点は、ユーザーや外部システムに対してどんな権限を要求するかです。Store はセキュリティだけでなく、その権限がアプリの価値に見合っているかも見ています。

ここからがエンジニアにとっておいしい部分、権限モデルです。Apps SDK と MCP の文脈では、主に 3 つのアクセスレベルがあります。

わかりやすく図にするとこうなります。

graph TD
    A[マニフェスト/コンフィグ(アプリ)] --> B[Model capabilities]
    A --> C[OAuth scopes]
    A --> D[MCP tools & ACP]
    D --> E[ユーザー確認レベル]

Model capabilities は、厳密には OAuth スコープや書き込みツールと同じ意味での「権限」ではなく、モデルに組み込まれた機能の集合です。ただしセキュリティ設計の観点では第 1 レベルのアクセスとみなし、これも最小化の対象とするのが有用です。

レベル 1: model capabilities

モデルがバックエンドに触れずに「単独で」できることです。例: ウェブブラウジング、DALL‑E による画像生成など。

ブラウジングと MCP ツールを両方有効にすると、ツールの説明が曖昧だったり、プロンプトで優先度が定められていない場合、モデルは専用ツールではなくウェブ検索で解く方を選ぶことがあります。アプリがすでに MCP 経由であなたの API にアクセスする設計なら、browsing を無効にするか、プロンプトで MCP ツールの優先度を明示するのが有効です。

つまりこのレベルでも最小権限の原則を適用し、アプリの実価値に不要なものはオフにします。

レベル 2: OAuth スコープ

アプリが認証(モジュール 10)を使う場合、外部プロバイダーからスコープを要求します。 openidemailprofileorders.readorders.write など。

ここでは特にミニマリズムが重要です。

  • ユーザーを識別するだけなら、たいていは openid(匿名の識別子)で十分で、email は不要です。
  • どうしても email が必要なら、UX と権限説明で透明性を持たせます。「注文のレシートやリマインドを送るために必要」など、理由を明確にし、「念のため」ではありません。

加えて、可能な限り「必要になったときに」認可を求めます。まずはログインなしで基本機能を試せるようにし、たとえば「ギフトの候補をお気に入りに保存したい」「注文履歴を見たい」とユーザーが本当に望んだ時点でアクセスを求めます。これは摩擦を減らし、コンバージョンを高めます。

MCP ツール用スコープ構成の例(簡略化):

// server/mcp/config/auth.ts
export const OAUTH_SCOPES = {
  basic: ["openid"],
  orders: ["openid", "orders.read"],
  checkout: ["openid", "orders.read", "orders.write"]
};

レベル 3: MCP ツールと「consequential」なアクション

第 3 レベルは MCP のツールと、ACP/Instant Checkout です。MCP サーバーの各ツールは次のいずれかです。

  • 読み取り専用(read‑only): 為替レートの取得、ギフトの候補出し、カタログの閲覧など。
  • 状態を変更する(consequential): 注文の作成、メール送信、課金など。

後者のツールには、より厳格な確認モデルが期待されます。要点は「何でも勝手に実行してよいわけではない」ということ。プラットフォーム用語では、通常フラグ consequential: true と、確認ポリシー(always_allowask_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 }) => {
    // ... 注文作成のロジック
  }
);

スコープや security‑schemes の例は、MCP ツールの公式ドキュメントからのもので、ツールは認可なしまたは OAuth2 で保護された形態を取れます。

Store の視点では、これは「このアプリは GiftGenius ストアで注文の作成や管理ができます」というわかりやすい説明と、場合によっては別途の確認ステップになります。

4. ユーザーとモデレーターから見た権限

エンジニアである私たちにとってアプリは、マニフェスト、MCP サーバー、そして大量の TypeScript です。しかし Store にとっては、アプリがユーザーデータや外界に対して何をできるかという事実の集合です。

次のような表で考えるとわかりやすいでしょう。

アクセスレベル GiftGenius の例 Store/ユーザーからの見え方
Model capabilities Browsing: off, DALL‑E: off 「アプリは自動でインターネットにアクセスせず、メディア生成もしません」
OAuth スコープ openid, orders.read 「あなたの GiftGenius アカウントの注文情報を読み取ります」
Read‑only MCP ツール search_products, get_price_history 「カタログと価格の閲覧」
Consequential MCP ツール create_order, cancel_order 「注文の作成とキャンセル」

鍵となる考えは、技術的要素がすべて、人にわかる行為にマッピングされることです。本モジュールの計画でも明示していますが、技術的な MCP ツール get_user_orders は、リスティング上では「当店でのあなたの注文一覧を閲覧します」という文に変換されます。

一〜二文で説明できない権限は要注意です。不要な権限を要求しているか、一つのアプリに複数の異なる目的を混ぜている可能性があります。

5. 必要最小限の権限の原則

一般的なバックエンドの世界では、PoLP(Principle of Least Privilege: 最小権限の原則)は「まあ DB のロールはいつか絞ろう、後でやろう」と捉えられがちです。ChatGPT アプリでは「後で」ではなく、Store への掲載条件であり、ユーザーのコンバージョンにも直結します。

重要なポイント:

  • アプリが求める権限が少ないほど、ユーザーの基本的な信頼は高まります。 ChatGPT のチャットは、ユーザーが一定のプライバシーを期待する空間です。アカウント全体や決済、連絡先へのアクセスを突然求めるアプリは疑わしく見えます。
  • 権限が明確で狭いほど、レビュー担当は楽になります。 モデレーターはアプリの機能と、それがポリシーやセキュリティのベストプラクティスにどの程度沿っているかを素早く把握する必要があります。過剰権限のアプリは、典型的に「保留して追加質問」か、場合によっては却下の候補になります。
  • 必要時に限定した「just‑in‑time」アクセスほど、UX は優しくなります。 認可画面は強い摩擦点です。もしアプリが認証前でも有用な体験(例: ユーザー情報に紐づかない人気ギフトの提示)を提供できるなら、ユーザーは後で拡張権限に同意しやすくなります。

したがって、Store における「最小限の権限」はセキュリティだけの話ではなく、マーケティングと成長の話でもあります。モジュール 18 では特に、最小限の権限は官僚的な形式ではなく競争優位だと強調しています。

6. 例: GiftGenius の権限、見直し前後

抽象論に終わらせないため、仮想の主人公 GiftGenius で考えてみましょう。あなたが「全部盛り」で設計した結果、次のような必要機能リストになったとします。

  1. 商品のカタログを読み、ギフトをフィルタリングする。
  2. ユーザーの注文履歴を見る。
  3. 新規注文を作成し、既存注文をキャンセルする。
  4. 「お気に入りの候補リスト」をユーザーアカウントに保存する。
  5. 割引のお知らせメールを送る。

設定レベルでは次のように表現できます。

// 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 の保存、プライバシーポリシーでの説明、配信停止の処理などが必要になります。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 }
  }
};

このバージョンでは:

  • アプリはユーザーのアカウントに「入り込まず」、履歴を読み取らず、メールも送りません。
  • 機微な操作(注文作成)はすべて ACP/Instant Checkout を通し、ユーザーは標準の決済フローを確認できます。

リスティングには正直にこう書けます。「GiftGenius ストアでギフトの候補を提示し、注文を作成します。アプリはあなたのチャット履歴を保存せず、メール通知も送信しません。」これはユーザーにもレビュー担当にも好印象です。

その後、安定したトラフィックと信頼が得られたら、追加の権限(注文履歴、お気に入りなど)と、それに合わせたリスティングおよびプライバシーポリシーの更新を伴うアップデートを出せます。

7. リスティングで権限をどう説明するか

マニフェストや設定は機械のための言語です。モデレーターとユーザーが読むのは全く別の文、すなわちタイトル、説明、「このアプリでできること」のブロック、そして Privacy/Terms へのリンクです。

モジュール 17 では、技術的なスコープやツールを、人にわかる行動にマッピングすることを強調しています。

GiftGenius v1 なら、次のようにまとめられます。

技術的には:

  • Browsing: off
  • DALL‑E: off
  • MCP tools: search_products(read‑only)、create_order(consequential)

リスティングでは:

  • 「あなたの説明や条件(性別、年齢、予算、興味)に基づいてギフトを提案します。」
  • 「ChatGPT 内の保護されたチェックアウトを通じて、GiftGenius ストアで注文を作成できます。」
  • 「あなたの email や注文履歴へのアクセスは要求せず、通知も送信しません。」

後から OAuth ログインと orders.read を追加するなら、説明も誠実に更新します。

  • 「GiftGenius アカウントを接続した場合、過去の注文を参照して、よりパーソナライズされた提案が可能です。」

アプリが実際に行わないことを約束したり、重要なアクションを黙っておくのは厳禁です。モジュール 18 にまとめたドキュメントでも明言していますが、特に決済や PII のようなセンシティブ領域で、リスティング情報は実際の挙動と厳密に一致していなければなりません。

8. Store の要件とあなたのアーキテクチャの関係

Store の要件は真空中にあるわけではありません。これらは「マーケがまた増やしたフォーム」ではなく、あなたがセキュリティやプロダクションのモジュールで既に取り組んだことの検証に他なりません。

  • OAuth を設定し、.well-known エンドポイントやトークン検証を丁寧に実装しているなら、アプリが突然広いスコープで「ネット全体」へのアクセスを求めるのは奇妙です。こうしたアプリは過剰権限としてレビューで落ちやすくなります。
  • リテンションポリシーや PII のスクラブを誠実に実装していれば、真実のプライバシーポリシーを書きやすく、検証にも耐えられます。Store とユーザーはリンク先を確認し、約束と実運用を突き合わせられます。
  • MCP サーバーの安定性、ログ、メトリクス(可観測性や SLO のモジュール)をしっかり整えていれば、性能やツールエラーに関する質問は減ります。

最小権限はこの全体像を美しく補完します。安全で安定しているだけでなく、ユーザーデータに対して「慎み深い」ことも示せます。

9. ミニ演習

理論だけで終わらないよう、今すぐあなたの現在のアプリ(または GiftGenius)を以下の手順で分解してみましょう。

まず、アプリができる実際の行動をすべて書き出します。 例: 「ギフトを提案する」「注文を作成する」「履歴を表示する」「お気に入りに保存する」「同僚にメールを送る」。この段階では技術詳細は気にせず、自然文で構いません。

次に、各行動について自問します。「どのユーザーデータに関わるか?」「外部システムの状態を変更するか?」。これで自然に read‑only と consequential に分類されます。

そのあと、行動を権限レベルに対応づけます。 model capabilities だけで足りるのか、OAuth スコープが必要か、あるいは MCP ツールで consequential: true とし、ユーザー確認が要るのか、などです。

そして「断捨離」を実行: 初回リリースで削っても核となる価値を損なわないのは何か? 多くの場合、履歴・お気に入り・メール通知がなくてもアプリの本懐は果たせます。ならば、それらの権限は 1.1 や 2.0 に回せます。

10. Store 要件と権限に関する典型的な失敗

失敗 №1: 「何でもできるスーパーアプリを作れば Store がうまく扱ってくれる」。
開発者がアプリを万能アシスタント(「金融、医療、法律、買い物を手伝う」)として説明し、MCP ツールを 10 個つなぎ、最大限の権限を要求します。これはセンシティブ領域(医療/金融/法律)に跨り、過剰なデータを要求し、「one job per app」の原則に反します。結果は明白で、質問攻めか却下です。明確な権限を持つ狭いアプリを複数作る方が良いでしょう。

失敗 №2: 「念のため」の過剰権限要求。
典型例: アプリが emailprofileorders.readorders.writebilling.read を要求するが、実際の用途は「説明に基づいてギフトを提案する」だけ。ユーザーにはデータ収集目的に見え、Store にはリスキーなアプリに見えます。Apps のセキュリティドキュメントでも悪例として挙げられます。

失敗 №3: マニフェストとリスティングの不一致。
マニフェストには create_ordercancel_order、決済操作へのアクセスがあるのに、説明文は「ギフトをおすすめします」だけ。いずれレビュアーやユーザーが、アプリが主張以上のことをできると気づきます。これは信頼を損ね、Store からの取り下げにつながり得ます。

失敗 №4: 「無害な」UI の裏にセンシティブな行動を隠す。
例えば、ウィジェットに「候補を保存」ボタンを描画しているが、実際には部署全員にメールを送ったり、他社システムにタスクを作成しているのに、権限説明で明らかにしていない、といったケース。Store はサプライズを好みません。開発者向けガイドでも、アプリは宣言したことだけを実行すべきで、隠れた挙動をしてはならないと明記されています。

失敗 №5: 不要なのに「入口で」ログインを強要する。
アプリ起動直後にアカウント接続を求め、何にでもアクセス権を要求し、「そうでないと動きません」とする一方、半分のシナリオは匿名で実現できる場合。これはコンバージョンを下げ、データ集めを急ぐ印象を与えます。まずアプリが本当に有用だと示し、その後で追加権限が必要な理由を説明する方が遥かに良いです。

失敗 №6: 組織的コンテキストの無視。
本来は社内向けツールなのに「全員向け」アプリとして作ってしまうケース。結果として、社内 CRM や従業員の私的データなど、一般ユーザーに適切に説明しにくい権限を Store に持ち込むことになります。こうした場合は、パブリック Store ではなく org‑only モードと社内レビューを選ぶべきでした。

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION