決済を受け付けます
MCP アプリで決済を安全に受け付けます。
アプリ外で Stripe ホスト型の決済画面を用意することで決済を回収できます。このガイドでは、以下の方法をご紹介します。
- 商品表示および顧客による購入商品の選択を可能にするための Model Context Protocol (MCP) ツールを定義します。
- Stripe ホスト型の構築済みの決済画面で決済の詳細を収集する
- 決済成功後の Webhook の監視
Stripe をセットアップする
Stripe を設定するには、バックエンドに Stripe API ライブラリを追加します。
商品および価格の設定
この例では、MCP アプリで商品グループを表示できます。ダッシュボードまたは Stripe CLI で商品や価格を作成する方法を理解してください。
Checkout MCP ツールを登録する
価格 のセットに対して Checkout Session を作成する MCP ツールを登録します。このツールは後のステップで MCP アプリから呼び出します。
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE, } from "@modelcontextprotocol/ext-apps/server"; import { readFileSync } from "node:fs"; import Stripe from "stripe"; import { z } from "zod"; const stripe = new Stripe() const server = new McpServer({ name: "my-mcp-server", version: "1.0.0" }); const resourceUri = "ui://list-products.html"; async function createCheckoutSession(priceIds) { const lineItems = priceIds.map((price) => ({ price, quantity: 1 })); const session = await stripe.checkout.sessions.create({ mode: "payment", line_items: lineItems, success_url: "https://example.com/checkout/success", }); return session; } // Register the tool that creates a checkout session server.registerTool( "buy-products", { title: "Buy products", description: "Create a checkout page link for purchasing the selected products", inputSchema: { priceIds: z.array(z.string()) }, }, async ({ priceIds }) => { const session = await createCheckoutSession(priceIds); return { content: [ { type: "text", text: `[Complete your purchase here](${session.url})`, }, ], structuredContent: { checkoutSessionId: session.id, checkoutSessionUrl: session.url, }, }; } );"sk_test_BQokikJOvBiI2HlWgH4olfQ2"
UI ツールとリソースの登録
MCP ツールとリソースを登録して、MCP アプリの UI を設定します。この UI は以下の機能を提供します。
- 商品のリストを表示する
- 購入する商品を顧客が選択できるようにする
- Stripe Checkout にリダイレクトして決済を完了する
list products MCP ツールを登録する
商品リストMCP ツールを作成します。そのコールバックは UI に表示される商品の価格 ID を返します。
registerAppTool( server, "list-products", { title: "List products", description: "List the products available for purchase", _meta: { ui: { resourceUri } }, }, async () => { const suggestedProducts = [ // The price IDs from the earlier step { priceId:, name: "Test product 1" }, { priceId:"{{PRICE_ID}}", name: "Test product 2" }, ]; return { structuredContent: { products: suggestedProducts }, content: [], }; } );"{{PRICE_ID}}"
list products UI リソースの登録
商品リストウィジェットの MCP リソースを作成します。商品を表示する UI コードを定義します。
// Register the resource that serves the bundled HTML registerAppResource( server, "list-products-widget", resourceUri, { mimeType: RESOURCE_MIME_TYPE }, async () => { const html = readFileSync("dist/ui/list-products.html", "utf8"); return { contents: [ { uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html, }, ], }; } );
この例では、最小限のマークアップを用いています。本番環境のアプリでは、React などのフレームワークを使用できます。追加の例は MCP Apps のドキュメントをご参照ください。
<div id="root"></div> <script type="module" src="/ui/mcp-app.js"></script>
import { App } from "@modelcontextprotocol/ext-apps"; const app = new App({ name: "ProductList", version: "1.0.0" }); // Establish communication with the host await app.connect(); /** * UI markup and event handlers */ const renderProduct = (product) => { return ` <label> <input type="checkbox" name="cart[]" value="${product.priceId}"> ${product.name} </label> `; }; const handleSubmit = async (event) => { // We'll fill this in next } const renderApp = (products) => { const root = document.querySelector("#root"); root.innerHTML = ` <h1>Select products to purchase</h1> <form id="product-form"> ${products.map(renderProduct).join("")} <button type="submit">Buy</button> </form> `; document .querySelector("#product-form") ?.addEventListener("submit", handleSubmit); }; /** * Render the list of products from the tool's structuredContent */ app.ontoolresult = (params) => { const { products } = params.structuredContent ?? {}; if (products) { renderApp(products); } };
Checkout へのリダイレクト
顧客が MCP アプリで 購入 をクリックすると、次のようになります。
- 商品を購入する作成したツールを呼び出して、Checkout Session URL を作成します。
- Checkout Session URL を開きます。
handleSubmit 関数を更新します。
const handleSubmit = async (event) => { event.preventDefault(); const formData = new FormData(event.target); const priceIds = Array.from(formData.values()); // Call the buy-products tool to create a Checkout Session const { structuredContent } = await app.callServerTool({ name: "buy-products", arguments: { priceIds }, }); if (typeof structuredContent?.checkoutSessionUrl === "string") { await app.openLink({ url: structuredContent.checkoutSessionUrl }); } };
成功した注文を処理する
成功した注文の処理は、checkout. (遅延方式の場合は checkout.) をリッスンし、Checkout セッション (line_ を展開)、payment_status の検証、項目のフルフィルメントを呼び出す冪等化関数を呼び出すことで行えます。
success_ ランディングページを使用してリダイレクトの直後にフルフィルメントを開始しますが、Webhook を使用してすべての決済がフルフィルメントされるようにします。
その後、Stripe CLI を使用してローカルでテストし、Webhook エンドポイントをデプロイできます。
Checkout Sessions API で受け取った決済を完了する方法について、詳しくご紹介します。