@productmaker/mcp 12.1.1 → 12.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -309,6 +309,13 @@ The `base64` field was removed. MCP JSON-RPC transports truncate large tool argu
309
309
 
310
310
  ## Version history
311
311
 
312
+ ### 12.1.2 — ChatGPT result metadata compatibility
313
+
314
+ - The result viewer reads ChatGPT's canonical `toolResponseMetadata` envelopes as well as direct metadata and standard MCP App notifications. Initial results and later updates retain the same media validation and cleanup.
315
+ - The bridge answers trusted parent JSON-RPC pings and accepts initialization only from its matching response, once. A host request reusing the same ID cannot initialize it.
316
+ - After changing a development connector's tool descriptors, refresh its tools in ChatGPT. A successful server deployment alone does not prove that the installed connector has discovered the new viewer.
317
+ - Hosted playback remains a separate release check; local bridge fixtures do not establish it.
318
+
312
319
  ### 12.1.1 — Real media in chat and service landing quote parity
313
320
 
314
321
  - `get_task_status` attaches a read-only MCP App with the delivered ProductMaker images and playable videos, plus original native image bytes and protected download fallbacks. It never generates replacement media.
package/dist/http.js CHANGED
@@ -25883,7 +25883,7 @@ var ApiClient = class {
25883
25883
  };
25884
25884
 
25885
25885
  // src/index.ts
25886
- var MCP_VERSION = "12.1.1";
25886
+ var MCP_VERSION = "12.1.2";
25887
25887
 
25888
25888
  // src/meta-upload-app.ts
25889
25889
  import { readFileSync } from "fs";
package/dist/stdio.js CHANGED
@@ -24210,7 +24210,7 @@ var ApiClient = class {
24210
24210
  };
24211
24211
 
24212
24212
  // src/index.ts
24213
- var MCP_VERSION = "12.1.1";
24213
+ var MCP_VERSION = "12.1.2";
24214
24214
 
24215
24215
  // src/meta-upload-app.ts
24216
24216
  import { readFileSync } from "fs";
@@ -117,9 +117,18 @@
117
117
  const media = document.getElementById("media");
118
118
  let receivedResult = false;
119
119
  let hostReady = false;
120
+ let initializationSettled = false;
120
121
  let disposed = false;
122
+ const initializeRequestId = 1;
121
123
  const isRecord = (value) =>
122
124
  value !== null && typeof value === "object" && !Array.isArray(value);
125
+ const resultStates = new Set([
126
+ "ready",
127
+ "empty",
128
+ "pending",
129
+ "awaiting_review",
130
+ "error",
131
+ ]);
123
132
  const safeUrl = (value) => {
124
133
  if (typeof value !== "string") return null;
125
134
  try {
@@ -257,9 +266,7 @@
257
266
  !isRecord(result) ||
258
267
  result.isError ||
259
268
  !isRecord(data) ||
260
- !["ready", "empty", "pending", "awaiting_review", "error"].includes(
261
- data.state,
262
- )
269
+ !resultStates.has(data.state)
263
270
  ) {
264
271
  setState(
265
272
  "error",
@@ -321,10 +328,44 @@
321
328
  }
322
329
  reportSize();
323
330
  }
331
+ function applyOpenAiMetadata(metadata) {
332
+ if (!isRecord(metadata) || disposed) return;
333
+ // ChatGPT preserves the MCP envelope in toolResponseMetadata:
334
+ // https://developers.openai.com/plugins/reference#capabilities
335
+ // Read only the known wrappers; never search arbitrary nested data.
336
+ const callResult = isRecord(metadata.call_tool_result)
337
+ ? metadata.call_tool_result
338
+ : null;
339
+ const candidates = [
340
+ metadata.mcp_tool_result,
341
+ callResult?.mcp_tool_result,
342
+ callResult,
343
+ metadata,
344
+ { _meta: metadata },
345
+ ];
346
+ const result = candidates.find((candidate) => {
347
+ if (!isRecord(candidate)) return false;
348
+ if (candidate.isError === true) return true;
349
+ const data = isRecord(candidate._meta)
350
+ ? candidate._meta.taskResults
351
+ : null;
352
+ return (
353
+ isRecord(data) &&
354
+ resultStates.has(data.state) &&
355
+ Array.isArray(data.images) &&
356
+ Array.isArray(data.videos) &&
357
+ Array.isArray(data.links)
358
+ );
359
+ });
360
+ // Globals can arrive before a result or with unrelated host updates.
361
+ // Keep delivered playback until a valid result or explicit error.
362
+ if (result) applyResult(result);
363
+ }
324
364
  function handleMessage(event) {
325
365
  if (
326
366
  event.source !== window.parent ||
327
367
  !isRecord(event.data) ||
368
+ event.data.jsonrpc !== "2.0" ||
328
369
  disposed
329
370
  )
330
371
  return;
@@ -343,7 +384,30 @@
343
384
  );
344
385
  }
345
386
  disposed = true;
346
- } else if (message.id === 1) {
387
+ } else if (message.method === "ping") {
388
+ if (
389
+ (typeof message.id === "string" ||
390
+ Number.isInteger(message.id)) &&
391
+ !Object.prototype.hasOwnProperty.call(message, "result") &&
392
+ !Object.prototype.hasOwnProperty.call(message, "error") &&
393
+ (message.params === undefined || isRecord(message.params))
394
+ )
395
+ window.parent.postMessage(
396
+ { jsonrpc: "2.0", id: message.id, result: {} },
397
+ "*",
398
+ );
399
+ } else if (
400
+ !initializationSettled &&
401
+ message.id === initializeRequestId &&
402
+ !Object.prototype.hasOwnProperty.call(message, "method") &&
403
+ ((isRecord(message.result) &&
404
+ !Object.prototype.hasOwnProperty.call(message, "error")) ||
405
+ (isRecord(message.error) &&
406
+ Number.isInteger(message.error.code) &&
407
+ typeof message.error.message === "string" &&
408
+ !Object.prototype.hasOwnProperty.call(message, "result")))
409
+ ) {
410
+ initializationSettled = true;
347
411
  window.clearTimeout(initializeTimeout);
348
412
  if (message.error) {
349
413
  if (!receivedResult) applyResult({ isError: true });
@@ -366,7 +430,7 @@
366
430
  "toolResponseMetadata",
367
431
  )
368
432
  )
369
- applyResult({ _meta: globals.toolResponseMetadata });
433
+ applyOpenAiMetadata(globals.toolResponseMetadata);
370
434
  }
371
435
  const resultTimeout = window.setTimeout(() => {
372
436
  if (!receivedResult) applyResult({ isError: true });
@@ -380,7 +444,7 @@
380
444
  window.parent.postMessage(
381
445
  {
382
446
  jsonrpc: "2.0",
383
- id: 1,
447
+ id: initializeRequestId,
384
448
  method: "ui/initialize",
385
449
  params: {
386
450
  appInfo: { name: "ProductMaker task results", version: "1.0.0" },
@@ -390,8 +454,7 @@
390
454
  },
391
455
  "*",
392
456
  );
393
- if (isRecord(window.openai?.toolResponseMetadata))
394
- applyResult({ _meta: window.openai.toolResponseMetadata });
457
+ applyOpenAiMetadata(window.openai?.toolResponseMetadata);
395
458
  })();
396
459
  </script>
397
460
  </body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productmaker/mcp",
3
- "version": "12.1.1",
3
+ "version": "12.1.2",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "ProductMaker MCP server — cost products, generate landing pages, UGC videos, and ad creatives, and publish to Shopify, Meta Ads, and TikTok Ads.",