For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Navegação principal

Referência

Referência de extensões de interface e metadados específicos do ChatGPT.

Comece pelo padrão aberto. Use a

especificação MCP Apps

para campos de interface e métodos da ponte de comunicação compartilhados. As extensões da OpenAI são opcionais e ficam em window.openai para quando você precisar de capacidades específicas do ChatGPT.

Ponte de comunicação de componentes window.openai

O ChatGPT fornece window.openai para aliases de compatibilidade e extensões opcionais do ChatGPT. Novas interfaces devem usar a ponte de comunicação MCP Apps sempre que a especificação compartilhada oferecer um equivalente e usar window.openai apenas para capacidades específicas do ChatGPT.

Consulte Crie uma interface para o ChatGPT para ver guias de implementação passo a passo.

Se sua ferramenta exigir confirmação, a ausência inicial de toolInput é esperada. O ChatGPT não carrega argumentos que dependem de aprovação nos valores do widget antes da aprovação; o host os envia por meio de ui/notifications/tool-input assim que o usuário aprova a chamada.

Capacidades

CapacidadeO que fazUso típico
Estado e dadoswindow.openai.toolInputArgumentos fornecidos quando a ferramenta foi chamada. Para ferramentas que dependem de aprovação, esse valor pode permanecer null até que o host envie ui/notifications/tool-input após a aprovação.
Estado e dadoswindow.openai.toolOutputSeu structuredContent. Mantenha os campos concisos; o modelo lê seu conteúdo exatamente como foi escrito.
Estado e dadoswindow.openai.toolResponseMetadataMetadados canônicos do resultado da ferramenta, exclusivos do widget. No ChatGPT, isso inclui status, call_tool_result e mcp_tool_result, preservando o envelope completo do resultado MCP, inclusive o campo oculto _meta.
Estado e dadoswindow.openai.widgetStateRegistro do estado da interface persistido entre renderizações.
Estado e dadoswindow.openai.setWidgetState(state)Armazena um novo registro de estado de forma síncrona; faça a chamada após cada interação relevante com a interface.
APIs do ambiente de execução do widgetwindow.openai.callTool(name, args)Chame outra ferramenta MCP a partir do widget (reproduz as chamadas iniciadas pelo modelo).
APIs do ambiente de execução do widgetwindow.openai.sendFollowUpMessage({ prompt, scrollToBottom })Peça ao ChatGPT para publicar uma mensagem criada pelo componente. scrollToBottom é opcional, tem true como valor padrão e pode ser definido como false para impedir a rolagem automática.
APIs do ambiente de execução do widgetwindow.openai.uploadFile(file, { library?: boolean })Envie um arquivo selecionado pelo usuário e receba um fileId. Passe { library: true } para também salvar o arquivo enviado na biblioteca de arquivos do usuário no ChatGPT, quando ela estiver disponível.
APIs do ambiente de execução do widgetwindow.openai.selectFiles()Abra o seletor da biblioteca de arquivos do ChatGPT e retorne os arquivos cujo acesso foi autorizado para o plug-in no formato { fileId, fileName, mimeType }[]. Verifique se essa função auxiliar está disponível antes de usá-la, pois a biblioteca de arquivos pode não estar disponível para todos os usuários.
APIs do ambiente de execução do widgetwindow.openai.getFileDownloadUrl({ fileId })Obtenha uma URL temporária de download para um arquivo enviado pelo widget, selecionado na biblioteca de arquivos, passado por parâmetros de arquivo ou retornado por referências a arquivos da ferramenta.
APIs do ambiente de execução do widgetwindow.openai.requestDisplayMode(...)Solicite os modos PiP ou tela cheia.
APIs do ambiente de execução do widgetwindow.openai.requestModal({ params, template })Abra um modal gerenciado pelo ChatGPT. Omita template para usar o modelo de interface atual ou passe o URI de um modelo de interface registrado para trocar o conteúdo do modal.
APIs do ambiente de execução do widgetwindow.openai.requestClose()Peça ao ChatGPT para fechar o widget atual.
APIs do ambiente de execução do widgetwindow.openai.notifyIntrinsicHeight(...)Informe as alturas dinâmicas do widget para evitar que o conteúdo seja cortado durante a rolagem.
APIs do ambiente de execução do widgetwindow.openai.openExternal({ href, redirectUrl })Abra um link externo verificado no navegador do usuário. Para destinos de redirecionamento aprovados, o ChatGPT acrescenta ?redirectUrl=... por padrão; defina redirectUrl: false para evitar isso.
APIs do ambiente de execução do widgetwindow.openai.setOpenInAppUrl({ href })Substitua, opcionalmente, o destino externo exibido em tela cheia. Se não for definido, o ChatGPT mantém o comportamento padrão e abre o caminho atual do iframe do componente.
Contextowindow.openai.theme, window.openai.displayMode, window.openai.maxHeight, window.openai.safeArea, window.openai.view, window.openai.userAgent, window.openai.localeSinais do ambiente que você pode ler ou acompanhar por meio de useOpenAiGlobal para adaptar os elementos visuais e os textos.

Função auxiliar useOpenAiGlobal

Muitos projetos de interface para o ChatGPT encapsulam o acesso a window.openai em pequenas funções auxiliares para que as visualizações continuem testáveis. Esta função auxiliar de exemplo monitora os eventos openai:set_globals do host e permite que componentes React acompanhem um único valor global:

export function useOpenAiGlobal<K extends keyof WebplusGlobals>(
  key: K
): WebplusGlobals[K] {
  return useSyncExternalStore(
    (onChange) => {
      const handleSetGlobal = (event: SetGlobalsEvent) => {
        const value = event.detail.globals[key];
        if (value === undefined) {
          return;
        }

        onChange();
      };

      window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal, {
        passive: true,
      });

      return () => {
        window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);
      };
    },
    () => window.openai[key]
  );
}

Feche a interface

Chame window.openai.requestClose() para pedir ao ChatGPT que feche a interface atual.

Solicite outro modo de apresentação

Use window.openai.requestDisplayMode para solicitar a apresentação na própria conversa, em imagem sobre imagem ou em tela cheia:

await window.openai?.requestDisplayMode({ mode: "fullscreen" });
// On mobile, picture-in-picture may be presented as fullscreen.

Abra um modal

Use window.openai.requestModal para abrir um modal controlado pelo host. Forneça o URI de outro modelo de interface registrado pelo mesmo servidor MCP ou omita template para abrir o modelo de interface atual:

await window.openai.requestModal({
  template: "ui://widget/checkout.html",
});

APIs de arquivos

O ChatGPT oferece funções auxiliares para envio e download de arquivos como extensões opcionais de window.openai.

APIFinalidadeObservações
window.openai.uploadFile(file, { library?: boolean })Envie um arquivo selecionado pelo usuário e receba um fileId.Passe { library: true } para também salvar o arquivo enviado na biblioteca de arquivos do usuário no ChatGPT, quando ela estiver disponível para o usuário atual.
window.openai.selectFiles()Abra o seletor da biblioteca de arquivos para selecionar arquivos existentes.Retorna [{ fileId, fileName, mimeType }]. Verifique se essa função auxiliar está disponível, pois a biblioteca de arquivos pode não estar disponível para todos os usuários.
window.openai.getFileDownloadUrl({ fileId })Solicite uma URL temporária de download para um arquivo.Funciona com arquivos enviados pelo widget, selecionados na biblioteca de arquivos, passados por parâmetros de arquivo ou retornados por referências a arquivos nas ferramentas.

A biblioteca de arquivos do ChatGPT é opcional e pode não estar disponível para todos os usuários. Os arquivos retornados por window.openai.selectFiles() já estão autorizados para o plug-in atual quando a função auxiliar está disponível. Use o fileId retornado com window.openai.getFileDownloadUrl({ fileId }) ou em uma entrada de ferramenta que use parâmetros de arquivo.

Envie um arquivo selecionado pelo usuário:

const { fileId } = await window.openai.uploadFile(file, {
  library: true,
});

Selecione arquivos que o usuário já enviou ao ChatGPT:

if (window.openai?.selectFiles) {
  const files = await window.openai.selectFiles();
  // [{ fileId, fileName, mimeType }]
}

Verifique se window.openai.selectFiles está disponível e use window.openai.uploadFile como alternativa quando a biblioteca de arquivos estiver indisponível.

Solicite uma URL temporária de download:

const { downloadUrl } = await window.openai.getFileDownloadUrl({ fileId });

Defina arquivos de entrada

Para permitir que o ChatGPT passe arquivos a uma ferramenta, liste cada entrada de arquivo de nível superior em _meta["openai/fileParams"]. Cada campo listado deve corresponder a um objeto de arquivo ou a um array de objetos de arquivo.

Todo esquema de objeto de arquivo deve declarar as quatro propriedades suportadas:

PropriedadeTipoDeclarar em propertiesIncluir em required
download_urlstringSimSim
file_idstringSimSim
mime_typestringSimNão
file_namestringSimNão

mime_type e file_name são valores opcionais, mas você deve declarar suas propriedades no esquema. A etapa Verificar ferramentas e o processo de envio do plug-in rejeitam um esquema de arquivo que omita qualquer uma das quatro propriedades, não exija download_url e file_id, marque qualquer uma das propriedades opcionais como obrigatória ou exija uma propriedade diferente de download_url ou file_id. Você pode declarar propriedades opcionais adicionais.

Este descritor completo de ferramenta aceita uma entrada de arquivo obrigatória:

{
  "name": "analyze_file",
  "title": "Analyze file",
  "description": "Analyzes a user-provided file without modifying it.",
  "inputSchema": {
    "type": "object",
    "$defs": {
      "OpenAIFile": {
        "type": "object",
        "properties": {
          "download_url": { "type": "string" },
          "file_id": { "type": "string" },
          "mime_type": { "type": "string" },
          "file_name": { "type": "string" }
        },
        "required": ["download_url", "file_id"],
        "additionalProperties": false
      }
    },
    "properties": {
      "file": { "$ref": "#/$defs/OpenAIFile" }
    },
    "required": ["file"]
  },
  "annotations": {
    "readOnlyHint": true,
    "openWorldHint": false,
    "destructiveHint": false
  },
  "_meta": {
    "openai/fileParams": ["file"]
  }
}

Para aceitar mais de um arquivo, defina o campo de nível superior como um array e use o mesmo esquema de objeto de arquivo em items. A ferramenta pode exigir o campo de arquivo de nível superior independentemente das propriedades obrigatórias dentro de cada objeto de arquivo.

Em tempo de execução, o ChatGPT passa valores de arquivo com campos em snake case:

{
  "download_url": "https://...",
  "file_id": "file_...",
  "mime_type": "image/png",
  "file_name": "input.png"
}

O ChatGPT sempre inclui download_url e file_id; ele pode omitir mime_type e file_name. Use file_id como valor de fileId em window.openai.getFileDownloadUrl({ fileId }) quando um widget precisar de uma nova URL temporária de download.

Ao persistir o estado do widget, use o formato estruturado (modelContent, privateContent, imageIds) se quiser que o modelo tenha acesso aos IDs das imagens nas próximas interações.

Navegação com suporte do host

O ambiente de execução do sandbox espelha o histórico de navegação do iframe na interface do ChatGPT. Use APIs de roteamento padrão, como o React Router, e o host manterá seus controles de navegação sincronizados com a sua interface.

Configuração do roteador com o BrowserRouter do React Router:

export default function PizzaListRouter() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<PizzaListPlugin />}>
          <Route path="place/:placeId" element={<PizzaListPlugin />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

Navegação programática:

const navigate = useNavigate();

function openDetails(placeId: string) {
  navigate(`place/${placeId}`, { replace: false });
}

function closeDetails() {
  navigate("..", { replace: true });
}

Parâmetros do descritor de ferramenta

Por padrão, a descrição de uma ferramenta deve incluir os campos listados aqui.

Declare outputSchema para qualquer ferramenta que retorne structuredContent. O esquema deve descrever exatamente o objeto retornado pela ferramenta para que os clientes possam validar os resultados e o modelo possa raciocinar sobre chamadas de ferramenta subsequentes.

Campos de _meta no descritor de ferramenta

Use estes campos de _meta no descritor de ferramenta. Dê preferência à chave padrão do MCP Apps _meta.ui.resourceUri para vincular uma ferramenta a um modelo de interface. O ChatGPT oferece suporte a metadados específicos da OpenAI para compatibilidade e extensões opcionais.

ChaveLocalizaçãoTipoLimitesFinalidade
_meta["securitySchemes"]Descritor de ferramentaarrayNenhumCópia para compatibilidade com versões anteriores, destinada a clientes que leem apenas _meta.
_meta.ui.resourceUriDescritor de ferramentastring (URI)NenhumURI de recurso padrão para o modelo de interface.
_meta.ui.visibilityDescritor de ferramentastring[]padrão ["model", "app"]Controla se uma ferramenta está disponível para o modelo, para a interface ou para ambos. O valor app é o identificador de interface no protocolo MCP Apps.
_meta["openai/outputTemplate"]Descritor de ferramentastring (URI)NenhumAlias opcional de compatibilidade, específico da OpenAI, para _meta.ui.resourceUri no ChatGPT.
_meta["openai/profile"]Descritor de ferramentabooleanOpcional; somente true designa uma ferramenta de perfilIdentifica a ferramenta autenticada e somente leitura que retorna o perfil atual. Implemente-a para ajudar os usuários a reconhecer e gerenciar várias contas conectadas. Os usuários podem conectar várias contas sem essa ferramenta. Consulte Suporte a várias contas.
_meta["openai/widgetAccessible"]Descritor de ferramentabooleanpadrão falseCampo de compatibilidade específico da OpenAI usado por integrações de interface existentes; dê preferência a _meta.ui.visibility + tools/call.
_meta["openai/visibility"]Descritor de ferramentastringpublic (padrão) ou privateCampo de compatibilidade específico da OpenAI usado por integrações de interface existentes; prefira _meta.ui.visibility.
_meta["openai/toolInvocation/invoking"]Descritor da ferramentastring≤ 64 caracteresTexto curto de status durante a execução da ferramenta.
_meta["openai/toolInvocation/invoked"]Descritor da ferramentastring≤ 64 caracteresTexto curto de status após a conclusão da ferramenta.
_meta["openai/fileParams"]Descritor da ferramentastring[]NenhumLista de campos de entrada de nível superior que representam arquivos. Cada campo recebe { download_url, file_id, mime_type?, file_name? }.

Exemplo:

import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
import { z } from "zod";

registerAppTool(
  server,
  "search",
  {
    title: "Public Search",
    description: "Search public documents.",
    inputSchema: { q: z.string() },
    outputSchema: {
      results: z.array(
        z.object({
          id: z.string(),
          title: z.string(),
          url: z.string(),
        })
      ),
    },
    securitySchemes: [
      { type: "noauth" },
      { type: "oauth2", scopes: ["search.read"] },
    ],
    _meta: {
      securitySchemes: [
        { type: "noauth" },
        { type: "oauth2", scopes: ["search.read"] },
      ],
      ui: { resourceUri: "ui://widget/story.html" },
      // Optional compatibility alias (ChatGPT only):
      // "openai/outputTemplate": "ui://widget/story.html",
      "openai/toolInvocation/invoking": "Searching…",
      "openai/toolInvocation/invoked": "Results ready",
    },
  },
  async ({ q }) => {
    const results = await performSearch(q);

    return {
      structuredContent: { results },
      content: [{ type: "text", text: `Found ${results.length} results.` }],
    };
  }
);

Anotações

Para identificar uma ferramenta como "somente leitura", use os seguintes campos de ToolAnnotations no descritor da ferramenta:

ChaveTipoObrigatórioObservações
readOnlyHintbooleanObrigatórioIndique que a ferramenta apenas consulta ou calcula informações e não cria, atualiza, exclui nem envia dados fora da conversa.
destructiveHintbooleanObrigatórioDeclare que a ferramenta pode excluir ou sobrescrever dados do usuário para que o host saiba que deve solicitar aprovação explícita antes de prosseguir.
openWorldHintbooleanObrigatórioDeclare que a ferramenta acessa a internet pública ou entidades externas de escopo não delimitado, inclusive por meio de ações somente leitura, como pesquisa na Web. Uma conta privada ou um workspace de escopo delimitado não constitui um ambiente aberto apenas por estar hospedado externamente.
idempotentHintbooleanOpcionalDeclare que chamar a ferramenta com os mesmos argumentos não tem efeito adicional sobre o ambiente em que ela opera.

Essas indicações influenciam apenas como o ChatGPT ou o Codex apresenta a chamada de ferramenta ao usuário; os servidores ainda devem aplicar sua própria lógica de autorização.

Exemplo:

import { z } from "zod";

server.registerTool(
  "list_saved_recipes",
  {
    title: "List saved recipes",
    description: "Returns the user’s saved recipes without modifying them.",
    inputSchema: {},
    outputSchema: {
      recipes: z.array(
        z.object({
          id: z.string(),
          title: z.string(),
        })
      ),
    },
    annotations: { readOnlyHint: true },
  },
  async () => ({
    structuredContent: { recipes: await fetchSavedRecipes() },
  })
);

Campos _meta do recurso do componente

Defina estas chaves no template de recurso que fornece seu componente (registerResource). Elas ajudam o ChatGPT a descrever e apresentar o iframe renderizado sem expor metadados a outros clientes.

ChaveLocalizaçãoTipoFinalidade
_meta.ui.prefersBorderConteúdo do recursobooleanIndique que o componente deve ser renderizado dentro de um cartão com borda quando houver suporte.
_meta.ui.cspConteúdo do recursoobjectLocal preferencial nos metadados para os campos padrão de CSP do widget: connectDomains, resourceDomains e, opcionalmente, frameDomains.
_meta.ui.domainConteúdo do recursostring (origem)Origem dedicada para componentes hospedados (obrigatória ao enviar um plug-in com interface; deve ser exclusiva de cada plug-in). O padrão é https://web-sandbox.oaiusercontent.com.
_meta["openai/widgetDescription"]Conteúdo do recursostringResumo legível por humanos, disponibilizado ao modelo quando o componente é carregado, para reduzir explicações redundantes do assistente.
_meta["openai/widgetPrefersBorder"]Conteúdo do recursobooleanAlias de compatibilidade específico da OpenAI para _meta.ui.prefersBorder no ChatGPT.
_meta["openai/widgetCSP"]Conteúdo do recursoobjectChave legada de compatibilidade do ChatGPT para metadados de CSP do widget. Os campos padrão de CSP são substituídos por _meta.ui.csp, mas redirect_domains ainda é obrigatório para destinos confiáveis de openExternal.
_meta["openai/widgetDomain"]Conteúdo do recursostring (origem)Alias de compatibilidade específico da OpenAI para _meta.ui.domain no ChatGPT.

O ChatGPT oferece suporte à chave legada de compatibilidade _meta["openai/widgetCSP"] com os seguintes nomes de campos em snake_case:

  • connect_domains: string[]
  • resource_domains: string[]
  • frame_domains?: string[]
  • redirect_domains?: string[]. Extensão do ChatGPT para destinos de redirecionamento de window.openai.openExternal.

O objeto padrão _meta.ui.csp geralmente é a opção recomendada para novas interfaces e oferece suporte a:

  • connectDomains: string[]. Domínios aos quais o widget pode se conectar via fetch/XHR.
  • resourceDomains: string[]. Domínios para recursos estáticos (imagens, fontes, scripts, estilos).
  • frameDomains?: string[]. Lista opcional de origens permitidas para incorporações em iframes. Por padrão, widgets não podem renderizar subquadros. Plug-ins podem incorporar conteúdo do próprio domínio, incluindo editores e interfaces de administração existentes, conforme a política de iframes. É necessário apresentar uma justificativa no envio, e o uso de iframes pode exigir revisão adicional ou tornar a aprovação mais demorada.

No entanto, _meta.ui.csp não oferece suporte a redirect_domains para links de window.openai.openExternal(...). Para adicionar destinos de redirecionamento à lista de permissões, ainda é necessário definir _meta["openai/widgetCSP"].redirect_domains.

Resultados de ferramentas

Os resultados de ferramentas podem conter os seguintes campos. Em especial:

ChaveTipoObrigatórioObservações
structuredContentobjectOpcionalDisponibilizado ao modelo e ao componente. Deve corresponder ao outputSchema declarado, quando fornecido.
contentstring ou Content[]OpcionalDisponibilizado ao modelo e ao componente.
_metaobjectOpcionalEnviado apenas ao componente. Oculto para o modelo.

Apenas structuredContent e content aparecem na transcrição da conversa. O host encaminha _meta ao componente para que você possa hidratar a interface sem expor os dados ao modelo.

Metadados do resultado da ferramenta fornecidos pelo host:

ChaveLocalizaçãoTipoFinalidade
_meta["openai/widgetSessionId"]_meta do resultado da ferramenta (fornecido pelo host)stringID estável da instância do widget atualmente montada; use-o para correlacionar logs e chamadas de ferramentas até que o widget seja desmontado.

Exemplo:

import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
import { z } from "zod";

registerAppTool(
  server,
  "get_zoo_animals",
  {
    title: "get_zoo_animals",
    inputSchema: { count: z.number().int().min(1).max(20).optional() },
    outputSchema: {
      animals: z.array(
        z.object({
          id: z.string(),
          name: z.string(),
          species: z.string(),
        })
      ),
    },
    _meta: { ui: { resourceUri: "ui://widget/widget.html" } },
  },
  async ({ count = 10 }) => {
    const animals = generateZooAnimals(count);

    return {
      structuredContent: { animals },
      content: [{ type: "text", text: `Here are ${animals.length} animals.` }],
      _meta: {
        allAnimalsById: Object.fromEntries(
          animals.map((animal) => [animal.id, animal])
        ),
      },
    };
  }
);

Resultado de ferramenta com erro

Para retornar um erro no resultado da ferramenta, use a seguinte chave de _meta:

ChaveFinalidadeTipoObservações
_meta["mcp/www_authenticate"]Resultado de errostring ou string[]Desafios WWW-Authenticate da RFC 7235 para iniciar o OAuth.

Campos de _meta fornecidos pelo cliente

ChaveQuando é fornecidoTipoFinalidade
_meta["openai/locale"]Inicialização + chamadas de ferramentasstring (BCP 47)Localidade solicitada (clientes mais antigos podem enviar _meta["webplus/i18n"]).
_meta["openai/userAgent"]Chamadas de ferramentasstringIndicação opcional do agente de usuário, fornecida quando possível, para análise de uso ou formatação.
_meta["openai/userLocation"]Chamadas de ferramentasobjectIndicação de localização aproximada (city, region, country, timezone, longitude, latitude).
_meta["openai/subject"]Chamadas de ferramentasstringID anonimizado do usuário enviado aos servidores MCP para limitação de taxa e identificação
_meta["openai/session"]Chamadas de ferramentasstringID anonimizado da conversa para correlacionar chamadas de ferramentas na mesma sessão do ChatGPT.
_meta["openai/organization"]Chamadas de ferramentasstringID anonimizado da organização associado à organização atual do ChatGPT, quando disponível.

Na fase de operação, _meta["openai/userAgent"] e _meta["openai/userLocation"] são apenas indicações; os servidores nunca devem usá-los como base para decisões de autorização e devem funcionar mesmo na ausência deles. Trate _meta["openai/userAgent"] como metadados opcionais, fornecidos conforme possível, e não como uma forma estável de detectar qual interface do host está chamando seu servidor.

Exemplo:

import { z } from "zod";

server.registerTool(
  "recommend_cafe",
  {
    title: "Recommend a cafe",
    inputSchema: {},
    outputSchema: {
      cafes: z.array(
        z.object({
          name: z.string(),
          address: z.string(),
        })
      ),
    },
  },
  async (_args, { _meta }) => {
    const locale = _meta?.["openai/locale"] ?? "en";
    const location = _meta?.["openai/userLocation"]?.city;
    const cafes = await findNearbyCafes(location);

    return {
      content: [{ type: "text", text: formatIntro(locale, location) }],
      structuredContent: { cafes },
    };
  }
);