External Publication
Visit Post

Android ChatGPT blocks Apps SDK widget app destructive tool before MCP, while web/iOS show confirmation modal and work

OpenAI Developer Community May 15, 2026
Source

Hi Mark, here are the details.

ChatGPT Android app version

  • Google Pixel 7, 1.2026.125

  • Google Pixel 6a, 1.2026.125

Android versions/devices tested

  • Google Pixel 7, Android 17 build CP31.260423.012.A1

  • Google Pixel 6a, Android 16 build BP41.250822.010

Whether the native confirmation modal appears at all on Android

For my Isocarto app, no: the native confirmation modal does not appear on Android for the affected tools.

As a comparison, I tested the Dropbox ChatGPT app on the same Android device. Dropbox does show the native confirmation modal correctly. One difference is that Dropbox appears to be a shipped app without my widget flow, while Isocarto is an Apps SDK app with a widget.

Behavior after approval / failure

Since the confirmation modal does not appear for Isocarto on Android, there is no approval step.

Instead, the assistant returns an error before the MCP server receives the tool call. For example, I sometimes get:

“I couldn’t execute debug_write_confirmation_probe: the call was blocked by OpenAI safety controls.”

For delete_zone specifically, the Android failure produces no MCP log at all, which suggests the call is blocked client-side / OpenAI-side before reaching my MCP endpoint.

Full delete_zone tool descriptor + annotations

Here is the tool code:

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

import { z } from "zod";

import { fetchClientApi } from "../../helpers/apiClient.js";

import { requireAuth } from "../../middleware/auth.js";




export function registerDeleteZoneTool(server) {

  registerAppTool(

    server,

    "delete_zone",

    {

      title: "Supprimer une zone",

      description: "Supprime une zone de chalandise d'une carte Isocarto.",

      inputSchema: {

        mapId: z.string(),

        zoneId: z.string(),

      },

      annotations: { readOnlyHint: false, openWorldHint: false, destructiveHint: true },

      _meta: {},

    },

    requireAuth(async (args) => {

      try {

        const { mapId, zoneId } = args;

        if (!mapId || !zoneId) throw new Error("mapId et zoneId sont requis.");

        await fetchClientApi(`/zones/delete-zone/${zoneId}`, null, {

          bearerToken: args._mcpAccessToken,

          method: "DELETE",

          body: { mapId },

        });

        const remainingZonesResult = await fetchClientApi("/zones/get-zones", null, {

          bearerToken: args._mcpAccessToken,

          params: { mapId },

        }).catch(() => ({ zones: [] }));

        const remainingZones = remainingZonesResult?.zones || remainingZonesResult || [];

        return {

          content: [{ type: "text", text: "🗑️ Zone supprimée avec succès." }],

          structuredContent: {

            type: "zone_deleted",

            mapId,

            zoneId,

            remainingZones,

            remainingCount: remainingZones.length,

          },

        };

      } catch (err) {

          return {

            isError: true,

            content: [{ type: "text", text: `❌ Erreur : ${err.message}` }],

          structuredContent: { error: err.message },

        };

      }

    }),

  );

}

Invocation mode

The delete_zone tool is assistant-invoked from the conversation. It is not called directly from the widget via window.openai.callTool in this repro.

The app does have a widget for map visualization, but the failing delete_zone call is triggered by the assistant/tool orchestration, not by a direct widget button calling window.openai.callTool.

Successful web/desktop MCP log

On web/desktop, the native confirmation modal appears and the tool reaches the MCP server successfully:

1|isocarto-mcp        | 2026-05-15 16:57:18: 🧭 MCP tool called {

1|isocarto-mcp        | 2026-05-15 16:57:18:   toolName: 'delete_zone',

1|isocarto-mcp        | 2026-05-15 16:57:18:   userId: '252e8aad-64a1-486d-89a4-6ec06f6b8ab0',

1|isocarto-mcp        | 2026-05-15 16:57:18:   organizationId: '80075eaa-1314-4097-bf55-04e31ebbfb47',

1|isocarto-mcp        | 2026-05-15 16:57:18:   clientId: 'nrPRsqWupqcUMVEwpuwcapaRuYPllDym',

1|isocarto-mcp        | 2026-05-15 16:57:18:   sessionId: null,

1|isocarto-mcp        | 2026-05-15 16:57:18:   tokenMode: 'jwt',

1|isocarto-mcp        | 2026-05-15 16:57:18:   args: {

1|isocarto-mcp        | 2026-05-15 16:57:18:     mapId: '7d4b0b82-3941-4621-96f6-03dafeba59f0',

1|isocarto-mcp        | 2026-05-15 16:57:18:     zoneId: 'bfd86904-cfaf-4552-9476-3f1a8e3e34f7',

1|isocarto-mcp        | 2026-05-15 16:57:18:     hasGeometry: false

1|isocarto-mcp        | 2026-05-15 16:57:18:   }

1|isocarto-mcp        | 2026-05-15 16:57:18: }

186|isocarto          | 2026-05-15 16:57:18: [USER] Suppression d'une zone

1|isocarto-mcp        | 2026-05-15 16:57:18: ✅ MCP tool result {

1|isocarto-mcp        | 2026-05-15 16:57:18:   toolName: 'delete_zone',

1|isocarto-mcp        | 2026-05-15 16:57:18:   durationMs: 163,

1|isocarto-mcp        | 2026-05-15 16:57:18:   success: true,

1|isocarto-mcp        | 2026-05-15 16:57:18:   isError: false,

1|isocarto-mcp        | 2026-05-15 16:57:18:   type: 'zone_deleted',

1|isocarto-mcp        | 2026-05-15 16:57:18:   error: null,

1|isocarto-mcp        | 2026-05-15 16:57:18:   mapId: '7d4b0b82-3941-4621-96f6-03dafeba59f0',

1|isocarto-mcp        | 2026-05-15 16:57:18:   zoneId: 'bfd86904-cfaf-4552-9476-3f1a8e3e34f7'

1|isocarto-mcp        | 2026-05-15 16:57:18: }

Failed Android attempt

On Android, there is no MCP log for the failed delete_zone attempt. The tool is not called at all server-side.

Here is a screen (of another tool but the error is the same)

Minimal destructive test tool

I also tested a minimal harmless destructive test tool with similar annotations. It only logs/persists a debug label and does not perform a real deletion. That test also fails on Android in the same way: sometimes blocked by OpenAI safety controls before reaching the MCP server.

Summary

The issue seems specific to ChatGPT Android handling of Apps SDK confirmation/safety flow for my widget app. Web and iOS work. Android can still run some non-confirmation tools, but tools requiring the native confirmation modal, especially destructive tools like delete_zone, fail before reaching MCP.

Discussion in the ATmosphere

Loading comments...