@productmaker/mcp 12.1.1 → 12.1.3

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.
@@ -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.3",
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.",