Agents browser-store-apis
Reference for browser extension store APIs for querying extension info, checking compatibility, and tracking submission status
install
source · Clone the upstream repo
git clone https://github.com/aRustyDev/agents
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aRustyDev/agents "$T" && mkdir -p ~/.claude/skills && cp -r "$T/content/plugins/web/browser-extension-dev/skills/browser-store-apis" ~/.claude/skills/arustydev-agents-browser-store-apis && rm -rf "$T"
manifest:
content/plugins/web/browser-extension-dev/skills/browser-store-apis/SKILL.mdsource content
Browser Store APIs
Reference for browser extension store APIs used for querying extension info, checking compatibility, and tracking submission status.
MCP Server: browser-store-api
The plugin includes an MCP server for store API integration.
Configuration
{ "mcpServers": { "browser-store-api": { "command": "npx", "args": ["-y", "@anthropic-ai/mcp-browser-store-api"], "env": { "AMO_API_KEY": "${AMO_API_KEY}", "AMO_API_SECRET": "${AMO_API_SECRET}", "CHROME_WEBSTORE_CLIENT_ID": "${CHROME_WEBSTORE_CLIENT_ID}", "CHROME_WEBSTORE_CLIENT_SECRET": "${CHROME_WEBSTORE_CLIENT_SECRET}", "CHROME_WEBSTORE_REFRESH_TOKEN": "${CHROME_WEBSTORE_REFRESH_TOKEN}" } } } }
Available Tools
| Tool | Description |
|---|---|
| Get extension info from Firefox Add-ons |
| List version history from AMO |
| Check Firefox version compatibility |
| Get extension info from Chrome Web Store |
| Get user reviews and ratings |
| Check publication/review status |
Firefox Add-ons API (AMO)
Authentication
# Generate API credentials at: # https://addons.mozilla.org/developers/addon/api/key/ export AMO_API_KEY="user:12345678:123" export AMO_API_SECRET="your-api-secret"
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
| GET | Get addon details |
| GET | List versions |
| GET | Search addons |
| GET | Review information |
| GET | Account info |
Extension Info Request
# Get extension by slug or ID curl "https://addons.mozilla.org/api/v5/addons/addon/ublock-origin/" \ -H "Authorization: JWT $AMO_JWT_TOKEN"
Response Structure
{ "id": 123456, "guid": "uBlock0@example.com", "slug": "ublock-origin", "name": { "en-US": "uBlock Origin" }, "current_version": { "version": "1.50.0", "files": [ { "id": 7890, "created": "2024-01-15T12:00:00Z", "status": "public", "size": 1234567 } ] }, "ratings": { "average": 4.8, "count": 50000 }, "weekly_downloads": 500000 }
Version Compatibility
# Check version compatibility curl "https://addons.mozilla.org/api/v5/addons/addon/{id}/versions/{version}/"
{ "version": "1.50.0", "compatibility": { "firefox": { "min": "109.0", "max": "*" }, "android": { "min": "109.0", "max": "*" } }, "is_strict_compatibility_enabled": false }
Chrome Web Store API
Authentication
# Create OAuth2 credentials at: # https://console.cloud.google.com/apis/credentials export CHROME_WEBSTORE_CLIENT_ID="your-client-id.apps.googleusercontent.com" export CHROME_WEBSTORE_CLIENT_SECRET="your-client-secret" export CHROME_WEBSTORE_REFRESH_TOKEN="your-refresh-token"
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
| GET | Get item info |
| PUT | Update item |
| POST | Publish item |
| POST | Create new item |
Get Access Token
# Exchange refresh token for access token curl -X POST "https://oauth2.googleapis.com/token" \ -d "client_id=$CHROME_WEBSTORE_CLIENT_ID" \ -d "client_secret=$CHROME_WEBSTORE_CLIENT_SECRET" \ -d "refresh_token=$CHROME_WEBSTORE_REFRESH_TOKEN" \ -d "grant_type=refresh_token"
Extension Info Request
curl "https://www.googleapis.com/chromewebstore/v1.1/items/$ITEM_ID?projection=DRAFT" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "x-goog-api-version: 2"
Response Structure
{ "kind": "chromewebstore#item", "id": "abcdefghijklmnopqrstuvwxyz123456", "publicKey": "...", "uploadState": "SUCCESS", "crxVersion": "1.0.0", "itemError": [] }
Upload New Version
curl -X PUT \ "https://www.googleapis.com/upload/chromewebstore/v1.1/items/$ITEM_ID" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "x-goog-api-version: 2" \ -T extension.zip
Publish Extension
curl -X POST \ "https://www.googleapis.com/chromewebstore/v1.1/items/$ITEM_ID/publish" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H "x-goog-api-version: 2" \ -H "Content-Length: 0"
Edge Add-ons API
Authentication
Uses Azure AD authentication via Partner Center.
# Register app in Azure Portal # Grant permissions to Partner Center API export AZURE_CLIENT_ID="your-client-id" export AZURE_CLIENT_SECRET="your-client-secret" export AZURE_TENANT_ID="your-tenant-id"
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
| GET | Get product info |
| GET | List submissions |
| POST | Create submission |
Get Token
curl -X POST \ "https://login.microsoftonline.com/$AZURE_TENANT_ID/oauth2/v2.0/token" \ -d "client_id=$AZURE_CLIENT_ID" \ -d "client_secret=$AZURE_CLIENT_SECRET" \ -d "scope=https://api.partner.microsoft.com/.default" \ -d "grant_type=client_credentials"
Status Tracking
Submission States
| Store | States |
|---|---|
| AMO | , , , |
| Chrome | , , , |
| Edge | , , |
Polling for Status
async function pollSubmissionStatus( store: 'amo' | 'chrome' | 'edge', extensionId: string, maxAttempts: number = 60, intervalMs: number = 60000 ): Promise<string> { for (let i = 0; i < maxAttempts; i++) { const status = await getSubmissionStatus(store, extensionId); if (isTerminalState(status)) { return status; } await sleep(intervalMs); } throw new Error('Status check timed out'); } function isTerminalState(status: string): boolean { const terminal = [ 'approved', 'rejected', // AMO 'PUBLISHED', 'REJECTED', // Chrome 'Published', 'Failed' // Edge ]; return terminal.includes(status); }
Version Checking
Compare Versions
function compareVersions(v1: string, v2: string): number { const parts1 = v1.split('.').map(Number); const parts2 = v2.split('.').map(Number); for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) { const p1 = parts1[i] || 0; const p2 = parts2[i] || 0; if (p1 > p2) return 1; if (p1 < p2) return -1; } return 0; } function isNewerVersion(current: string, published: string): boolean { return compareVersions(current, published) > 0; }
Check All Stores
interface StoreVersions { amo: string | null; chrome: string | null; edge: string | null; } async function checkAllStoreVersions( extensionIds: { amo?: string; chrome?: string; edge?: string } ): Promise<StoreVersions> { const [amo, chrome, edge] = await Promise.all([ extensionIds.amo ? getAMOVersion(extensionIds.amo) : null, extensionIds.chrome ? getChromeVersion(extensionIds.chrome) : null, extensionIds.edge ? getEdgeVersion(extensionIds.edge) : null ]); return { amo, chrome, edge }; }
Rate Limits
| Store | Limit | Window |
|---|---|---|
| AMO | 100 requests | per minute |
| Chrome Web Store | 2000 requests | per day |
| Edge Partner Center | 500 requests | per minute |
Retry Strategy
async function withRetry<T>( fn: () => Promise<T>, maxRetries: number = 3, baseDelayMs: number = 1000 ): Promise<T> { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { if (i === maxRetries - 1) throw error; const isRateLimit = error.status === 429; const delay = isRateLimit ? parseInt(error.headers['retry-after'] || '60') * 1000 : baseDelayMs * Math.pow(2, i); await sleep(delay); } } throw new Error('Max retries exceeded'); }
Common Use Cases
Check for Updates Needed
async function checkUpdatesNeeded( manifestVersion: string, extensionIds: { amo?: string; chrome?: string; edge?: string } ): Promise<{ store: string; needsUpdate: boolean }[]> { const storeVersions = await checkAllStoreVersions(extensionIds); return Object.entries(storeVersions) .filter(([_, version]) => version !== null) .map(([store, version]) => ({ store, needsUpdate: isNewerVersion(manifestVersion, version!) })); }
Submit to All Stores
async function submitToAllStores( zipPath: string, extensionIds: { amo: string; chrome: string; edge: string } ): Promise<{ store: string; success: boolean; error?: string }[]> { const results = await Promise.allSettled([ submitToAMO(zipPath, extensionIds.amo), submitToChrome(zipPath, extensionIds.chrome), submitToEdge(zipPath, extensionIds.edge) ]); return [ { store: 'amo', ...resultToStatus(results[0]) }, { store: 'chrome', ...resultToStatus(results[1]) }, { store: 'edge', ...resultToStatus(results[2]) } ]; }
Related Resources
- store-submission-reviewer agent: Pre-submission compliance checks
- extension-store-submission skill: Submission process guides
- validate-extension command: Local validation before submission