-
Couldn't load subscription status.
- Fork 1.4k
first class support for apps sdk #2210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| assert resource.meta is not None | ||
| assert "openai/widgetCSP" in resource.meta | ||
| csp = resource.meta["openai/widgetCSP"] | ||
| assert "https://custom.com" in csp["resource_domains"] |
Check failure
Code scanning / CodeQL
Incomplete URL substring sanitization High test
https://custom.com
| assert "openai/widgetCSP" in resource.meta | ||
| csp = resource.meta["openai/widgetCSP"] | ||
| assert "https://custom.com" in csp["resource_domains"] | ||
| assert "https://another.com" in csp["resource_domains"] |
Check failure
Code scanning / CodeQL
Incomplete URL substring sanitization High test
https://another.com
Copilot Autofix
AI 6 days ago
Copilot could not generate an autofix suggestion
Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.
| csp = resource.meta["openai/widgetCSP"] | ||
| assert "https://custom.com" in csp["resource_domains"] | ||
| assert "https://another.com" in csp["resource_domains"] | ||
| assert "wss://websocket.com" in csp["connect_domains"] |
Check failure
Code scanning / CodeQL
Incomplete URL substring sanitization High test
wss://websocket.com
Copilot Autofix
AI 6 days ago
Copilot could not generate an autofix suggestion
Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a nice UI! Since the changes supporting meta should land in the sdk tomorrow, I have a small suggestion on response type payloads.
|
|
||
| from typing import Any | ||
|
|
||
| WidgetToolResponse = dict[str, Any] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to introduce this as a dataclass/pydantic from the beginning? Support for _meta fields will land in the python sdk tomorrow and that's part of what's necessary to support openai's full protocol. I think string|dict|WidgetToolResponse could make a lot of sense instead of extending the tuple or supporting different return types. Something like a simpler version of the CallToolResult like:
class WidgetToolResponse(BaseModel)
content: str
structured_content: dict[str, Any] | None = None
meta: dict[str, Any] | None = None|
Nice! Welcome your feedback. Lay it on me! |
|
Just PR'd #2283 to hopefully make meta usage simpler! |
Add native OpenAI widget support
FastMCP now provides first-class support for OpenAI's ChatGPT widgets through the
@app.ui.openai.widgetdecorator. Previously, developers had to manually manage widget HTML resources, construct OpenAI-specific metadata, and transform return values to match OpenAI's{"content": [...], "structuredContent": {...}}wire format. This PR eliminates that boilerplate entirely—just decorate your function and return astr,dict, ortuple[str, dict], and FastMCP handles the rest.The decorator automatically registers widget HTML as an MCP resource, injects OpenAI metadata (CSP policies, widget templates, invocation status messages), and wraps your function to auto-transform its return value. You write clean Python functions that return natural data types, and the framework translates them to OpenAI's format behind the scenes.
The decorator follows FastMCP's existing conventions, using
name=(consistent with@app.tool(name=...)) and exposing all customization points:widget_description,widget_csp_resources,widget_csp_connect,widget_prefers_border, and more. Smart defaults handle the common cases—for instance,widget_descriptiondefaults to"{title} widget UI."when not specified.This makes OpenAI widgets feel like a natural extension of FastMCP's tool system rather than a separate SDK layer. See
examples/widget_test/for three working patterns showing dict-only, string-only, and combined return types.Resolves #2014
🤖 Generated with Claude Code