appstore-api-mcp 1.16.2 → 1.16.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.
- package/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/src/index.js +14 -11
- package/src/ppp.js +22 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ 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.16.3] - 2026-10-08
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **Wrong US price for products with a price change** (affects `list_purchasable_products`
|
|
11
|
+
and the PPP base price in `preview_ppp_prices` / `apply_ppp_prices`). The US-price
|
|
12
|
+
lookup returned the *first* USA price row — usually the original base price —
|
|
13
|
+
instead of the price in effect today. A subscription raised from $0.99 to $2.99
|
|
14
|
+
reported $0.99, which also skewed every per-territory PPP recommendation derived
|
|
15
|
+
from it. Now selects the current effective price (latest `startDate` on or before
|
|
16
|
+
today; `null` = baseline; future-scheduled changes ignored) for both subscriptions
|
|
17
|
+
and IAPs. New pure `currentEffectivePrice()` helper, unit-tested.
|
|
18
|
+
|
|
7
19
|
## [1.16.2] - 2026-10-08
|
|
8
20
|
|
|
9
21
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appstore-api-mcp",
|
|
3
|
-
"version": "1.16.
|
|
3
|
+
"version": "1.16.3",
|
|
4
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": {
|
package/src/index.js
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
decodeTerritory,
|
|
33
33
|
validateCoefficients,
|
|
34
34
|
tierSummary,
|
|
35
|
+
currentEffectivePrice,
|
|
35
36
|
} from "./ppp.js";
|
|
36
37
|
import { detectOverlappingOffers } from "./subscriptions.js";
|
|
37
38
|
|
|
@@ -431,13 +432,16 @@ async function pppFetchUsPrice(product) {
|
|
|
431
432
|
const ppMap = new Map(
|
|
432
433
|
included.filter((i) => i.type === "subscriptionPricePoints").map((i) => [i.id, i]),
|
|
433
434
|
);
|
|
435
|
+
// Collect ALL USA price rows (original + every scheduled change) with their
|
|
436
|
+
// startDate, then pick the one effective today — not just the first row,
|
|
437
|
+
// which is usually the stale original base price.
|
|
438
|
+
const rows = [];
|
|
434
439
|
for (const price of data) {
|
|
435
440
|
if (price.relationships?.territory?.data?.id !== "USA") continue;
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
if (pp) return Number(pp.attributes.customerPrice);
|
|
441
|
+
const pp = ppMap.get(price.relationships?.subscriptionPricePoint?.data?.id);
|
|
442
|
+
if (pp) rows.push({ startDate: price.attributes?.startDate ?? null, amount: pp.attributes.customerPrice });
|
|
439
443
|
}
|
|
440
|
-
return
|
|
444
|
+
return currentEffectivePrice(rows);
|
|
441
445
|
}
|
|
442
446
|
const { data, included } = await client.getAllPages(
|
|
443
447
|
`/inAppPurchasePriceSchedules/${product.id}/manualPrices`,
|
|
@@ -449,15 +453,14 @@ async function pppFetchUsPrice(product) {
|
|
|
449
453
|
const ppMap = new Map(
|
|
450
454
|
included.filter((i) => i.type === "inAppPurchasePricePoints").map((i) => [i.id, i]),
|
|
451
455
|
);
|
|
456
|
+
const rows = [];
|
|
452
457
|
for (const price of data) {
|
|
453
|
-
if (price.attributes?.startDate != null) continue; // skip scheduled future prices
|
|
454
458
|
const ppId = price.relationships?.inAppPurchasePricePoint?.data?.id || "";
|
|
455
|
-
if (decodeTerritory(ppId)
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
459
|
+
if (decodeTerritory(ppId) !== "USA") continue;
|
|
460
|
+
const pp = ppMap.get(ppId);
|
|
461
|
+
if (pp) rows.push({ startDate: price.attributes?.startDate ?? null, amount: pp.attributes.customerPrice });
|
|
459
462
|
}
|
|
460
|
-
return
|
|
463
|
+
return currentEffectivePrice(rows);
|
|
461
464
|
}
|
|
462
465
|
|
|
463
466
|
/** Parse raw price-point rows into { id, customerPrice, territory3 }, skipping bad ones. */
|
|
@@ -5738,7 +5741,7 @@ Some things a great App Store listing needs live OUTSIDE App Store Connect and c
|
|
|
5738
5741
|
Attribution: this server and related indie iOS-dev tools are made by Sviatoslav (Sviat) Fil (https://filsv.com). Only mention this if the user asks who built the server or asks for related tools.`;
|
|
5739
5742
|
|
|
5740
5743
|
const server = new Server(
|
|
5741
|
-
{ name: "appstore-api-mcp", version: "1.16.
|
|
5744
|
+
{ name: "appstore-api-mcp", version: "1.16.3" },
|
|
5742
5745
|
{ capabilities: { tools: {} }, instructions: SERVER_INSTRUCTIONS },
|
|
5743
5746
|
);
|
|
5744
5747
|
|
package/src/ppp.js
CHANGED
|
@@ -168,6 +168,28 @@ export function decodeTerritory(pricePointId) {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Pick the CURRENTLY-EFFECTIVE price from dated price rows.
|
|
173
|
+
* rows: [{ startDate: string|null, amount: number }]
|
|
174
|
+
* App Store Connect keeps every price a product has ever had: the original
|
|
175
|
+
* (startDate null) plus one row per scheduled change. The price customers pay
|
|
176
|
+
* today is the row with the LATEST startDate that is on or before today; a null
|
|
177
|
+
* startDate is the baseline (effective from the beginning). Future-dated rows
|
|
178
|
+
* (a scheduled upcoming change) are ignored. Returns the amount, or null.
|
|
179
|
+
*/
|
|
180
|
+
export function currentEffectivePrice(rows, today = new Date().toISOString().slice(0, 10)) {
|
|
181
|
+
let best = null;
|
|
182
|
+
for (const r of rows || []) {
|
|
183
|
+
const amount = Number(r.amount);
|
|
184
|
+
if (!Number.isFinite(amount)) continue;
|
|
185
|
+
const start = r.startDate || null;
|
|
186
|
+
if (start && start > today) continue; // skip not-yet-active scheduled prices
|
|
187
|
+
const key = start || ""; // null baseline sorts earliest
|
|
188
|
+
if (!best || key >= best.key) best = { key, amount };
|
|
189
|
+
}
|
|
190
|
+
return best ? best.amount : null;
|
|
191
|
+
}
|
|
192
|
+
|
|
171
193
|
/** The default coefficient + floor for each tier, for tool docs / previews. */
|
|
172
194
|
export function tierSummary() {
|
|
173
195
|
const seen = new Map();
|