From 91da273efe08b98761e861aa8128e1e8941badba Mon Sep 17 00:00:00 2001 From: "R.V.Guha" Date: Mon, 22 Jun 2026 13:24:00 -0700 Subject: [PATCH] spec: switch interactive UI output from ChatGPT Apps to MCP Apps Replaces the chatgpt_app response_format with mcp_app, conforming to the MCP Apps extension (io.modelcontextprotocol/ui): - response_format: chatgpt_app -> mcp_app - structuredData (array) -> structuredContent (object with a results array) - _meta openai/outputTemplate + openai/widgetAccessible -> _meta.ui.resourceUri referencing a ui:// resource (fetched via resources/read over MCP; resolvable URL over HTTP transport) Mirrors the same edits into the rendered docs page (app/docs/specification/page.mdx) and notes the migration in the changelog. Co-Authored-By: Claude Opus 4.8 --- NLWEBSPEC.md | 52 ++++++++++++++++++--------------- app/docs/specification/page.mdx | 52 ++++++++++++++++++--------------- 2 files changed, 58 insertions(+), 46 deletions(-) diff --git a/NLWEBSPEC.md b/NLWEBSPEC.md index b62cf13..7b90749 100644 --- a/NLWEBSPEC.md +++ b/NLWEBSPEC.md @@ -111,7 +111,7 @@ Example: { "prefer": { "streaming": false, - "response_format": "chatgpt_app", + "response_format": "mcp_app", "mode": "list, summarize", "accept-language": "en", "user-agent": "Copilot/1.0.0" @@ -124,7 +124,7 @@ Example: We expect a wide range of clients to call NLWeb agents — from chatbots to site search interfaces to data analytics tools. Different output structures may be suitable for different clients. The set of possible response_format values is open-ended and extensible. This specification defines two formats: * conversational_search (default): Returns results in the Conversational Search result structure (see 4.1.1). -* chatgpt_app: Returns results in the ChatGPT App result structure (see 4.1.1), conforming to the ChatGPT Apps SDK. +* mcp_app: Returns results in the MCP Apps result structure (see 4.1.1), conforming to the MCP Apps extension ([io.modelcontextprotocol/ui](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx)). NLWeb agents may support additional formats. A client may specify the formats it can accept, and the NLWeb agent chooses the best match. @@ -187,12 +187,12 @@ Convention: Request metadata uses the attribute name meta. Response metadata use Metadata about the response. * response_type (string, required): One of "answer", "elicitation", "promise", or "failure". -* response_format (string, optional): The response format of the answer (e.g., "conversational_search", "chatgpt_app"). +* response_format (string, optional): The response format of the answer (e.g., "conversational_search", "mcp_app"). * version (string, required): API version number. * session_context (object, optional): Context object which can include attribute-value pairs that need to be included in future calls to the NLWeb agent. * Response format-specific fields such as: - * openai/outputTemplate (string): For ChatGPT Apps SDK — URI of the widget template. - * openai/widgetAccessible (boolean): For ChatGPT Apps SDK — whether the widget can make tool calls. + * ui (object): For the MCP Apps extension. Associates the result with a UI resource used to render it. Contains: + * resourceUri (string): URI of the UI resource (the rendering template), using the `ui://` scheme (e.g., "ui://recipe-server/recipe-widget"). Over MCP transport, the host retrieves the template via `resources/read`. Over HTTP transport, the URI MUST be resolvable by the client to a UI resource served as `text/html;profile=mcp-app`. * Other protocol-specific metadata as needed. ### 4.1 Response Content @@ -201,7 +201,7 @@ The result structure is a function of the response_type. The following subsectio #### 4.1.1 Answer -Though we expect to allow different structures for the content, as specified by the response_format in the request, we expect most answers to be an array of JSON objects, each encoding some semi-structured information. In some cases, as with ChatGPT apps, the structured and unstructured portions may be broken out into separate sections. +Though we expect to allow different structures for the content, as specified by the response_format in the request, we expect most answers to be an array of JSON objects, each encoding some semi-structured information. In some cases, as with MCP Apps, the structured and unstructured portions may be broken out into separate sections. This specification defines two result structures. @@ -246,25 +246,28 @@ Example: } ``` -**ChatGPT App Result Structure** +**MCP Apps Result Structure** -This structure conforms to the structure specified for ChatGPT apps. The main differences from Conversational Search are: +This structure conforms to the MCP Apps extension ([io.modelcontextprotocol/ui](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx)), which standardizes how a result is paired with an interactive UI. The main differences from Conversational Search are: -1. content (array, required): Used for natural language descriptions of the result, meant for consumption by the chatbot's LLM. An array of JSON objects, each with: +1. content (array, required): Used for natural language descriptions of the result, meant for consumption by the host's model and by text-only hosts. An array of JSON objects, each with: * type (string): The value "text". * text (string): A natural language description of the results. -2. structuredData (array, required): An array of typed semi-structured JSON objects, following the same item schema as results in the Conversational Search structure. +2. structuredContent (object, required): Structured data optimized for UI rendering (and not added to the model's context). NLWeb places the typed semi-structured items under a results array, where each item follows the same item schema as results in the Conversational Search structure. + +The UI resource used to render the result is referenced from `_meta.ui.resourceUri` (see the _meta section above). Example: ```json { "_meta": { "response_type": "answer", - "response_format": "chatgpt_app", + "response_format": "mcp_app", "version": "0.55", - "openai/outputTemplate": "https://example.com/recipe-widget", - "openai/widgetAccessible": true + "ui": { + "resourceUri": "ui://recipe-server/recipe-widget" + } }, "content": [ { @@ -272,15 +275,17 @@ Example: "text": "Here are protein-rich pumpkin recipes with cinnamon..." } ], - "structuredData": [ - { - "@type": "Recipe", - "name": "Pumpkin spice with coconut", - "description": "....", - "recipeIngredient": ["..."], - "cookTime": "PT30M" - } - ] + "structuredContent": { + "results": [ + { + "@type": "Recipe", + "name": "Pumpkin spice with coconut", + "description": "....", + "recipeIngredient": ["..."], + "cookTime": "PT30M" + } + ] + } } ``` @@ -1033,7 +1038,8 @@ Checking on the promise with await: * Elicitation question types enumerated: single_select, multi_select, free_text, number, boolean. * Error codes enumerated: NO_RESULTS, INVALID_QUERY, UNSUPPORTED_FORMAT, UNSUPPORTED_MODE, RATE_LIMITED, INTERNAL_ERROR, TIMEOUT, TOKEN_LIMIT. * Summary items in Conversational Search results given a recommended @type of SearchSummary. -* response_format values documented: conversational_search (default) and chatgpt_app. +* response_format values documented: conversational_search (default) and mcp_app. +* Interactive UI output migrated from the ChatGPT Apps SDK structure to the MCP Apps extension (io.modelcontextprotocol/ui): response_format chatgpt_app replaced by mcp_app, structuredData (array) replaced by structuredContent (object with a results array), and the openai/outputTemplate and openai/widgetAccessible meta fields replaced by _meta.ui.resourceUri referencing a ui:// resource. * User object in meta clarified as accepting either a string or structured object. * Authentication, authorization, and rate limiting explicitly scoped as transport-layer concerns (Sections 2.4, 2.5). * HTTP status code guidance added (Section 7.4). diff --git a/app/docs/specification/page.mdx b/app/docs/specification/page.mdx index b62cf13..7b90749 100644 --- a/app/docs/specification/page.mdx +++ b/app/docs/specification/page.mdx @@ -111,7 +111,7 @@ Example: { "prefer": { "streaming": false, - "response_format": "chatgpt_app", + "response_format": "mcp_app", "mode": "list, summarize", "accept-language": "en", "user-agent": "Copilot/1.0.0" @@ -124,7 +124,7 @@ Example: We expect a wide range of clients to call NLWeb agents — from chatbots to site search interfaces to data analytics tools. Different output structures may be suitable for different clients. The set of possible response_format values is open-ended and extensible. This specification defines two formats: * conversational_search (default): Returns results in the Conversational Search result structure (see 4.1.1). -* chatgpt_app: Returns results in the ChatGPT App result structure (see 4.1.1), conforming to the ChatGPT Apps SDK. +* mcp_app: Returns results in the MCP Apps result structure (see 4.1.1), conforming to the MCP Apps extension ([io.modelcontextprotocol/ui](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx)). NLWeb agents may support additional formats. A client may specify the formats it can accept, and the NLWeb agent chooses the best match. @@ -187,12 +187,12 @@ Convention: Request metadata uses the attribute name meta. Response metadata use Metadata about the response. * response_type (string, required): One of "answer", "elicitation", "promise", or "failure". -* response_format (string, optional): The response format of the answer (e.g., "conversational_search", "chatgpt_app"). +* response_format (string, optional): The response format of the answer (e.g., "conversational_search", "mcp_app"). * version (string, required): API version number. * session_context (object, optional): Context object which can include attribute-value pairs that need to be included in future calls to the NLWeb agent. * Response format-specific fields such as: - * openai/outputTemplate (string): For ChatGPT Apps SDK — URI of the widget template. - * openai/widgetAccessible (boolean): For ChatGPT Apps SDK — whether the widget can make tool calls. + * ui (object): For the MCP Apps extension. Associates the result with a UI resource used to render it. Contains: + * resourceUri (string): URI of the UI resource (the rendering template), using the `ui://` scheme (e.g., "ui://recipe-server/recipe-widget"). Over MCP transport, the host retrieves the template via `resources/read`. Over HTTP transport, the URI MUST be resolvable by the client to a UI resource served as `text/html;profile=mcp-app`. * Other protocol-specific metadata as needed. ### 4.1 Response Content @@ -201,7 +201,7 @@ The result structure is a function of the response_type. The following subsectio #### 4.1.1 Answer -Though we expect to allow different structures for the content, as specified by the response_format in the request, we expect most answers to be an array of JSON objects, each encoding some semi-structured information. In some cases, as with ChatGPT apps, the structured and unstructured portions may be broken out into separate sections. +Though we expect to allow different structures for the content, as specified by the response_format in the request, we expect most answers to be an array of JSON objects, each encoding some semi-structured information. In some cases, as with MCP Apps, the structured and unstructured portions may be broken out into separate sections. This specification defines two result structures. @@ -246,25 +246,28 @@ Example: } ``` -**ChatGPT App Result Structure** +**MCP Apps Result Structure** -This structure conforms to the structure specified for ChatGPT apps. The main differences from Conversational Search are: +This structure conforms to the MCP Apps extension ([io.modelcontextprotocol/ui](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx)), which standardizes how a result is paired with an interactive UI. The main differences from Conversational Search are: -1. content (array, required): Used for natural language descriptions of the result, meant for consumption by the chatbot's LLM. An array of JSON objects, each with: +1. content (array, required): Used for natural language descriptions of the result, meant for consumption by the host's model and by text-only hosts. An array of JSON objects, each with: * type (string): The value "text". * text (string): A natural language description of the results. -2. structuredData (array, required): An array of typed semi-structured JSON objects, following the same item schema as results in the Conversational Search structure. +2. structuredContent (object, required): Structured data optimized for UI rendering (and not added to the model's context). NLWeb places the typed semi-structured items under a results array, where each item follows the same item schema as results in the Conversational Search structure. + +The UI resource used to render the result is referenced from `_meta.ui.resourceUri` (see the _meta section above). Example: ```json { "_meta": { "response_type": "answer", - "response_format": "chatgpt_app", + "response_format": "mcp_app", "version": "0.55", - "openai/outputTemplate": "https://example.com/recipe-widget", - "openai/widgetAccessible": true + "ui": { + "resourceUri": "ui://recipe-server/recipe-widget" + } }, "content": [ { @@ -272,15 +275,17 @@ Example: "text": "Here are protein-rich pumpkin recipes with cinnamon..." } ], - "structuredData": [ - { - "@type": "Recipe", - "name": "Pumpkin spice with coconut", - "description": "....", - "recipeIngredient": ["..."], - "cookTime": "PT30M" - } - ] + "structuredContent": { + "results": [ + { + "@type": "Recipe", + "name": "Pumpkin spice with coconut", + "description": "....", + "recipeIngredient": ["..."], + "cookTime": "PT30M" + } + ] + } } ``` @@ -1033,7 +1038,8 @@ Checking on the promise with await: * Elicitation question types enumerated: single_select, multi_select, free_text, number, boolean. * Error codes enumerated: NO_RESULTS, INVALID_QUERY, UNSUPPORTED_FORMAT, UNSUPPORTED_MODE, RATE_LIMITED, INTERNAL_ERROR, TIMEOUT, TOKEN_LIMIT. * Summary items in Conversational Search results given a recommended @type of SearchSummary. -* response_format values documented: conversational_search (default) and chatgpt_app. +* response_format values documented: conversational_search (default) and mcp_app. +* Interactive UI output migrated from the ChatGPT Apps SDK structure to the MCP Apps extension (io.modelcontextprotocol/ui): response_format chatgpt_app replaced by mcp_app, structuredData (array) replaced by structuredContent (object with a results array), and the openai/outputTemplate and openai/widgetAccessible meta fields replaced by _meta.ui.resourceUri referencing a ui:// resource. * User object in meta clarified as accepting either a string or structured object. * Authentication, authorization, and rate limiting explicitly scoped as transport-layer concerns (Sections 2.4, 2.5). * HTTP status code guidance added (Section 7.4).