update-metadata-ui
Update Chrome Web Store listing metadata through automated UI interaction when API updates fail or as the primary method due to API deprecation.
Instructions
Update listing metadata via Chrome Web Store dashboard UI automation (Playwright). Use this when API metadata updates are not reflected, or as the primary metadata update method since the v1 API is deprecated.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| itemId | No | Extension item ID (defaults to CWS_ITEM_ID env var) | |
| title | No | Store listing title | |
| summary | No | Store listing short summary | |
| description | No | Store listing long description | |
| category | No | Category label as shown in dashboard UI | |
| homepageUrl | No | Homepage URL | |
| supportUrl | No | Support URL | |
| storeIconPath | No | Absolute path to 128x128 store icon image | |
| accountIndex | No | Google account index in dashboard URL (default: 0) | |
| headless | No | Run browser headless (default: false) |
Implementation Reference
- src/index.ts:599-700 (handler)The handler for the 'update-metadata-ui' tool, which uses Playwright to automate Chrome Web Store dashboard interactions.
async ({ itemId, title, summary, description, category, homepageUrl, supportUrl, storeIconPath, accountIndex, headless, }) => { try { const id = resolveItemId(itemId); const idx = accountIndex ?? 0; const dashboardUrl = `https://chromewebstore.google.com/u/${idx}/dashboard/${id}/edit`; const hasAnyField = [title, summary, description, category, homepageUrl, supportUrl, storeIconPath].some( (v) => typeof v === "string" && v.trim().length > 0 ); if (!hasAnyField) { throw new Error("No fields provided for UI update."); } const context = await chromium.launchPersistentContext(DASHBOARD_PROFILE_DIR, { channel: "chrome", headless: headless ?? false, }); try { const page = context.pages()[0] || (await context.newPage()); await page.goto(dashboardUrl, { waitUntil: "domcontentloaded", timeout: 90_000 }); await page.waitForTimeout(2500); if (page.url().includes("accounts.google.com")) { throw new Error( `Not signed in to Chrome Web Store dashboard. Open once with headless=false and sign in. Profile dir: ${DASHBOARD_PROFILE_DIR}` ); } if (title?.trim()) { await fillTextFieldByLabel(page, ["Title", "제목", "Name", "이름"], title.trim()); } if (summary?.trim()) { await fillTextFieldByLabel( page, ["Summary", "Short description", "요약", "짧은 설명"], summary.trim() ); } if (description?.trim()) { await fillTextFieldByLabel(page, ["Description", "설명"], description.trim()); } if (homepageUrl?.trim()) { await fillTextFieldByLabel(page, ["Homepage", "홈페이지"], homepageUrl.trim()); } if (supportUrl?.trim()) { await fillTextFieldByLabel(page, ["Support", "지원", "Help", "도움말"], supportUrl.trim()); } if (storeIconPath?.trim()) { await uploadFileBySectionLabel( page, ["Store icon", "스토어 아이콘", "아이콘", "Icon"], storeIconPath.trim() ); } if (category?.trim()) { const categoryCombo = page .getByRole("combobox", { name: /category|카테고리/i }) .first(); if ((await categoryCombo.count()) > 0) { await categoryCombo.click(); const option = page.getByRole("option", { name: new RegExp(escapeRegExp(category), "i") }).first(); if ((await option.count()) > 0) { await option.click(); } } } await clickSaveButton(page); return { content: [ { type: "text" as const, text: JSON.stringify( { ok: true, mode: "dashboard-ui", profileDir: DASHBOARD_PROFILE_DIR, url: page.url(), }, null, 2 ), }, ], isError: false, }; } finally { await context.close(); - src/index.ts:569-598 (registration)Registration of the 'update-metadata-ui' tool with its schema definition using Zod.
server.tool( "update-metadata-ui", "Update listing metadata via Chrome Web Store dashboard UI automation (Playwright). Use this when API metadata updates are not reflected, or as the primary metadata update method since the v1 API is deprecated.", { itemId: z .string() .optional() .describe("Extension item ID (defaults to CWS_ITEM_ID env var)"), title: z.string().optional().describe("Store listing title"), summary: z.string().optional().describe("Store listing short summary"), description: z.string().optional().describe("Store listing long description"), category: z.string().optional().describe("Category label as shown in dashboard UI"), homepageUrl: z.string().optional().describe("Homepage URL"), supportUrl: z.string().optional().describe("Support URL"), storeIconPath: z .string() .optional() .describe("Absolute path to 128x128 store icon image"), accountIndex: z .number() .int() .min(0) .max(9) .optional() .describe("Google account index in dashboard URL (default: 0)"), headless: z .boolean() .optional() .describe("Run browser headless (default: false)"), },