Introduction
ChatGPT has become second nature for billions of people. But historically, it has mainly focused on conversation, not interaction.
What if you could chat with apps directly inside ChatGPT such as booking hotels, designing slides, and more without ever leaving the conversation?
That’s now possible with ChatGPT Apps.
Powered by the new Apps SDK, developers can build interactive, context-aware apps that run natively inside ChatGPT.
In this tutorial, you’ll learn how to build your first ChatGPT app using FastApps.
We’ll walk through setup → development → deployment.
By the end, you’ll have an app that shows widgets directly inside ChatGPT.
How Do ChatGPT Apps Work?
A ChatGPT app is essentially an MCP server that serves widgets.
[High-level flow]
ChatGPT triggers your app based on user input.
The user message is forwarded to your app.
The app selects an MCP tool based on context.
Example: When a user asks, “I want to buy clothes,” your app may call a tool like ShowClothes.
The tool returns:
Widgets → UI components displayed in ChatGPT
Data → used in the response logic
This lets you create rich interfaces + logic without leaving the conversation.
Step 1: Install FastApps
Install FastApps with uv:
uv tool install fastapps
uv tool install --upgrade fastapps
Step 2: Initialize a New App
fastapps init my-app
cd my-app
fastapps dev
You’ll get a public URL via Cloudflare Tunnel.
Your MCP server lives at:
https://your-public-url.trycloudflare.com/mcp
Step 3: Test Your App
✅ Option A — MCPJam Inspector
npx @mcpjam/inspector@latest
Then enter:
/mcp
✅ Option B — Inside ChatGPT
Go to Settings → Connectors
Add your public MCP endpoint
Select No authentication
Step 4: Create More Widgets
Add new widgets anytime:
fastapps create additional-widget
Step 5: Edit Your Widget
You’ll mainly work inside two folders:
server/tools/
widgets/
1) MCP Tool — server/tools/
Defines backend logic + input schema.
# server/tools/my_widget_tool.py
from fastapps import BaseWidget, Field, ConfigDict
from pydantic import BaseModel
from typing import Dict, Any
class MyWidgetInput(BaseModel):
model_config = ConfigDict(populate_by_name=True)
name: str = Field(default="World")
class MyWidgetTool(BaseWidget):
identifier = "my-widget"
title = "My Widget"
input_schema = MyWidgetInput
invoking = "Processing..."
invoked = "Done!"
widget_csp = {
"connect_domains": [],
"resource_domains": []
}
async def execute(self, input_data: MyWidgetInput) -> Dict[str, Any]:
return {
"name": input_data.name,
"message": f"Hello, {input_data.name}!"
}
2) Widget UI — widgets/
React UI displayed inside ChatGPT.
// widgets/my-widget/index.jsx
import React from 'react';
import { useWidgetProps } from 'fastapps';
export default function MyWidget() {
const props = useWidgetProps();
return (
<div style={{
padding: '40px',
textAlign: 'center',
background: '#4A90E2',
color: 'white',
borderRadius: '12px'
}}>
<h1>{props.message}</h1>
<p>Welcome, {props.name}!</p>
</div>
);
}
Widgets support:
React + hooks
Tool interaction
Rich chat-native UI
Step 6: Deploy Your App
Deploy via CLI:
fastapps cloud deploy
Here’s a detailed guide on how to build ChatGPT apps.
Top comments (0)