appstore-api-mcp 1.1.2 → 1.2.0
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/CHANGELOG.md +14 -0
- package/README.md +4 -2
- package/docs/TOOLS.md +7 -0
- package/package.json +7 -3
- package/src/client.js +26 -0
- package/src/index.js +45 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ All notable changes to this project are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/) and the project uses
|
|
5
5
|
[Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [1.2.0] - 2026-06-02
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **`get_screenshot`** — fetch a live screenshot as an actual **image the agent
|
|
11
|
+
can see** (not just metadata). Downloads the App Store Connect image asset,
|
|
12
|
+
downscaled by default (`maxWidth`), and returns an `image/png` content block.
|
|
13
|
+
Lets an agent review/compare what's currently on a listing.
|
|
14
|
+
|
|
15
|
+
## [1.1.3] - 2026-06-02
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- Lead with analytics in the package/repo description, README one-liner, and
|
|
19
|
+
keywords — downloads, revenue, and subscriptions are now front and center.
|
|
20
|
+
|
|
7
21
|
## [1.1.2] - 2026-06-02
|
|
8
22
|
|
|
9
23
|
### Fixed
|
package/README.md
CHANGED
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
**Run App Store Connect by talking to your AI.** An
|
|
15
15
|
[MCP](https://modelcontextprotocol.io) server that turns Apple's
|
|
16
16
|
[App Store Connect API](https://developer.apple.com/documentation/appstoreconnectapi)
|
|
17
|
-
into plain-language actions — edit your listings,
|
|
18
|
-
and reach the entire API, from
|
|
17
|
+
into plain-language actions — edit your listings, **track downloads, revenue &
|
|
18
|
+
subscriptions**, audit your whole portfolio, and reach the entire API, from
|
|
19
|
+
whatever AI agent you already use.
|
|
19
20
|
|
|
20
21
|
### ✨ What makes it stand out
|
|
21
22
|
|
|
@@ -241,6 +242,7 @@ Full parameter reference: **[docs/TOOLS.md](docs/TOOLS.md)**.
|
|
|
241
242
|
| `create_app_store_version_localization` | Add a new locale to a version |
|
|
242
243
|
| `list_screenshot_sets` / `create_screenshot_set` | Manage per-device screenshot sets |
|
|
243
244
|
| `list_screenshots` / `upload_screenshot` / `delete_screenshot` | Manage screenshots (upload handles the full reserve→upload→commit flow) |
|
|
245
|
+
| 👁️ `get_screenshot` | Fetch a live screenshot **as an image the agent can see** — review/compare what's currently on a listing |
|
|
244
246
|
| 🚀 `audit_apps` | **Fleet health check** — scan all (or selected) apps for missing subtitle/keywords/description, under-used keyword field, single-locale listings, missing screenshots, and more. Read-only. |
|
|
245
247
|
| 📊 `get_sales_report` / `get_subscription_report` / `get_finance_report` | Units/downloads, proceeds, **subscriptions & retention**, earnings by region (parsed rows). Needs a Vendor Number + a key with Admin/Finance/Sales role. |
|
|
246
248
|
| 📈 `request_analytics_report` → `list_analytics_reports` → `list_analytics_report_instances` → `get_analytics_report_data` | The async Analytics Reports API — downloads, sessions, active devices, App Store engagement. |
|
package/docs/TOOLS.md
CHANGED
|
@@ -117,6 +117,13 @@ Common `displayType` values: `APP_IPHONE_67`, `APP_IPHONE_65`, `APP_IPHONE_61`,
|
|
|
117
117
|
### `list_screenshots`
|
|
118
118
|
- `screenshotSetId` **(required)**
|
|
119
119
|
|
|
120
|
+
### `get_screenshot`
|
|
121
|
+
Fetch the actual screenshot **image** (not just metadata) and return it as an
|
|
122
|
+
image the agent can see — review/compare what's currently live.
|
|
123
|
+
- `screenshotId` **(required)**
|
|
124
|
+
- `maxWidth` — downscale width in px for a lighter preview (default `750`; `0` = full size)
|
|
125
|
+
- **Returns:** an `image/png` content block + a caption with the file name and original dimensions.
|
|
126
|
+
|
|
120
127
|
### `upload_screenshot`
|
|
121
128
|
Upload an image into a set. Handles reserve → upload bytes → commit (with checksum).
|
|
122
129
|
- `screenshotSetId` **(required)**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appstore-api-mcp",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "MCP server for Apple App Store Connect —
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "MCP server for Apple App Store Connect — edit listings (keywords, descriptions, titles, screenshots), track analytics (downloads, proceeds, subscriptions, retention), run a fleet-wide ASO audit, preview changes with dry-run, and reach the full API. Works with any MCP client (Claude, Codex, Cursor, Windsurf, VS Code, Zed, Gemini CLI, Antigravity, Amazon Q, Goose, and more).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"appstore-api-mcp": "src/index.js"
|
|
@@ -33,7 +33,11 @@
|
|
|
33
33
|
"cursor",
|
|
34
34
|
"keywords",
|
|
35
35
|
"screenshots",
|
|
36
|
-
"metadata"
|
|
36
|
+
"metadata",
|
|
37
|
+
"analytics",
|
|
38
|
+
"app-analytics",
|
|
39
|
+
"subscriptions",
|
|
40
|
+
"aso-tools"
|
|
37
41
|
],
|
|
38
42
|
"license": "MIT",
|
|
39
43
|
"author": "Sviatoslav Fil",
|
package/src/client.js
CHANGED
|
@@ -193,6 +193,32 @@ export class AppStoreConnectClient {
|
|
|
193
193
|
: buf.toString("utf8");
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
/** Fetch raw bytes from a URL (e.g. an image asset). Returns a Buffer. */
|
|
197
|
+
async fetchBinary(url) {
|
|
198
|
+
const res = await fetch(url);
|
|
199
|
+
if (!res.ok)
|
|
200
|
+
throw new Error(`Image fetch failed (${res.status}) for ${url}`);
|
|
201
|
+
return Buffer.from(await res.arrayBuffer());
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Build a concrete image URL from an App Store Connect imageAsset
|
|
206
|
+
* (`{ templateUrl, width, height }`), optionally downscaled to maxWidth.
|
|
207
|
+
*/
|
|
208
|
+
static imageUrlFromAsset(imageAsset, maxWidth, format = "png") {
|
|
209
|
+
if (!imageAsset || !imageAsset.templateUrl) return null;
|
|
210
|
+
let w = imageAsset.width || 0;
|
|
211
|
+
let h = imageAsset.height || 0;
|
|
212
|
+
if (maxWidth && w && h && w > maxWidth) {
|
|
213
|
+
h = Math.round((h * maxWidth) / w);
|
|
214
|
+
w = maxWidth;
|
|
215
|
+
}
|
|
216
|
+
return imageAsset.templateUrl
|
|
217
|
+
.replace("{w}", String(w))
|
|
218
|
+
.replace("{h}", String(h))
|
|
219
|
+
.replace("{f}", format);
|
|
220
|
+
}
|
|
221
|
+
|
|
196
222
|
/** Parse TSV/CSV text into an array of row objects. Auto-detects delimiter. */
|
|
197
223
|
static parseDelimited(text, delimiter) {
|
|
198
224
|
const lines = text.split(/\r?\n/).filter((l) => l.length > 0);
|
package/src/index.js
CHANGED
|
@@ -619,6 +619,49 @@ const tools = [
|
|
|
619
619
|
return committed;
|
|
620
620
|
},
|
|
621
621
|
},
|
|
622
|
+
{
|
|
623
|
+
name: "get_screenshot",
|
|
624
|
+
description:
|
|
625
|
+
"Fetch the actual screenshot IMAGE by its id and return it so the agent can SEE it (not just metadata). Downloads the live image asset from App Store Connect, downscaled for a quick preview by default. Use this to review/compare what's currently live on a listing.",
|
|
626
|
+
inputSchema: {
|
|
627
|
+
type: "object",
|
|
628
|
+
properties: {
|
|
629
|
+
screenshotId: { type: "string" },
|
|
630
|
+
maxWidth: {
|
|
631
|
+
type: "number",
|
|
632
|
+
description: "Downscale to this width in px for a lighter preview (default 750; pass 0 for full size)",
|
|
633
|
+
},
|
|
634
|
+
},
|
|
635
|
+
required: ["screenshotId"],
|
|
636
|
+
},
|
|
637
|
+
run: async (a) => {
|
|
638
|
+
const res = await client.get(`/appScreenshots/${a.screenshotId}`);
|
|
639
|
+
const attr = res.data.attributes || {};
|
|
640
|
+
const asset = attr.imageAsset;
|
|
641
|
+
if (!asset || !asset.templateUrl)
|
|
642
|
+
return {
|
|
643
|
+
note: "This screenshot has no rendered image yet (still uploading/processing). State: " +
|
|
644
|
+
(attr.assetDeliveryState && attr.assetDeliveryState.state),
|
|
645
|
+
fileName: attr.fileName,
|
|
646
|
+
};
|
|
647
|
+
const maxWidth = a.maxWidth === undefined ? 750 : a.maxWidth || 0;
|
|
648
|
+
const url = AppStoreConnectClient.imageUrlFromAsset(asset, maxWidth, "png");
|
|
649
|
+
const buf = await client.fetchBinary(url);
|
|
650
|
+
return {
|
|
651
|
+
__mcpContent: [
|
|
652
|
+
{
|
|
653
|
+
type: "image",
|
|
654
|
+
data: buf.toString("base64"),
|
|
655
|
+
mimeType: "image/png",
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
type: "text",
|
|
659
|
+
text: `Screenshot ${a.screenshotId} — ${attr.fileName || "(no name)"}, original ${asset.width}×${asset.height}.`,
|
|
660
|
+
},
|
|
661
|
+
],
|
|
662
|
+
};
|
|
663
|
+
},
|
|
664
|
+
},
|
|
622
665
|
{
|
|
623
666
|
name: "delete_screenshot",
|
|
624
667
|
description: "Delete a screenshot by its id.",
|
|
@@ -1091,6 +1134,8 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
1091
1134
|
if (!tool) return fail(new Error(`Unknown tool: ${req.params.name}`));
|
|
1092
1135
|
try {
|
|
1093
1136
|
const result = await tool.run(req.params.arguments || {});
|
|
1137
|
+
// Tools may return raw MCP content (e.g. images) via __mcpContent.
|
|
1138
|
+
if (result && result.__mcpContent) return { content: result.__mcpContent };
|
|
1094
1139
|
return ok(result);
|
|
1095
1140
|
} catch (e) {
|
|
1096
1141
|
if (e && e.status === 403 && REPORT_TOOLS.has(req.params.name))
|