appstore-api-mcp 1.7.2 → 1.8.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/CHANGELOG.md +18 -0
- package/README.md +30 -10
- package/docs/TOOLS.md +24 -0
- package/package.json +1 -1
- package/src/index.js +206 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@ 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.8.1] - 2026-06-02
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Docs clarify that **build & ship** (`archive_app` / `upload_build` /
|
|
11
|
+
`bump_build_number`) is an optional, **Mac + Xcode** add-on — everything else
|
|
12
|
+
works from any OS. Added "build & ship" examples (archive, upload a new build)
|
|
13
|
+
to the README "What you can ask" section and refreshed the other groups.
|
|
14
|
+
|
|
15
|
+
## [1.8.0] - 2026-06-02
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **Build & ship from a Mac** (local Xcode tooling):
|
|
19
|
+
- `bump_build_number` — increment/set the build number via agvtool.
|
|
20
|
+
- `archive_app` — archive + export a signed `.ipa` via xcodebuild.
|
|
21
|
+
- `upload_build` — upload to App Store Connect via `xcrun altool`, reusing the
|
|
22
|
+
same API key; auto-places the `.p8` where altool expects it.
|
|
23
|
+
- Each tool returns friendly install guidance if Xcode/CLI tools are missing.
|
|
24
|
+
|
|
7
25
|
## [1.7.2] - 2026-06-02
|
|
8
26
|
|
|
9
27
|
### Changed
|
package/README.md
CHANGED
|
@@ -62,7 +62,9 @@ whatever AI agent you already use.
|
|
|
62
62
|
## Quick start
|
|
63
63
|
|
|
64
64
|
**Requirements:** Node.js ≥ 18 and an Apple Developer account with an
|
|
65
|
-
[App Store Connect API key](#getting-your-api-key).
|
|
65
|
+
[App Store Connect API key](#getting-your-api-key). Everything works from any
|
|
66
|
+
OS — *except* the optional **build & ship** tools (`archive_app` / `upload_build`),
|
|
67
|
+
which additionally need a **Mac with Xcode**.
|
|
66
68
|
|
|
67
69
|
### 🤖 Easiest: let your AI agent set it up (works with any agent)
|
|
68
70
|
|
|
@@ -253,6 +255,7 @@ Full parameter reference: **[docs/TOOLS.md](docs/TOOLS.md)**.
|
|
|
253
255
|
| `list_game_center_leaderboards` / `list_game_center_achievements` | 🎮 Game Center leaderboards & achievements |
|
|
254
256
|
| `signing_health` | 🔐 Flag **certificates & profiles expiring soon** (or invalid) across the account — catches CI breakage early |
|
|
255
257
|
| `list_bundle_ids` / `register_bundle_id` / `list_devices` / `register_device` / `list_certificates` / `create_certificate` / `revoke_certificate` / `list_profiles` / `create_profile` / `download_profile` / `delete_profile` | 🔏 **Provisioning & code signing** — bundle IDs, devices, certificates, and provisioning profiles |
|
|
258
|
+
| `bump_build_number` / `archive_app` / `upload_build` | 🛠️ **Build & ship from a Mac** — bump the build number (agvtool), archive + export a signed `.ipa` (xcodebuild), and upload to App Store Connect (`altool`, using your existing API key). Requires Xcode; tools explain how to install it if missing |
|
|
256
259
|
| `raw_request` | 🧰 Any method/path against the API — app previews, matchmaking, Xcode Cloud, anything not above |
|
|
257
260
|
|
|
258
261
|
> ⚙️ **Rate-limit aware:** the client automatically backs off and retries on
|
|
@@ -272,24 +275,41 @@ Once it's connected, just talk to your agent in plain language. A few things to
|
|
|
272
275
|
- *"Which of my apps are missing a subtitle or screenshots?"* (fleet audit)
|
|
273
276
|
- *"Tighten the keywords for <app> — dry-run it first so I can confirm."*
|
|
274
277
|
- *"Show me <app>'s current screenshots and flag any that look outdated."*
|
|
275
|
-
- *"Translate <app>'s description and keywords into German and French."*
|
|
278
|
+
- *"Translate <app>'s description and keywords into German and French."* (bulk localization)
|
|
276
279
|
|
|
277
|
-
**Performance**
|
|
280
|
+
**Performance & feedback**
|
|
278
281
|
- *"How many downloads did all my apps get last week?"*
|
|
279
282
|
- *"Pull last month's proceeds broken down by country."*
|
|
280
283
|
- *"How many active subscribers do I have, and what's the recent churn?"*
|
|
281
|
-
|
|
282
|
-
**Releases & the rest of the API** (via `raw_request`)
|
|
283
|
-
- *"Create a new App Store version (1.4.0) for <app>."*
|
|
284
284
|
- *"Summarize this week's 1-star reviews and draft polite replies."*
|
|
285
|
+
|
|
286
|
+
**Release management**
|
|
287
|
+
- *"Which of my apps are waiting for review, rejected, or ready to release?"* (fleet review board)
|
|
288
|
+
- *"Create a new App Store version 1.4.0 for <app>, then submit it for review."*
|
|
289
|
+
- *"Release <app> — it's approved and waiting for manual release."*
|
|
285
290
|
- *"List my latest TestFlight builds and which beta groups can see them."*
|
|
286
|
-
|
|
291
|
+
|
|
292
|
+
**Pipeline & accounts**
|
|
293
|
+
- *"Are any of my certificates or provisioning profiles expiring soon?"* (signing health)
|
|
294
|
+
- *"What's <app>'s price, and which territories is it available in?"*
|
|
295
|
+
|
|
296
|
+
**🛠️ Build & ship — *additional, Mac-only* (see note below)**
|
|
297
|
+
- *"Bump SpeakerMate's build number, archive it, and upload the new build to App Store Connect."*
|
|
298
|
+
- *"Create an archive of <app> and export a signed .ipa."*
|
|
299
|
+
- *"Upload this .ipa to App Store Connect."*
|
|
287
300
|
|
|
288
301
|
> **Dedicated tools cover it all:** app management, localization, screenshots
|
|
289
302
|
> (incl. *seeing* them), sales/subscriptions/analytics, ASO audit, dry-run,
|
|
290
|
-
>
|
|
291
|
-
>
|
|
292
|
-
> through the **`raw_request`** escape hatch — just ask.
|
|
303
|
+
> customer reviews, TestFlight, in-app purchases, pricing, availability, age-rating,
|
|
304
|
+
> submit/release, and signing health. Anything else in the App Store Connect API
|
|
305
|
+
> is still reachable through the **`raw_request`** escape hatch — just ask.
|
|
306
|
+
>
|
|
307
|
+
> 🛠️ **Build & ship is different — it's an optional, local add-on.** Almost every
|
|
308
|
+
> tool here talks to Apple's API and works from **any machine**. The three build
|
|
309
|
+
> tools (`bump_build_number`, `archive_app`, `upload_build`) instead run **local
|
|
310
|
+
> Xcode commands**, so they only work on a **Mac with Xcode installed** and an
|
|
311
|
+
> Xcode project on disk. If those aren't present the tools tell you exactly what
|
|
312
|
+
> to install; everything else keeps working regardless.
|
|
293
313
|
|
|
294
314
|
## Common workflows
|
|
295
315
|
|
package/docs/TOOLS.md
CHANGED
|
@@ -389,6 +389,30 @@ Lists certificates and provisioning profiles, flagging expired/expiring (within
|
|
|
389
389
|
### list_game_center_leaderboards / list_game_center_achievements
|
|
390
390
|
- `appId` **(required)** — requires Game Center enabled on the app.
|
|
391
391
|
|
|
392
|
+
## Build & ship (macOS + Xcode)
|
|
393
|
+
|
|
394
|
+
These run local Xcode tooling, so they only work on a Mac with Xcode installed.
|
|
395
|
+
Each returns clear install guidance if a tool is missing.
|
|
396
|
+
|
|
397
|
+
### bump_build_number
|
|
398
|
+
- `projectDir` **(required)** — folder containing the `.xcodeproj`
|
|
399
|
+
- `setTo` — exact build number (omit to increment by 1). Uses `agvtool`.
|
|
400
|
+
|
|
401
|
+
### archive_app
|
|
402
|
+
Archive + export a signed `.ipa` for App Store upload (`xcodebuild`). **Can take
|
|
403
|
+
several minutes** — your MCP client may need a longer tool timeout.
|
|
404
|
+
- `project` **or** `workspace` **(one required)** — absolute path
|
|
405
|
+
- `scheme` **(required)**, `configuration` (default Release)
|
|
406
|
+
- `exportMethod` (default `app-store-connect`), `teamId`, `outputDir`
|
|
407
|
+
- **Returns:** `{ ipaPath, archivePath, exportPath }`
|
|
408
|
+
|
|
409
|
+
### upload_build
|
|
410
|
+
Upload an `.ipa` via `xcrun altool --upload-app`, using your App Store Connect
|
|
411
|
+
API key (`ASC_KEY_ID` / `ASC_ISSUER_ID`). The `.p8` is auto-placed where altool
|
|
412
|
+
looks (`~/.appstoreconnect/private_keys/`). After processing, the build appears
|
|
413
|
+
in `list_builds` and can be submitted with `submit_for_review`.
|
|
414
|
+
- `ipaPath` **(required)**, `platform` (default `ios`), `apiKey`, `apiIssuer`
|
|
415
|
+
|
|
392
416
|
---
|
|
393
417
|
|
|
394
418
|
## Rate limits
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appstore-api-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
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
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
readFileSync,
|
|
4
|
+
writeFileSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
existsSync,
|
|
7
|
+
copyFileSync,
|
|
8
|
+
readdirSync,
|
|
9
|
+
} from "node:fs";
|
|
10
|
+
import { basename, join } from "node:path";
|
|
11
|
+
import { homedir, tmpdir } from "node:os";
|
|
12
|
+
import { execFile } from "node:child_process";
|
|
4
13
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
14
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
15
|
import {
|
|
@@ -131,6 +140,61 @@ const EDITABLE_VERSION_STATES = new Set([
|
|
|
131
140
|
// Optional default Vendor Number for sales/finance reports.
|
|
132
141
|
const DEFAULT_VENDOR = process.env.ASC_VENDOR_NUMBER;
|
|
133
142
|
|
|
143
|
+
// ---- Local build tooling (archive & upload) helpers ----
|
|
144
|
+
|
|
145
|
+
/** Run a command, capturing output. timeout 0 = no timeout (for long archives). */
|
|
146
|
+
function runCmd(cmd, args, opts = {}) {
|
|
147
|
+
return new Promise((resolve) => {
|
|
148
|
+
execFile(
|
|
149
|
+
cmd,
|
|
150
|
+
args,
|
|
151
|
+
{
|
|
152
|
+
cwd: opts.cwd,
|
|
153
|
+
timeout: opts.timeout || 0,
|
|
154
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
155
|
+
env: process.env,
|
|
156
|
+
},
|
|
157
|
+
(err, stdout, stderr) => {
|
|
158
|
+
resolve({
|
|
159
|
+
code: err && typeof err.code === "number" ? err.code : err ? 1 : 0,
|
|
160
|
+
stdout: stdout || "",
|
|
161
|
+
stderr: stderr || "",
|
|
162
|
+
error: err ? err.message : null,
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const tail = (s, n = 40) => (s || "").split("\n").slice(-n).join("\n");
|
|
170
|
+
|
|
171
|
+
/** Throw a friendly install-guidance error if Xcode CLI tools aren't available. */
|
|
172
|
+
async function ensureXcode() {
|
|
173
|
+
if (process.platform !== "darwin")
|
|
174
|
+
throw new Error(
|
|
175
|
+
"Archiving/uploading requires macOS with Xcode. These build tools only run on a Mac.",
|
|
176
|
+
);
|
|
177
|
+
const sel = await runCmd("xcode-select", ["-p"]);
|
|
178
|
+
if (sel.code !== 0)
|
|
179
|
+
throw new Error(
|
|
180
|
+
"Xcode command-line tools not found. To fix: 1) install Xcode from the Mac App Store, 2) run `xcode-select --install` (or, if Xcode is already installed, `sudo xcode-select -s /Applications/Xcode.app/Contents/Developer`), then verify with `xcodebuild -version`.",
|
|
181
|
+
);
|
|
182
|
+
return sel.stdout.trim();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Make sure altool can find the .p8: copy it to ~/.appstoreconnect/private_keys/. */
|
|
186
|
+
function ensureAltoolKey(keyId) {
|
|
187
|
+
const src = process.env.ASC_PRIVATE_KEY_PATH;
|
|
188
|
+
if (!src || !existsSync(src)) return false;
|
|
189
|
+
const dir = join(homedir(), ".appstoreconnect", "private_keys");
|
|
190
|
+
const dest = join(dir, `AuthKey_${keyId}.p8`);
|
|
191
|
+
if (!existsSync(dest)) {
|
|
192
|
+
mkdirSync(dir, { recursive: true });
|
|
193
|
+
copyFileSync(src, dest);
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
|
|
134
198
|
/** Cap parsed report rows so large reports don't flood the response. */
|
|
135
199
|
function reportResult(reportType, parsed, limit = 200) {
|
|
136
200
|
const rows = parsed.rows;
|
|
@@ -2001,6 +2065,145 @@ const tools = [
|
|
|
2001
2065
|
},
|
|
2002
2066
|
},
|
|
2003
2067
|
|
|
2068
|
+
// ---- Local build: archive & upload (macOS + Xcode) ----
|
|
2069
|
+
{
|
|
2070
|
+
name: "bump_build_number",
|
|
2071
|
+
description:
|
|
2072
|
+
"Increment (or set) an Xcode project's build number (CFBundleVersion / CURRENT_PROJECT_VERSION) via agvtool. macOS + Xcode required. Pass projectDir = the folder containing the .xcodeproj.",
|
|
2073
|
+
inputSchema: {
|
|
2074
|
+
type: "object",
|
|
2075
|
+
properties: {
|
|
2076
|
+
projectDir: { type: "string", description: "Folder containing the .xcodeproj" },
|
|
2077
|
+
setTo: { type: "string", description: "Set to this exact build number; omit to increment by 1" },
|
|
2078
|
+
},
|
|
2079
|
+
required: ["projectDir"],
|
|
2080
|
+
},
|
|
2081
|
+
run: async (a) => {
|
|
2082
|
+
await ensureXcode();
|
|
2083
|
+
const cur = await runCmd("xcrun", ["agvtool", "what-version", "-terse"], { cwd: a.projectDir });
|
|
2084
|
+
const previous = (cur.stdout || "").trim();
|
|
2085
|
+
const res = a.setTo
|
|
2086
|
+
? await runCmd("xcrun", ["agvtool", "new-version", "-all", a.setTo], { cwd: a.projectDir })
|
|
2087
|
+
: await runCmd("xcrun", ["agvtool", "next-version", "-all"], { cwd: a.projectDir });
|
|
2088
|
+
if (res.code !== 0)
|
|
2089
|
+
return {
|
|
2090
|
+
error:
|
|
2091
|
+
"agvtool failed — ensure the project's Versioning System is 'Apple Generic' (target → Build Settings → Versioning), or set the build number in Xcode manually.",
|
|
2092
|
+
detail: tail(res.stderr || res.stdout, 8),
|
|
2093
|
+
previous,
|
|
2094
|
+
};
|
|
2095
|
+
const after = await runCmd("xcrun", ["agvtool", "what-version", "-terse"], { cwd: a.projectDir });
|
|
2096
|
+
return { previous, current: (after.stdout || "").trim() };
|
|
2097
|
+
},
|
|
2098
|
+
},
|
|
2099
|
+
{
|
|
2100
|
+
name: "archive_app",
|
|
2101
|
+
description:
|
|
2102
|
+
"Archive an Xcode app and export a signed .ipa ready for App Store upload (xcodebuild archive + -exportArchive). macOS + Xcode required. Returns the .ipa path. CAN TAKE SEVERAL MINUTES — your MCP client may need a longer tool timeout; xcodebuild keeps running server-side regardless.",
|
|
2103
|
+
inputSchema: {
|
|
2104
|
+
type: "object",
|
|
2105
|
+
properties: {
|
|
2106
|
+
project: { type: "string", description: "Absolute path to the .xcodeproj" },
|
|
2107
|
+
workspace: { type: "string", description: "Absolute path to the .xcworkspace (use instead of project)" },
|
|
2108
|
+
scheme: { type: "string" },
|
|
2109
|
+
configuration: { type: "string", description: "Release (default)" },
|
|
2110
|
+
exportMethod: { type: "string", description: "app-store-connect (default), release-testing, enterprise, …" },
|
|
2111
|
+
teamId: { type: "string", description: "Signing team id (optional)" },
|
|
2112
|
+
outputDir: { type: "string", description: "Where to write the archive + ipa (default: a temp dir)" },
|
|
2113
|
+
},
|
|
2114
|
+
required: ["scheme"],
|
|
2115
|
+
},
|
|
2116
|
+
run: async (a) => {
|
|
2117
|
+
await ensureXcode();
|
|
2118
|
+
if (!a.project && !a.workspace)
|
|
2119
|
+
return { error: "Provide either project (.xcodeproj) or workspace (.xcworkspace)." };
|
|
2120
|
+
const safe = a.scheme.replace(/\W+/g, "_");
|
|
2121
|
+
const out = a.outputDir || join(tmpdir(), `asc-archive-${safe}`);
|
|
2122
|
+
mkdirSync(out, { recursive: true });
|
|
2123
|
+
const archivePath = join(out, `${safe}.xcarchive`);
|
|
2124
|
+
const exportPath = join(out, "export");
|
|
2125
|
+
const target = a.workspace
|
|
2126
|
+
? ["-workspace", a.workspace]
|
|
2127
|
+
: ["-project", a.project];
|
|
2128
|
+
const archiveArgs = [
|
|
2129
|
+
...target,
|
|
2130
|
+
"-scheme", a.scheme,
|
|
2131
|
+
"-configuration", a.configuration || "Release",
|
|
2132
|
+
"-destination", "generic/platform=iOS",
|
|
2133
|
+
"-archivePath", archivePath,
|
|
2134
|
+
"archive",
|
|
2135
|
+
"-allowProvisioningUpdates",
|
|
2136
|
+
];
|
|
2137
|
+
const arch = await runCmd("xcodebuild", archiveArgs);
|
|
2138
|
+
if (arch.code !== 0)
|
|
2139
|
+
return { step: "archive", error: "xcodebuild archive failed", log: tail(arch.stdout + "\n" + arch.stderr, 50) };
|
|
2140
|
+
const plistPath = join(out, "ExportOptions.plist");
|
|
2141
|
+
const method = a.exportMethod || "app-store-connect";
|
|
2142
|
+
writeFileSync(
|
|
2143
|
+
plistPath,
|
|
2144
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
2145
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
2146
|
+
<plist version="1.0"><dict>
|
|
2147
|
+
<key>method</key><string>${method}</string>
|
|
2148
|
+
<key>signingStyle</key><string>automatic</string>
|
|
2149
|
+
${a.teamId ? `<key>teamID</key><string>${a.teamId}</string>\n` : ""}<key>uploadSymbols</key><true/>
|
|
2150
|
+
</dict></plist>
|
|
2151
|
+
`,
|
|
2152
|
+
);
|
|
2153
|
+
const exp = await runCmd("xcodebuild", [
|
|
2154
|
+
"-exportArchive",
|
|
2155
|
+
"-archivePath", archivePath,
|
|
2156
|
+
"-exportOptionsPlist", plistPath,
|
|
2157
|
+
"-exportPath", exportPath,
|
|
2158
|
+
"-allowProvisioningUpdates",
|
|
2159
|
+
]);
|
|
2160
|
+
if (exp.code !== 0)
|
|
2161
|
+
return { step: "export", error: "xcodebuild -exportArchive failed", log: tail(exp.stdout + "\n" + exp.stderr, 50) };
|
|
2162
|
+
const ipa = existsSync(exportPath)
|
|
2163
|
+
? readdirSync(exportPath).find((f) => f.endsWith(".ipa"))
|
|
2164
|
+
: null;
|
|
2165
|
+
if (!ipa)
|
|
2166
|
+
return { error: "No .ipa was produced.", exportPath, files: existsSync(exportPath) ? readdirSync(exportPath) : [] };
|
|
2167
|
+
return { ipaPath: join(exportPath, ipa), archivePath, exportPath };
|
|
2168
|
+
},
|
|
2169
|
+
},
|
|
2170
|
+
{
|
|
2171
|
+
name: "upload_build",
|
|
2172
|
+
description:
|
|
2173
|
+
"Upload an .ipa to App Store Connect via `xcrun altool --upload-app`, using your App Store Connect API key (the same ASC_KEY_ID / ASC_ISSUER_ID this server already uses). macOS + Xcode required. After it finishes processing (minutes), the build appears in list_builds and can be submitted with submit_for_review.",
|
|
2174
|
+
inputSchema: {
|
|
2175
|
+
type: "object",
|
|
2176
|
+
properties: {
|
|
2177
|
+
ipaPath: { type: "string" },
|
|
2178
|
+
platform: { type: "string", description: "ios (default), macos, tvos" },
|
|
2179
|
+
apiKey: { type: "string", description: "Override ASC_KEY_ID" },
|
|
2180
|
+
apiIssuer: { type: "string", description: "Override ASC_ISSUER_ID" },
|
|
2181
|
+
},
|
|
2182
|
+
required: ["ipaPath"],
|
|
2183
|
+
},
|
|
2184
|
+
run: async (a) => {
|
|
2185
|
+
await ensureXcode();
|
|
2186
|
+
if (!existsSync(a.ipaPath))
|
|
2187
|
+
return { error: `File not found: ${a.ipaPath}` };
|
|
2188
|
+
const keyId = a.apiKey || process.env.ASC_KEY_ID;
|
|
2189
|
+
const issuer = a.apiIssuer || process.env.ASC_ISSUER_ID;
|
|
2190
|
+
if (!keyId || !issuer)
|
|
2191
|
+
return { error: "apiKey + apiIssuer required (or set ASC_KEY_ID / ASC_ISSUER_ID)." };
|
|
2192
|
+
ensureAltoolKey(keyId);
|
|
2193
|
+
const res = await runCmd("xcrun", [
|
|
2194
|
+
"altool",
|
|
2195
|
+
"--upload-app",
|
|
2196
|
+
"-t", a.platform || "ios",
|
|
2197
|
+
"-f", a.ipaPath,
|
|
2198
|
+
"--apiKey", keyId,
|
|
2199
|
+
"--apiIssuer", issuer,
|
|
2200
|
+
]);
|
|
2201
|
+
if (res.code !== 0)
|
|
2202
|
+
return { error: "Upload failed", log: tail(res.stdout + "\n" + res.stderr, 40) };
|
|
2203
|
+
return { uploaded: true, output: tail(res.stdout + "\n" + res.stderr, 20) };
|
|
2204
|
+
},
|
|
2205
|
+
},
|
|
2206
|
+
|
|
2004
2207
|
// ---- Generic escape hatch ----
|
|
2005
2208
|
{
|
|
2006
2209
|
name: "raw_request",
|
|
@@ -2044,7 +2247,7 @@ Some things a great App Store listing needs live OUTSIDE App Store Connect and c
|
|
|
2044
2247
|
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.`;
|
|
2045
2248
|
|
|
2046
2249
|
const server = new Server(
|
|
2047
|
-
{ name: "appstore-api-mcp", version: "1.
|
|
2250
|
+
{ name: "appstore-api-mcp", version: "1.8.1" },
|
|
2048
2251
|
{ capabilities: { tools: {} }, instructions: SERVER_INSTRUCTIONS },
|
|
2049
2252
|
);
|
|
2050
2253
|
|