UI Widgets
Agent skill:
nitrostack-python-ui-widgets
Python widgets are static HTML, not React trees from @nitrostack/widgets. Bind a route with @widget and return domain JSON from the tool.
from nitrostack import tool, widget, WidgetOptions, WidgetCsp, ExecutionContext
@tool(name="show_card", description="Product card", input_schema=CardInput)
@widget("card")
async def show_card(self, input: CardInput, context: ExecutionContext) -> dict:
return {"name": "Widget", "price": 9.99}
Place HTML at widgets/out/{route}.html (for example widgets/out/card.html). The SDK registers ui://widget/card.html and sets mode-gated _meta on tools/list and tools/call.
Object form:
@widget(WidgetOptions(
route="chart",
prefers_border=True,
csp=WidgetCsp(connect_domains=["https://api.example.com"]),
))
NITROSTACK_APP_MODE (default universal)
| Mode | Tool _meta | Resource MIME |
|---|---|---|
universal | Both OpenAI and MCP Apps keys | text/html;profile=mcp-app |
openai | openai/outputTemplate, ui/template | text/html |
mcp-app | _meta.ui (resourceUri, visibility, CSP) | text/html;profile=mcp-app |
Helpers: get_app_mode, is_openai_mode, is_mcp_app_mode, get_widget_mime_type.
Inspector and Studio
MCP Inspector: HTTP + stateless, Apps tab. Connect to http://localhost:3000/mcp (no trailing slash). Live preview: http://localhost:3000/widgets/preview. Do not use widgets/preview.html as the live result.
NitroStudio folder-connect looks for a TypeScript project (package.json with @nitrostack/core and src/index.ts). A Python server will not detect. Use Inspector HTTP or a custom Streamable HTTP URL. Turn Authentication off unless the OAuth template is configured.
There is no Python equivalent of the TypeScript Widget SDK / file-upload guides.