### Quick Start Commands Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/README.md Commands to install dependencies and launch the server on port 8000. ```bash pnpm install # from repo root cd cards_against_ai_server_node pnpm start # builds widget + starts server on :8000 ``` -------------------------------- ### Install and run the MCP server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/kitchen_sink_server_node/README.md Commands to install dependencies and start the server from the repository root or the local folder. ```bash pnpm install pnpm --filter kitchen-sink-mcp-node start # or, from this folder: pnpm start ``` -------------------------------- ### Build and Run Development Servers Source: https://context7.com/openai/openai-apps-sdk-examples/llms.txt Commands for installing dependencies, building assets, and starting Node.js or Python servers. ```bash # Install dependencies pnpm install # Build widget assets (required before starting servers) pnpm run build # Generates HTML/JS/CSS in assets/ # Serve static assets (required for all servers) pnpm run serve # Serves assets at http://localhost:4444 # Run Node.js servers pnpm --filter pizzaz-mcp-node start # Pizzaz server pnpm --filter kitchen-sink-mcp-node start # Kitchen sink server # Run Python servers python -m venv .venv && source .venv/bin/activate pip install -r pizzaz_server_python/requirements.txt uvicorn pizzaz_server_python.main:app --port 8000 # Environment variables for tunneling (ngrok) export MCP_ALLOWED_HOSTS="your-endpoint.ngrok-free.app" export MCP_ALLOWED_ORIGINS="https://your-endpoint.ngrok-free.app" # Production deployment export BASE_URL=https://your-server.com export API_BASE_URL=https://your-api.example.com ``` -------------------------------- ### Setup and Run Shopping Cart Python Server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Set up a Python virtual environment, activate it, install requirements, and run the Shopping cart Python server using uvicorn. This example demonstrates using widgetSessionId to maintain state between tool calls. ```bash python -m venv .venv source .venv/bin/activate pip install -r shopping_cart_python/requirements.txt uvicorn shopping_cart_python.main:app --port 8000 ``` -------------------------------- ### Setup and Run Authenticated Python Server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Set up a Python virtual environment, activate it, install requirements, and run the Authenticated Python server using uvicorn. ```bash python -m venv .venv source .venv/bin/activate pip install -r authenticated_server_python/requirements.txt uvicorn authenticated_python_server.main:app --port 8000 ``` -------------------------------- ### Setup and Run Kitchen Sink Lite Python Server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Set up a Python virtual environment, activate it, install requirements, and run the Kitchen sink lite Python server using uvicorn. ```bash python -m venv .venv source .venv/bin/activate pip install -r kitchen_sink_server_python/requirements.txt uvicorn kitchen_sink_server_python.main:app --port 8000 ``` -------------------------------- ### Setup and Run Solar System Python Server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Set up a Python virtual environment, activate it, install requirements, and run the Solar system Python server using uvicorn. ```bash python -m venv .venv source .venv/bin/activate pip install -r solar-system_server_python/requirements.txt uvicorn solar-system_server_python.main:app --port 8000 ``` -------------------------------- ### Install and run the MCP server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/mcp_app_basics_node/README.md Commands to install dependencies and start the server. The server defaults to port 8000. ```bash pnpm install pnpm start # or change port: PORT=9000 pnpm start ``` -------------------------------- ### Setup and Run Pizzaz Python Server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Set up a Python virtual environment, activate it, install requirements, and run the Pizzaz Python server using uvicorn. ```bash python -m venv .venv source .venv/bin/activate pip install -r pizzaz_server_python/requirements.txt uvicorn pizzaz_server_python.main:app --port 8000 ``` -------------------------------- ### Install workspace dependencies Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Commands to initialize the development environment after cloning the repository. ```bash pnpm install pre-commit install ``` -------------------------------- ### Install and Run Python Server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/kitchen_sink_server_python/README.md Installs dependencies and runs the FastAPI server. Ensure Python 3.10+ is installed and static assets are built. ```bash python -m venv .venv source .venv/bin/activate pip install -r requirements.txt uvicorn kitchen_sink_server_python.main:app --port 8000 ``` -------------------------------- ### Install dependencies Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/shopping_cart_python/README.md Commands to set up the Python virtual environment and install required packages. ```bash python -m venv .venv source .venv/bin/activate pip install -r shopping_cart_python/requirements.txt ``` -------------------------------- ### Install Python Requirements (Bash) Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/authenticated_server_python/README.md Install the necessary Python packages for the server. Navigate into the server directory and activate the virtual environment before running this command. ```bash cd authenticated_server_python/ python -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` -------------------------------- ### Start Pizzaz Node Server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Navigate to the pizzaz_server_node directory and run this command to start the Pizzaz Node.js server. ```bash cd pizzaz_server_node pnpm start ``` -------------------------------- ### Install dependencies Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/pizzaz_server_node/README.md Install the required project dependencies using pnpm. ```bash pnpm install ``` -------------------------------- ### Run the server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/pizzaz_server_node/README.md Start the MCP server over SSE to enable tool discovery and invocation. ```bash pnpm start ``` -------------------------------- ### Start Kitchen Sink Lite Node Server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Run this command to start the Kitchen sink lite Node.js server using pnpm filters. ```bash pnpm --filter kitchen-sink-mcp-node start ``` -------------------------------- ### Install Dependencies (Bash) Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/solar-system_server_python/README.md Installs the necessary Python packages for the solar system MCP server. Ensure you have Python 3.10+ and a virtual environment activated. ```bash python -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` -------------------------------- ### Run Solar System Server (Bash) Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/solar-system_server_python/README.md Starts the FastAPI application using uvicorn. This command boots the server, making it accessible at http://127.0.0.1:8000. ```bash python main.py ``` -------------------------------- ### Start the MCP server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/shopping_cart_python/README.md Commands to launch the shopping cart MCP server using either the main script or uvicorn. ```bash python shopping_cart_python/main.py # or python -m uvicorn shopping_cart_python.main:app --host 0.0.0.0 --port 8000 ``` -------------------------------- ### Run MCP Server (Bash) Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/authenticated_server_python/README.md Start the MCP server using uvicorn. The server will listen on port 8000. ```bash uvicorn authenticated_server_python.main:app --port 8000 ``` -------------------------------- ### Start Game Tool Schema Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Schema for the 'start-game' tool, used to create a new game instance. It defines player structure, initial prompt, and introductory dialog. ```json { "players": [ { "id": "string", "name": "string", "type": "human" | "cpu", "persona": { ... }, "answerCards": [ { "id": "string", "type": "answer", "text": "string" } ] } ], "firstPrompt": "string", "introDialog": [ { "playerId": "string", "playerName": "string", "dialog": "string" } ] } ``` -------------------------------- ### Python MCP Server with FastMCP Source: https://context7.com/openai/openai-apps-sdk-examples/llms.txt Set up an MCP server using FastMCP to expose tools and widget resources. This server pattern handles tool registration, input validation, and returns structured content for widget hydration. Ensure FastMCP is installed. ```python from mcp.server.fastmcp import FastMCP from mcp.server.transport_security import TransportSecuritySettings import mcp.types as types from pydantic import BaseModel, Field # Initialize the MCP server mcp = FastMCP( name="my-app-server", stateless_http=True, transport_security=TransportSecuritySettings(enable_dns_rebinding_protection=False), ) # Define input schema with Pydantic class MyToolInput(BaseModel): message: str = Field(..., description="Message to display in the widget") accent_color: str = Field(default="#2d6cdf", alias="accentColor") # Register a tool that returns widget content @mcp.tool() async def my_tool( message: str = Field(..., description="Primary message to render"), accent_color: str = Field(default="#2d6cdf", alias="accentColor"), ) -> types.CallToolResult: return types.CallToolResult( content=[types.TextContent(type="text", text=f"Widget ready: {message}")], structuredContent={"message": message, "accentColor": accent_color}, _meta={ "openai/outputTemplate": "ui://widget/my-widget.html", "openai/toolInvocation/invoking": "Loading widget", "openai/toolInvocation/invoked": "Widget rendered", "openai/widgetAccessible": True, }, isError=False, ) # Register the widget HTML resource @mcp.resource("ui://widget/my-widget.html", "My Widget", mime_type="text/html+skybridge") async def widget_template() -> str: return "" # Create the ASGI app app = mcp.streamable_http_app() # Run with: uvicorn main:app --port 8000 ``` -------------------------------- ### Setup MCP Server with SSE Transport Source: https://context7.com/openai/openai-apps-sdk-examples/llms.txt Initializes an MCP server using the official TypeScript SDK and configures an HTTP server for SSE transport. Requires the @modelcontextprotocol/sdk package. ```typescript import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import { CallToolRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, type Tool, } from "@modelcontextprotocol/sdk/types.js"; import { z } from "zod"; import { createServer } from "node:http"; // Define tools with metadata for widget binding const tools: Tool[] = [ { name: "my-tool", title: "My Tool", description: "Renders a custom widget", inputSchema: { type: "object", properties: { message: { type: "string", description: "Message to display" }, }, required: ["message"], }, _meta: { "openai/outputTemplate": "ui://widget/my-widget.html", "openai/toolInvocation/invoking": "Loading widget", "openai/toolInvocation/invoked": "Widget ready", "openai/widgetAccessible": true, }, annotations: { destructiveHint: false, openWorldHint: false, readOnlyHint: true, }, }, ]; function createMcpServer(): Server { const server = new Server( { name: "my-server", version: "0.1.0" }, { capabilities: { resources: {}, tools: {} } } ); server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools })); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { message } = z.object({ message: z.string() }).parse(request.params.arguments ?? {}); return { content: [{ type: "text", text: `Widget ready with message: ${message}` }], structuredContent: { message, timestamp: new Date().toISOString() }, _meta: { "openai/toolInvocation/invoking": "Loading", "openai/toolInvocation/invoked": "Ready", }, }; }); server.setRequestHandler(ReadResourceRequestSchema, async () => ({ contents: [ { uri: "ui://widget/my-widget.html", mimeType: "text/html+skybridge", text: widgetHtml, }, ], })); return server; } // HTTP server with SSE transport const httpServer = createServer(async (req, res) => { if (req.method === "GET" && req.url === "/mcp") { res.setHeader("Access-Control-Allow-Origin", "*"); const server = createMcpServer(); const transport = new SSEServerTransport("/mcp/messages", res); await server.connect(transport); } }); httpServer.listen(8000, () => console.log("MCP server on http://localhost:8000")); ``` -------------------------------- ### Configure Allowed Hosts and Origins for ngrok Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Before starting a Python server when using ngrok, set these environment variables to allow your tunnel host. Replace .ngrok-free.app with your actual ngrok endpoint. ```bash export MCP_ALLOWED_HOSTS=".ngrok-free.app" export MCP_ALLOWED_ORIGINS="https://.ngrok-free.app" ``` -------------------------------- ### start-game Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Initializes a new game instance, generating players, answer cards, and the first prompt. ```APIDOC ## start-game ### Description Creates a new game instance with 1 human and 3 CPU players, distributing 7 answer cards to each. ### Request Body - **players** (array) - Required - List of player objects including ID, name, type, persona, and initial answer cards. - **firstPrompt** (string) - Required - The initial prompt card text. - **introDialog** (array) - Required - Role-played introductions from CPU characters. ``` -------------------------------- ### Serve Widget Assets (Bash) Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/authenticated_server_python/README.md Build and serve the widget assets required for the UI. This command should be run from the root of the project directory. ```bash pnpm run build pnpm run serve ``` -------------------------------- ### Serve static assets Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/shopping_cart_python/README.md Command to serve the static assets from the repository root. ```bash pnpm run serve ``` -------------------------------- ### Build Components Gallery Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Run this command to build the standalone assets for the components gallery. These assets include versioned .html, .js, and .css files. ```bash pnpm run build ``` -------------------------------- ### Launch Vite Dev Server Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Use this command to iterate on components locally by launching the Vite development server. ```bash pnpm run dev ``` -------------------------------- ### Configure MCP Server Environment Variables Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/README.md Set these variables in your deployment environment to enable static asset hosting and correct API URL resolution. ```text BASE_URL=https://your-server.com API_BASE_URL=https://your-api.example.com ``` -------------------------------- ### Tunnel with ngrok (Bash) Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/authenticated_server_python/README.md Expose the local server to the public internet using ngrok. This is necessary for ChatGPT to access the server. After running, update the RESOURCE_SERVER_URL in your .env file with the provided ngrok URL. ```bash ngrok http 8000 ``` -------------------------------- ### Ngrok Deployment Commands Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/README.md Commands to expose the local server to the internet using ngrok for external access. ```bash echo 'BASE_URL=https://your-domain.ngrok.app' > .env.local # in repo root ngrok http 8000 --domain your-domain.ngrok.app cd cards_against_ai_server_node && pnpm start ``` -------------------------------- ### Manage Host Capabilities and Display Modes in React Source: https://context7.com/openai/openai-apps-sdk-examples/llms.txt Use the useApp hook to query host context and request display mode changes. Ensure display mode transitions are triggered by user actions. ```tsx import { useApp, useDocumentTheme } from "@modelcontextprotocol/ext-apps/react"; import { useState } from "react"; export default function DisplayModeWidget() { const [displayMode, setDisplayMode] = useState("inline"); const theme = useDocumentTheme(); const { app } = useApp({ onAppCreated: (app) => { // Listen for context changes (theme, display mode, dimensions) app.onhostcontextchanged = (ctx) => { setDisplayMode(ctx.displayMode); }; }, }); // Query static capabilities (set once at connection) const capabilities = app?.getHostCapabilities(); // capabilities.openLinks, capabilities.serverTools, capabilities.message, etc. // Query dynamic context const context = app?.getHostContext(); // context.theme, context.displayMode, context.locale, context.containerDimensions // Request display mode change (must be from user-initiated action) const goFullscreen = async () => { const result = await app.requestDisplayMode({ mode: "fullscreen" }); console.log("Granted mode:", result.mode); // May differ from requested }; // Open external URL (host may deny based on security policy) const openDocs = async () => { const result = await app.openLink({ url: "https://example.com" }); if (result.isError) { console.log("Link denied by host"); } }; return (

Theme: {theme}

Display Mode: {displayMode}

); } ``` -------------------------------- ### Implement OAuth-Protected Tools in Python Source: https://context7.com/openai/openai-apps-sdk-examples/llms.txt Define security schemes in tool metadata and handle authentication challenges by returning the mcp/www_authenticate meta field when tokens are missing. ```python # Security schemes for tool metadata OAUTH_SECURITY_SCHEMES = [{"type": "oauth2", "scopes": []}] MIXED_SECURITY_SCHEMES = [{"type": "noauth"}, {"type": "oauth2", "scopes": []}] @mcp._mcp_server.list_tools() async def _list_tools() -> List[types.Tool]: return [ types.Tool( name="see_past_orders", title="See past orders", description="Returns past orders (OAuth required)", inputSchema={"type": "object", "properties": {}}, securitySchemes=OAUTH_SECURITY_SCHEMES, # OAuth only _meta={"openai/outputTemplate": "ui://widget/orders.html"}, ), types.Tool( name="search_public", title="Public search", description="Search without auth, enhanced with auth", inputSchema={"type": "object", "properties": {}}, securitySchemes=MIXED_SECURITY_SCHEMES, # Both allowed ), ] async def _call_tool_request(req: types.CallToolRequest) -> types.ServerResult: if req.params.name == "see_past_orders": # Check for bearer token token = _get_bearer_token_from_request() if not token: return types.ServerResult( types.CallToolResult( content=[types.TextContent(type="text", text="Auth required")], _meta={ "mcp/www_authenticate": [ 'Bearer error="invalid_request", ' f'resource_metadata="{PROTECTED_RESOURCE_METADATA_URL}"' ] }, isError=True, ) ) # Process authenticated request return types.ServerResult( types.CallToolResult( content=[types.TextContent(type="text", text="Orders retrieved")], structuredContent={"orders": [...]}, ) ) ``` -------------------------------- ### Widget to Server Tool Call Source: https://context7.com/openai/openai-apps-sdk-examples/llms.txt Enables widgets to call MCP tools directly without model involvement. Use `visibility: ["app"]` for app-only tools that the model cannot see. ```tsx import { useApp } from "@modelcontextprotocol/ext-apps/react"; import { useState } from "react"; export default function DiceRollerWidget() { const [result, setResult] = useState(null); const [error, setError] = useState(null); const { app } = useApp({ onAppCreated: (app) => { app.ontoolresult = () => {}; // Widget ready }, }); const rollDice = async (sides: number) => { try { // Call an app-only tool directly from the widget const response = await app.callServerTool({ name: "roll_dice", // Tool with visibility: ["app"] arguments: { sides }, }); if (response.isError) { setError("Roll failed"); } else { const data = JSON.parse(response.content[0].text); setResult(data.rolled); } } catch (err) { setError(err instanceof Error ? err.message : "Unknown error"); } }; return (
{result &&

You rolled: {result}

} {error &&

{error}

}
); } // Server-side: Register app-only tool (invisible to model) // registerAppTool(server, "roll_dice", { // inputSchema: { sides: z.number() }, // _meta: { ui: { visibility: ["app"] } }, // App-only // }, async ({ sides }) => { // const rolled = Math.floor(Math.random() * sides) + 1; // return { content: [{ type: "text", text: JSON.stringify({ rolled }) }] }; // }); ``` -------------------------------- ### play-cpu-answer-cards Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Submits card selections for CPU players. ```APIDOC ## play-cpu-answer-cards ### Description Submits CPU player card selections based on persona and hand context. ### Request Body - **gameId** (string) - Required - Unique identifier for the game. - **cpuAnswerChoices** (array) - Required - List of objects containing playerId, cardId, and playerComment. ``` -------------------------------- ### Develop React Widgets with useApp Hook Source: https://context7.com/openai/openai-apps-sdk-examples/llms.txt Creates a React component that consumes tool results and integrates with host styles. Requires @modelcontextprotocol/ext-apps/react. ```tsx import { useApp, useHostStyles, useDocumentTheme } from "@modelcontextprotocol/ext-apps/react"; import { useState } from "react"; interface ToolResult { message: string; timestamp: string; } export default function MyWidget() { const [data, setData] = useState(null); const [isReady, setIsReady] = useState(false); const { app } = useApp({ onAppCreated: (app) => { // Receive structured content from tool response app.ontoolresult = (result) => { setData(result.structuredContent as ToolResult); setIsReady(true); }; // Optional: handle streaming tool input app.ontoolinputpartial = (params) => { console.log("Partial args:", params.arguments); }; }, }); // Apply host theme CSS variables useHostStyles(app, app?.getHostContext()); const theme = useDocumentTheme(); // "light" | "dark" if (!isReady) { return
Loading...
; } return (

{data?.message}

Generated at: {data?.timestamp}

Theme: {theme}

); } ``` -------------------------------- ### Environment Variables Configuration Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/authenticated_server_python/README.md Set up environment variables for the authorization and resource server URLs. These are crucial for the OAuth flow and server communication. ```env AUTHORIZATION_SERVER_URL=https://your-domain.example.com RESOURCE_SERVER_URL=https://your-domain.example.com/mcp ``` -------------------------------- ### submit-prompt Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Provides the next round's prompt and replacement cards for players. ```APIDOC ## submit-prompt ### Description Advances the game by providing a new prompt and replenishing player hands. ### Request Body - **gameId** (string) - Required - Unique identifier for the game. - **promptText** (string) - Required - Text for the new prompt card. - **replacementCards** (array) - Required - List of objects mapping playerId to the new answer card. ``` -------------------------------- ### Format CPU TextContent Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Use this markdown format to display role-played quips or announcements from CPU characters during tool responses. ```markdown **Brenda the Soccer Mom** slaps down a card: "Oh, this one's going to get me banned from the PTA." **Dave from IT** carefully places his card: "Statistically, this has a 23% chance of being funny." ``` -------------------------------- ### Play CPU Answer Cards Tool Schema Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Schema for the 'play-cpu-answer-cards' tool, used to submit CPU player card selections. It includes game ID and an array of CPU player choices with their selected card IDs and optional comments. ```json { "gameId": "string", "cpuAnswerChoices": [ { "playerId": "string", "cardId": "string", "playerComment": "string" } ] } ``` -------------------------------- ### Game Loop Flow Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/src/cards-against-ai/DESIGN.md Illustrates the sequence of events and tool calls in the Cards Against AI game loop, from human interaction to LLM actions and state updates via SSE. ```text Human clicks answer card → widget calls callServerTool("play-answer-card") → server updates state → SSE pushes → if nextAction.notifyModel: widget sends sendMessage → LLM calls play-cpu-answer-cards → SSE pushes → if nextAction is cpu-judge-answer-card: LLM calls cpu-judge-answer-card → SSE pushes → if nextAction is human-judge-pending: widget shows judge UI (via SSE state) Human judges card → widget calls callServerTool("judge-answer-card") → server updates state → SSE pushes → if nextAction.notifyModel: widget sends sendMessage (currently no cases, but future-proof) Human clicks "Next Round" → widget sends sendMessage("Call submit-prompt for gameId=...") → LLM calls submit-prompt → server updates state → SSE pushes ``` -------------------------------- ### Submit Prompt Tool Schema Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Schema for the 'submit-prompt' tool, used to provide the next round's prompt and replacement cards. Includes game ID, prompt text, and an array of replacement cards for players. ```json { "gameId": "string", "promptText": "string", "replacementCards": [ { "playerId": "string", "card": { "id": "string", "type": "answer", "text": "string" } } ] } ``` -------------------------------- ### Play Answer Card Tool Schema Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Schema for the 'play-answer-card' tool, used when a human player submits an answer card. Requires game ID, player ID, and the chosen card ID. ```json { "gameId": "string", "playerId": "string", "cardId": "string" } ``` -------------------------------- ### CPU Judge Answer Card Tool Schema Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Schema for the 'cpu-judge-answer-card' tool, used by a CPU judge to submit their verdict. Requires game ID, the winning card ID, and a reaction to the winning card. ```json { "gameId": "string", "winningCardId": "string", "reactionToWinningCard": "string" } ``` -------------------------------- ### Widget State Persistence Source: https://context7.com/openai/openai-apps-sdk-examples/llms.txt Maintains widget state across tool calls using `widgetSessionId`. The state is persisted by the host and restored when the widget reloads. ```python # Server-side: Include widgetSessionId in tool response async def _handle_call_tool(req: types.CallToolRequest) -> types.ServerResult: cart_id = req.params.arguments.get("cartId") or uuid4().hex items = req.params.arguments.get("items", []) meta = { "openai/outputTemplate": "ui://widget/shopping-cart.html", "openai/widgetAccessible": True, "openai/widgetSessionId": cart_id, # Enables state persistence } return types.ServerResult( types.CallToolResult( content=[types.TextContent(type="text", text=f"Cart {cart_id} updated")], structuredContent={"cartId": cart_id, "items": items}, _meta=meta, ) ) ``` ```tsx // Widget-side: Use widgetState hook for persistent state import { useEffect, useState } from "react"; function useWidgetState(initialState: T): [T, (updater: (prev: T) => T) => Promise] { const [state, setState] = useState(() => { return (window.openai?.widgetState as T) ?? initialState; }); const setWidgetState = async (updater: (prev: T) => T) => { const next = updater(state); setState(next); await window.openai?.setWidgetState?.(next); }; return [state, setWidgetState]; } // Usage in component function ShoppingCart() { const toolOutput = window.openai?.toolOutput; const [cartState, setCartState] = useWidgetState({ items: [] }); useEffect(() => { // Merge incoming tool output with existing widget state if (toolOutput?.items) { setCartState((prev) => ({ ...prev, items: [...prev.items, ...toolOutput.items], })); } }, [toolOutput]); const addItem = (name: string) => { setCartState((prev) => ({ ...prev, items: [...prev.items, { name, quantity: 1 }], })); }; return (
{cartState.items.map((item) => (
{item.name}: {item.quantity}
))}
); } ``` -------------------------------- ### cpu-judge-answer-card Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Submits the verdict when a CPU player is the judge. ```APIDOC ## cpu-judge-answer-card ### Description Submits the CPU judge's winning selection and reaction. ### Request Body - **gameId** (string) - Required - Unique identifier for the game. - **winningCardId** (string) - Required - ID of the winning answer card. - **reactionToWinningCard** (string) - Required - The judge's reaction text. ``` -------------------------------- ### Define CPU Persona Schema Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md This JSON structure is required to define CPU character attributes, including personality, preferences, and behavioral traits. ```json { "id": "string", "name": "string", "personality": "string", "likes": ["string"], "dislikes": ["string"], "humorStyle": ["string"], "favoriteJokeTypes": ["string"], "catchphrase": "string (optional — signature phrase)", "quirks": ["string (optional — behavioral tics)"], "backstory": "string (optional — 1-2 sentence background)", "voiceTone": "string (optional — e.g. 'sarcastic', 'deadpan')", "competitiveness": "number 1-10 (optional — trash-talk intensity)" } ``` -------------------------------- ### play-answer-card Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Allows the human player to submit an answer card from their hand. ```APIDOC ## play-answer-card ### Description Submits an answer card selection for the human player. ### Request Body - **gameId** (string) - Required - Unique identifier for the game. - **playerId** (string) - Required - ID of the human player. - **cardId** (string) - Required - ID of the selected answer card. ``` -------------------------------- ### Sending Messages from Widget to Conversation Source: https://context7.com/openai/openai-apps-sdk-examples/llms.txt Widgets can inject messages into the conversation or silently update model context using `sendMessage` and `updateModelContext`. ```tsx import { useApp } from "@modelcontextprotocol/ext-apps/react"; export default function MessageWidget() { const { app } = useApp({ onAppCreated: (app) => {} }); // Send a visible message that triggers model response const sendMessage = async () => { const result = await app.sendMessage({ role: "user", content: [{ type: "text", text: "User clicked the widget button!" }], }); if (result.isError) { console.error("Failed to send message"); } }; // Silently update model context (deferred, last-write-wins) const updateContext = async () => { await app.updateModelContext({ content: [{ type: "text", text: "User preference: dark mode enabled" }], }); // Context will be included in the model's next turn }; return (
); } ``` -------------------------------- ### Judge Answer Card Tool Schema Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Schema for the 'judge-answer-card' tool, used by a human judge to select the winning answer card. Requires game ID, player ID, and the winning card ID. ```json { "gameId": "string", "playerId": "string", "winningCardId": "string" } ``` -------------------------------- ### judge-answer-card Source: https://github.com/openai/openai-apps-sdk-examples/blob/main/cards_against_ai_server_node/RULES.md Allows the human judge to select the winning answer card for the round. ```APIDOC ## judge-answer-card ### Description Submits the human judge's choice for the winning card. ### Request Body - **gameId** (string) - Required - Unique identifier for the game. - **playerId** (string) - Required - ID of the human judge. - **winningCardId** (string) - Required - ID of the winning answer card. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.