feat: add dynamic resource template support#54
Conversation
- align template URI handling across node and python demos - add pizzaz toppings and detail tools returning parameterized widgets - inline dev/CDN asset handling with template metadata - update readme and env samples for SSR resource templates Fixes: openai#47
|
Hi @Obad94 How are you testing this? I gave it a try, and although I defined the resource template, it is never used by ChatGPT.
And at no point are ResourceTemplates called, but it is masked and may go unnoticed, because of the Resource resource which is identical to the ResourceTemplate. In my understanding this seems to be a limitation in the OpenAI/ChatGPT server side, or an intended limitation, and I would like input from @katia-openai, if nothing else at least where I should file a ticket to get an answer on this matter. |
|
@rinormaloku, in my implementation, the MCP server advertises templated URIs, returns Inspector proof and logsServer LogsList toolsnpx @modelcontextprotocol/inspector --cli https://1e1216949a29.ngrok-free.app/mcp \
--transport sse --method tools/listKey output: {
"name": "pizza-list",
"title": "Show Pizza List",
"_meta": {
"openai/outputTemplate": "ui://widget/pizza-list/{pizzaTopping}.html?v=dev-hgxti",
"openai/toolInvocation/invoking": "Hand-tossing a list",
"openai/toolInvocation/invoked": "Served a fresh list",
"openai/widgetAccessible": true,
"openai/resultCanProduceWidget": true,
"openai/outputTemplateSchema": {
"pizzaTopping": {
"type": "string",
"description": "Name of the topping to highlight in the list."
}
}
}
}Call the tool with a parameternpx @modelcontextprotocol/inspector --cli https://1e1216949a29.ngrok-free.app/mcp \
--transport sse \
--method tools/call \
--tool-name pizza-list \
--tool-arg pizzaTopping=mushroomResult: {
"_meta": {
"openai/outputTemplate": "ui://widget/pizza-list/{pizzaTopping}.html?v=dev-hgxti",
"openai/outputTemplateValues": { "pizzaTopping": "mushroom" },
"openai/outputTemplateResolved": "ui://widget/pizza-list/mushroom.html?v=dev-hgxti"
},
"content": [
{ "type": "text", "text": "Rendered a pizza list! Filtered by “mushroom”." }
],
"structuredContent": {
"pizzaTopping": "mushroom",
"availableToppings": [
"basil", "bianca", "burrata", "deep-dish", "detroit",
"four-cheese", "margherita", "marinara", "mozzarella",
"mushroom", "pepperoni", "prosciutto", "sausage",
"seasonal", "sourdough", "spinach", "truffle", "veggie", "white"
],
"filterApplied": true,
"requestedTopping": "mushroom"
}
}Read the resolved resourcenpx @modelcontextprotocol/inspector --cli https://1e1216949a29.ngrok-free.app/mcp \
--transport sse \
--method resources/read \
--uri ui://widget/pizza-list/mushroom.html?v=dev-hgxtiOutput: {
"contents": [
{
"uri": "ui://widget/pizza-list/mushroom.html?v=dev-hgxti",
"mimeType": "text/html+skybridge",
"_meta": {
"openai/outputTemplate": "ui://widget/pizza-list/{pizzaTopping}.html?v=dev-hgxti",
"openai/outputTemplateValues": { "pizzaTopping": "mushroom" },
"openai/outputTemplateResolved": "ui://widget/pizza-list/mushroom.html?v=dev-hgxti"
},
"text": "<div id=\"pizzaz-list-root\"></div>\n<link rel=\"stylesheet\" href=\"http://localhost:4444/pizzaz-list.css\">\n<script type=\"module\" src=\"http://localhost:4444/pizzaz-list.js\"></script>\n<script>window.__PIZZAZ_TEMPLATE_PARAMS__ = {\"pizzaTopping\":\"mushroom\"};</script>"
}
]
}Conclusion
|
Implements parametrized resource URIs for MCP widgets, enabling runtime template resolution and SSR-like functionality.
Changes
meta.openai/outputTemplate*fieldsHow it works
Tools can now return parametrized templates like
ui://widget/pizza-list/{pizzaTopping}that get resolved dynamically at runtime instead of being statically cached.Fixes #47