@productmaker/mcp 2.9.4 → 2.10.1
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 +94 -57
- package/dist/http.js +2129 -992
- package/dist/stdio.js +2129 -992
- package/dist/ui/meta-upload-app.html +46 -20
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<meta name="color-scheme" content="light dark" />
|
|
7
|
-
<title>
|
|
7
|
+
<title>Upload media · ProductMaker</title>
|
|
8
8
|
<style>
|
|
9
9
|
:root {
|
|
10
10
|
color-scheme: light dark;
|
|
@@ -1011,7 +1011,7 @@
|
|
|
1011
1011
|
async function initializeStandardHost() {
|
|
1012
1012
|
try {
|
|
1013
1013
|
const result = await rpcRequest("ui/initialize", {
|
|
1014
|
-
appInfo: { name: "ProductMaker
|
|
1014
|
+
appInfo: { name: "ProductMaker media upload", version: "1.0.0" },
|
|
1015
1015
|
appCapabilities: {
|
|
1016
1016
|
availableDisplayModes: ["inline", "fullscreen"],
|
|
1017
1017
|
},
|
|
@@ -1179,6 +1179,15 @@
|
|
|
1179
1179
|
const mediaKind = candidate.mediaKind;
|
|
1180
1180
|
const assetRole = candidate.assetRole;
|
|
1181
1181
|
const expiresAt = boundedString(candidate.expiresAt, 100);
|
|
1182
|
+
const checkToolName = [
|
|
1183
|
+
"check_media_upload",
|
|
1184
|
+
"check_meta_media_upload",
|
|
1185
|
+
].includes(candidate.checkToolName)
|
|
1186
|
+
? candidate.checkToolName
|
|
1187
|
+
: "check_meta_media_upload";
|
|
1188
|
+
const resolveEndpoint =
|
|
1189
|
+
boundedString(candidate.resolveEndpoint, 200) ||
|
|
1190
|
+
"/api/meta-upload/resolve";
|
|
1182
1191
|
if (!sessionId || !["image", "video", "mixed"].includes(mediaKind))
|
|
1183
1192
|
return null;
|
|
1184
1193
|
if (!["media", "thumbnail"].includes(assetRole)) return null;
|
|
@@ -1196,6 +1205,8 @@
|
|
|
1196
1205
|
assetRole,
|
|
1197
1206
|
maxFiles: candidate.maxFiles,
|
|
1198
1207
|
expiresAt,
|
|
1208
|
+
checkToolName,
|
|
1209
|
+
resolveEndpoint,
|
|
1199
1210
|
};
|
|
1200
1211
|
}
|
|
1201
1212
|
|
|
@@ -1534,7 +1545,7 @@
|
|
|
1534
1545
|
attempts: 0,
|
|
1535
1546
|
error: "",
|
|
1536
1547
|
failureStage: "",
|
|
1537
|
-
|
|
1548
|
+
assetId: "",
|
|
1538
1549
|
previewUrl: "",
|
|
1539
1550
|
};
|
|
1540
1551
|
}
|
|
@@ -1832,7 +1843,7 @@
|
|
|
1832
1843
|
renderItems();
|
|
1833
1844
|
},
|
|
1834
1845
|
);
|
|
1835
|
-
item.
|
|
1846
|
+
item.assetId = resolved.assetId;
|
|
1836
1847
|
return;
|
|
1837
1848
|
} catch (error) {
|
|
1838
1849
|
if (error && error.message === "session_expired") throw error;
|
|
@@ -1853,14 +1864,16 @@
|
|
|
1853
1864
|
const uploadPage = new URL(state.session.uploadPageUrl);
|
|
1854
1865
|
if (!safeUploadPageUrl(uploadPage))
|
|
1855
1866
|
throw new Error("unsafe_upload_page");
|
|
1856
|
-
const token =
|
|
1867
|
+
const token =
|
|
1868
|
+
uploadPage.searchParams.get("token") ||
|
|
1869
|
+
new URLSearchParams(uploadPage.hash.slice(1)).get("token");
|
|
1857
1870
|
if (!token) {
|
|
1858
1871
|
const error = new Error("missing_token");
|
|
1859
1872
|
error.safeStage = "resolve";
|
|
1860
1873
|
throw error;
|
|
1861
1874
|
}
|
|
1862
1875
|
const resolveUrl = new URL(
|
|
1863
|
-
|
|
1876
|
+
state.session.resolveEndpoint,
|
|
1864
1877
|
uploadPage.origin,
|
|
1865
1878
|
);
|
|
1866
1879
|
const response = await fetch(resolveUrl.toString(), {
|
|
@@ -1888,14 +1901,17 @@
|
|
|
1888
1901
|
const body = await response.json();
|
|
1889
1902
|
if (!isRecord(body)) throw new Error("invalid_resolve_response");
|
|
1890
1903
|
const uploadUrl = boundedString(body.uploadUrl, 3000);
|
|
1891
|
-
const
|
|
1904
|
+
const assetId = boundedString(
|
|
1905
|
+
body.assetId || body.stagingAssetId,
|
|
1906
|
+
300,
|
|
1907
|
+
);
|
|
1892
1908
|
const parsedUploadUrl = new URL(uploadUrl);
|
|
1893
|
-
if (!safeWebProtocol(parsedUploadUrl) || !
|
|
1909
|
+
if (!safeWebProtocol(parsedUploadUrl) || !assetId) {
|
|
1894
1910
|
const error = new Error("invalid_resolve_response");
|
|
1895
1911
|
error.safeStage = "resolve";
|
|
1896
1912
|
throw error;
|
|
1897
1913
|
}
|
|
1898
|
-
return { uploadUrl: parsedUploadUrl.toString(),
|
|
1914
|
+
return { uploadUrl: parsedUploadUrl.toString(), assetId };
|
|
1899
1915
|
}
|
|
1900
1916
|
|
|
1901
1917
|
function createClientUuid() {
|
|
@@ -2178,7 +2194,7 @@
|
|
|
2178
2194
|
const requestedSessionId = state.session.sessionId;
|
|
2179
2195
|
setSessionStatus("Comprobando el staging privado…", "neutral");
|
|
2180
2196
|
try {
|
|
2181
|
-
const result = await callReadOnlyTool(
|
|
2197
|
+
const result = await callReadOnlyTool(state.session.checkToolName, {
|
|
2182
2198
|
sessionId: requestedSessionId,
|
|
2183
2199
|
});
|
|
2184
2200
|
if (
|
|
@@ -2239,7 +2255,9 @@
|
|
|
2239
2255
|
}
|
|
2240
2256
|
|
|
2241
2257
|
async function callReadOnlyTool(name, args) {
|
|
2242
|
-
if (
|
|
2258
|
+
if (
|
|
2259
|
+
!["check_media_upload", "check_meta_media_upload"].includes(name)
|
|
2260
|
+
) {
|
|
2243
2261
|
throw new Error("tool_not_allowed");
|
|
2244
2262
|
}
|
|
2245
2263
|
const bridge = openAiBridge();
|
|
@@ -2286,7 +2304,10 @@
|
|
|
2286
2304
|
|
|
2287
2305
|
function parseStatusResult(result, expectedSessionId) {
|
|
2288
2306
|
const payload = resultPayload(result);
|
|
2289
|
-
if (
|
|
2307
|
+
if (
|
|
2308
|
+
state.session.checkToolName === "check_meta_media_upload" &&
|
|
2309
|
+
payload.sessionId !== expectedSessionId
|
|
2310
|
+
)
|
|
2290
2311
|
throw new Error("status_session_mismatch");
|
|
2291
2312
|
const status = payload.status;
|
|
2292
2313
|
if (!["pending", "uploaded"].includes(status))
|
|
@@ -2294,10 +2315,13 @@
|
|
|
2294
2315
|
const assets = Array.isArray(payload.assets)
|
|
2295
2316
|
? payload.assets.slice(0, MAX_FILES).flatMap((asset) => {
|
|
2296
2317
|
if (!isRecord(asset)) return [];
|
|
2297
|
-
const
|
|
2318
|
+
const assetId = boundedString(
|
|
2319
|
+
asset.assetId || asset.stagingAssetId,
|
|
2320
|
+
300,
|
|
2321
|
+
);
|
|
2298
2322
|
const mediaKind = asset.mediaKind;
|
|
2299
|
-
return
|
|
2300
|
-
? [{
|
|
2323
|
+
return assetId && ["image", "video"].includes(mediaKind)
|
|
2324
|
+
? [{ assetId, mediaKind }]
|
|
2301
2325
|
: [];
|
|
2302
2326
|
})
|
|
2303
2327
|
: [];
|
|
@@ -2322,7 +2346,7 @@
|
|
|
2322
2346
|
: null;
|
|
2323
2347
|
if (inferredMediaKind) {
|
|
2324
2348
|
assets.push({
|
|
2325
|
-
|
|
2349
|
+
assetId: legacyStagingAssetId,
|
|
2326
2350
|
mediaKind: inferredMediaKind,
|
|
2327
2351
|
});
|
|
2328
2352
|
} else {
|
|
@@ -2344,11 +2368,13 @@
|
|
|
2344
2368
|
setPickerAvailability();
|
|
2345
2369
|
renderCompletionAction();
|
|
2346
2370
|
const assets = state.assets
|
|
2347
|
-
.map(
|
|
2348
|
-
(asset) => `${asset.mediaKind} asset_id ${asset.stagingAssetId}`,
|
|
2349
|
-
)
|
|
2371
|
+
.map((asset) => `${asset.mediaKind} asset_id ${asset.assetId}`)
|
|
2350
2372
|
.join(", ");
|
|
2351
|
-
const
|
|
2373
|
+
const metaGuard =
|
|
2374
|
+
state.session.checkToolName === "check_meta_media_upload"
|
|
2375
|
+
? " Do not publish anything until you have asked me for the Meta portfolio, ad account, and Facebook Page."
|
|
2376
|
+
: "";
|
|
2377
|
+
const message = `The ProductMaker upload is complete. Continue my previous request using these uploaded assets: ${assets}. Do not ask me to upload them again.${metaGuard}`;
|
|
2352
2378
|
try {
|
|
2353
2379
|
const bridge = openAiBridge();
|
|
2354
2380
|
if (bridge && typeof bridge.sendFollowUpMessage === "function") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@productmaker/mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Product Maker MCP server — cost products, generate dropshipping landing pages, UGC videos, and ad creatives, and publish to Shopify and Meta Ads from Claude, ChatGPT, or Gemini.",
|