xmcp now supports building and serving UI resources compatible with OpenAI's Apps SDK. Get started by running:
npx create-xmcp-app --gpt
The --gpt
flag scaffolds a project with the necessary files and dependencies to get you up and running quickly.
Once your project is set up, you'll find two main folders. The prompts folder is excluded from this template by default, but you can easily enable it by modifying the xmcp.config.ts
file.
Resources
This folder contains your UI resources. The Apps SDK requires URI template paths to use the .html
extension. By setting mimeType: "text/html+skybridge"
, xmcp handles this automatically.
export const metadata: ResourceMetadata = {
name: "your-ui-resource",
title: "Show your UI resource",
mimeType: "text/html+skybridge",
};
Then, your handler can return the HTML content:
export default function handler() {
return `
<div>Hello, world!</div>
`;
}
This resource will be accessible at ui://widget/your-ui-resource.html
, corresponding to the folder structure (ui)/widget/your-ui-resource
.
For more information on constructing resource URIs, check out the resources documentation.
Tools
This folder contains your tools, which interact with and retrieve your UI resources.
The ToolMetadata
includes a _meta
property for adding Apps SDK-specific metadata, enabling your resources to be displayed within widgets.
Available metadata keys:
openai/outputTemplate
: Points to your resource URI template (required for discoverability)openai/widgetAccessible
: Boolean indicating if the resource is accessible within a widgetopenai/resultCanProduceWidget
: Boolean indicating if the tool result can produce a widgetopenai/widgetDescription
: Description displayed to the model when a client renders the componentopenai/widgetPrefersBorder
: Enables border rendering for widgets better suited to a "Card" layout
import { type ToolMetadata } from "xmcp";
const widgetMeta = {
"openai/outputTemplate": "ui://widget/your-ui-resource.html",
"openai/widgetAccessible": true,
"openai/resultCanProduceWidget": true,
};
export const metadata: ToolMetadata = {
name: "get-your-ui-resource",
description: "Show Your UI Resource",
_meta: {
...widgetMeta,
},
};
export default async function handler() {
return {
_meta: widgetMeta, // Required: return metadata in the response
};
}
If you're not returning content in the response, you can omit the content
array property and simply return the widget metadata.
References
For more details, see the OpenAI Apps SDK documentation. You can test your resources and tools using MCPJam, an open source MCP inspector.