@ggaiteam/appstore-connect-mcp 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 appstore-connect-mcp contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,353 @@
1
+ # App Store Connect MCP
2
+
3
+ A [Model Context Protocol](https://modelcontextprotocol.io/) server that exposes the entire **Apple App Store Connect API** (1,200+ operations) as MCP tools. Query apps, manage builds, handle submissions, read analytics, manage users, and more — all from your AI assistant.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@ggaiteam/appstore-connect-mcp.svg)](https://www.npmjs.com/package/@ggaiteam/appstore-connect-mcp)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org/)
8
+
9
+ ## Features
10
+
11
+ - **Complete API coverage** — all 1,216 operations from the App Store Connect API v4.4
12
+ - **Tool search** — `search_apis` meta-tool to find the right operation among 1,200+
13
+ - **Two transports** — `stdio` for local use (Claude Desktop, Cursor), `HTTP` for remote deployment
14
+ - **JWT authentication** — automatic ES256 token generation and caching
15
+ - **Docker ready** — multi-stage Dockerfile with health checks
16
+ - **Auto-publish** — GitHub Actions workflow for npm publishing on release
17
+
18
+ ## Quick Start
19
+
20
+ ### 1. Get API Credentials
21
+
22
+ 1. Go to [App Store Connect → Users and Access → Keys](https://appstoreconnect.apple.com/access/api)
23
+ 2. Click **Generate API Key** (or use an existing one)
24
+ 3. Note down:
25
+ - **Issuer ID** — shown at the top of the Keys page
26
+ - **Key ID** — shown in the key list
27
+ - **Private Key (.p8 file)** — download it (only available once)
28
+
29
+ > The key needs at least **App Manager** or **Admin** role for full functionality.
30
+
31
+ ### 2. Install
32
+
33
+ #### Option A: npm (recommended)
34
+
35
+ ```bash
36
+ npm install -g @ggaiteam/appstore-connect-mcp
37
+ ```
38
+
39
+ #### Option B: One-line installer
40
+
41
+ ```bash
42
+ curl -fsSL https://raw.githubusercontent.com/topcheer/appstore-connect-mcp/main/scripts/install.sh | bash
43
+ ```
44
+
45
+ #### Option C: Docker
46
+
47
+ ```bash
48
+ docker pull ghcr.io/topcheer/appstore-connect-mcp:latest
49
+ ```
50
+
51
+ ### 3. Configure Your MCP Client
52
+
53
+ #### Claude Desktop
54
+
55
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
56
+
57
+ ```json
58
+ {
59
+ "mcpServers": {
60
+ "appstore-connect": {
61
+ "command": "appstore-connect-mcp",
62
+ "env": {
63
+ "APP_STORE_CONNECT_ISSUER_ID": "your-issuer-id",
64
+ "APP_STORE_CONNECT_KEY_ID": "your-key-id",
65
+ "APP_STORE_CONNECT_P8_FILE": "/path/to/AuthKey_XXXXXXXXXX.p8"
66
+ }
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ #### Cursor
73
+
74
+ Add to your Cursor MCP settings:
75
+
76
+ ```json
77
+ {
78
+ "mcpServers": {
79
+ "appstore-connect": {
80
+ "command": "npx",
81
+ "args": ["@ggaiteam/appstore-connect-mcp"],
82
+ "env": {
83
+ "APP_STORE_CONNECT_ISSUER_ID": "your-issuer-id",
84
+ "APP_STORE_CONNECT_KEY_ID": "your-key-id",
85
+ "APP_STORE_CONNECT_P8_FILE": "/path/to/AuthKey_XXXXXXXXXX.p8"
86
+ }
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ > **Alternatively**, inline the private key instead of a file path:
93
+ > ```json
94
+ > "APP_STORE_CONNECT_PRIVATE_KEY": "-----BEGIN PRIVATE KEY-----\nMIGTAg...\n-----END PRIVATE KEY-----"
95
+ > ```
96
+
97
+ Restart your client. You should now have access to all App Store Connect API tools.
98
+
99
+ ## Usage Examples
100
+
101
+ Once connected, ask your AI assistant:
102
+
103
+ > "List all my apps on App Store Connect"
104
+
105
+ > "Show me the latest build for bundle ID com.example.myapp"
106
+
107
+ > "Get all pending app review submissions"
108
+
109
+ > "Search for subscription-related API operations"
110
+
111
+ The AI uses the `search_apis` meta-tool to discover available operations, then calls them.
112
+
113
+ ### Meta-Tools
114
+
115
+ | Tool | Description |
116
+ |------|-------------|
117
+ | `search_apis` | Search API operations by keyword, category, or HTTP method |
118
+ | `list_categories` | List all 192 API resource categories |
119
+ | `get_tool_details` | Get full parameter details for a specific operation |
120
+
121
+ ### Example Tool Calls
122
+
123
+ The AI can call tools like:
124
+ - `apps_getCollection` — list all apps
125
+ - `builds_getCollection` — list builds with filters
126
+ - `appStoreVersions_getCollection` — get app versions
127
+ - `betaTesters_getCollection` — list beta testers
128
+ - `salesReports_getCollection` — download sales reports
129
+ - `userInvitations_createInstance` — invite a new team member
130
+
131
+ ## Remote Deployment (HTTP Mode)
132
+
133
+ ### Docker Compose
134
+
135
+ ```bash
136
+ # 1. Create .env file
137
+ cp .env.example .env
138
+ # Edit .env with your credentials
139
+
140
+ # 2. Start
141
+ docker compose up -d
142
+ ```
143
+
144
+ The server is available at `http://localhost:3000/mcp`.
145
+
146
+ ### Docker (manual)
147
+
148
+ ```bash
149
+ docker run -d \
150
+ --name appstore-connect-mcp \
151
+ -p 3000:3000 \
152
+ -e APP_STORE_CONNECT_ISSUER_ID=your-issuer-id \
153
+ -e APP_STORE_CONNECT_KEY_ID=your-key-id \
154
+ -e APP_STORE_CONNECT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----" \
155
+ ghcr.io/topcheer/appstore-connect-mcp:latest
156
+ ```
157
+
158
+ ### Health Check
159
+
160
+ ```bash
161
+ curl http://localhost:3000/health
162
+ # {"status":"ok","server":"appstore-connect-mcp","version":"1.0.0"}
163
+ ```
164
+
165
+ ### Connect Remote MCP to Claude Desktop
166
+
167
+ ```json
168
+ {
169
+ "mcpServers": {
170
+ "appstore-connect": {
171
+ "url": "http://your-server:3000/mcp"
172
+ }
173
+ }
174
+ }
175
+ ```
176
+
177
+ ## CLI Usage
178
+
179
+ ```bash
180
+ # Stdio mode (default — for local MCP clients)
181
+ appstore-connect-mcp
182
+
183
+ # HTTP mode (for remote deployment)
184
+ appstore-connect-mcp --transport http --port 3000 --host 0.0.0.0
185
+
186
+ # With verbose logging
187
+ appstore-connect-mcp --verbose
188
+ ```
189
+
190
+ ### CLI Flags
191
+
192
+ | Flag | Default | Description |
193
+ |------|---------|-------------|
194
+ | `--transport` | `stdio` | Transport mode: `stdio` or `http` |
195
+ | `--port` | `3000` | HTTP port (HTTP mode only) |
196
+ | `--host` | `0.0.0.0` | HTTP bind host |
197
+ | `--issuer-id` | env | App Store Connect issuer ID |
198
+ | `--key-id` | env | API key ID |
199
+ | `--p8-file` | env | Path to .p8 private key file |
200
+ | `--verbose` | off | Enable verbose logging |
201
+
202
+ ### Environment Variables
203
+
204
+ | Variable | Description |
205
+ |----------|-------------|
206
+ | `APP_STORE_CONNECT_ISSUER_ID` | Issuer ID from App Store Connect |
207
+ | `APP_STORE_CONNECT_KEY_ID` | Key ID |
208
+ | `APP_STORE_CONNECT_PRIVATE_KEY` | PEM private key content (inline) |
209
+ | `APP_STORE_CONNECT_P8_FILE` | Path to .p8 file (alternative to above) |
210
+ | `MCP_TRANSPORT` | `stdio` or `http` |
211
+ | `MCP_PORT` | HTTP port |
212
+ | `MCP_HOST` | HTTP host |
213
+ | `MCP_VERBOSE` | `1` to enable verbose logging |
214
+
215
+ ## Architecture
216
+
217
+ ```
218
+ ┌──────────────────┐ ┌──────────────────┐
219
+ │ MCP Client │ │ MCP Server │
220
+ │ (Claude, etc.) │◄───►│ │
221
+ └──────────────────┘ │ ┌────────────┐ │ ┌─────────────────┐
222
+ │ │ Tool │ │ │ App Store │
223
+ stdio or HTTP/SSE │ │ Registry │──┼────►│ Connect API │
224
+ │ │ (1,216 │ │ │ api.appstore │
225
+ │ │ tools) │ │ │ connect.apple │
226
+ │ └────────────┘ │ │ .com │
227
+ │ │ │ └─────────────────┘
228
+ │ ┌────▼─────┐ │ ▲
229
+ │ │ JWT Auth │ │ │
230
+ │ │ (ES256) │────┼────────────┘
231
+ │ └──────────┘ │
232
+ └──────────────────┘
233
+ ```
234
+
235
+ - **Tool data** is generated from Apple's OpenAPI spec (`scripts/generate-tools.py`)
236
+ - **Runtime** loads `tools.json` and registers all tools dynamically
237
+ - **JWT tokens** are cached and auto-refreshed (20-minute TTL)
238
+ - **Responses** are truncated at 50KB to fit LLM context windows
239
+
240
+ ### Regenerating Tools
241
+
242
+ When Apple updates their API:
243
+
244
+ ```bash
245
+ # Download the latest OpenAPI spec
246
+ # https://developer.apple.com/app-store-connect/
247
+
248
+ # Generate updated tools.json
249
+ python3 scripts/generate-tools.py openapi.oas.json src/tools.json
250
+
251
+ # Rebuild
252
+ npm run build
253
+ ```
254
+
255
+ ## Development
256
+
257
+ ```bash
258
+ # Clone
259
+ git clone https://github.com/topcheer/appstore-connect-mcp.git
260
+ cd appstore-connect-mcp
261
+
262
+ # Install
263
+ npm install
264
+
265
+ # Generate tools from OpenAPI spec
266
+ npm run generate
267
+
268
+ # Build
269
+ npm run build
270
+
271
+ # Run locally
272
+ APP_STORE_CONNECT_ISSUER_ID=... \
273
+ APP_STORE_CONNECT_KEY_ID=... \
274
+ APP_STORE_CONNECT_P8_FILE=... \
275
+ npm start
276
+ ```
277
+
278
+ ### Project Structure
279
+
280
+ ```
281
+ ├── scripts/
282
+ │ ├── generate-tools.py # OpenAPI → tools.json generator
283
+ │ └── install.sh # One-line installer
284
+ ├── src/
285
+ │ ├── index.ts # Entry point + CLI
286
+ │ ├── server.ts # MCP server (tool registry + dispatch)
287
+ │ ├── transport.ts # stdio + HTTP transports
288
+ │ ├── auth.ts # JWT (ES256) token generation
289
+ │ ├── client.ts # App Store Connect API client
290
+ │ ├── tools.ts # Tool schema builder + executor
291
+ │ ├── types.ts # TypeScript type definitions
292
+ │ └── tools.json # Generated tool definitions (1,216 ops)
293
+ ├── Dockerfile # Multi-stage Docker build
294
+ ├── docker-compose.yml # Remote deployment config
295
+ ├── .github/workflows/
296
+ │ ├── ci.yml # Lint + build + test
297
+ │ ├── npm-publish.yml # Auto-publish to npm on release
298
+ │ └── docker.yml # Build + push Docker image
299
+ └── package.json
300
+ ```
301
+
302
+ ## npm Publishing
303
+
304
+ Publishing is automated via GitHub Actions:
305
+
306
+ 1. **Create a release** on GitHub (tag format: `v1.0.0`)
307
+ 2. The `npm-publish.yml` workflow automatically:
308
+ - Builds the package
309
+ - Publishes to npm
310
+ - With [provenance](https://docs.npmjs.com/generating-provenance-statements)
311
+
312
+ ### First-time Setup
313
+
314
+ 1. Create an npm access token: https://www.npmjs.com/settings/~/tokens
315
+ 2. Add it as a repository secret: `NPM_TOKEN`
316
+ 3. Create a GitHub release — done!
317
+
318
+ ### Manual Publishing
319
+
320
+ ```bash
321
+ npm version patch # or minor/major
322
+ npm run build
323
+ npm publish
324
+ ```
325
+
326
+ ## API Coverage
327
+
328
+ This server covers **all 1,216 operations** across the App Store Connect API:
329
+
330
+ | Method | Count |
331
+ |--------|-------|
332
+ | GET | 768 |
333
+ | POST | 168 |
334
+ | PATCH | 153 |
335
+ | DELETE | 127 |
336
+
337
+ Including: Apps, Builds, App Store Versions, Beta Testing, Subscriptions, In-App Purchases, User Management, Sales Reports, Analytics, App Clips, Game Center, and more (192 categories total).
338
+
339
+ ## Security
340
+
341
+ - Private keys are read from environment variables or files — never logged
342
+ - JWT tokens are short-lived (20 minutes max) and cached in memory only
343
+ - No data is stored or persisted between requests
344
+ - For remote deployment, use HTTPS/TLS termination at your reverse proxy
345
+
346
+ ## License
347
+
348
+ MIT — see [LICENSE](LICENSE)
349
+
350
+ ## Acknowledgments
351
+
352
+ - [Apple App Store Connect API](https://developer.apple.com/app-store-connect/) — API and OpenAPI specification
353
+ - [Model Context Protocol](https://modelcontextprotocol.io/) — Protocol specification
package/dist/auth.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * auth.ts — JWT token generation for App Store Connect API.
3
+ *
4
+ * Apple's App Store Connect API authenticates using JWT signed with
5
+ * ES256 (ECDSA P-256 + SHA-256). The private key comes from a .p8 file
6
+ * downloaded from App Store Connect → Users and Access → Keys.
7
+ */
8
+ import type { ASCCredentials } from "./types.js";
9
+ /**
10
+ * Generate (or return cached) a signed JWT for the App Store Connect API.
11
+ *
12
+ * @param creds The issuer ID, key ID, and PEM private key
13
+ * @param force Force a fresh token even if the cache is still valid
14
+ */
15
+ export declare function getToken(creds: ASCCredentials, force?: boolean): string;
16
+ /**
17
+ * Parse a .p8 file content into a PEM string suitable for jwt.sign().
18
+ * Handles both raw PEM and the Apple AuthKey format.
19
+ */
20
+ export declare function parsePrivateKey(raw: string): string;
21
+ /**
22
+ * Validate that credentials look reasonable.
23
+ * Throws a descriptive Error if something is missing.
24
+ */
25
+ export declare function validateCredentials(creds: ASCCredentials): void;
26
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AASjD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,UAAQ,GAAG,MAAM,CAsBrE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAgBnD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAgB/D"}
package/dist/auth.js ADDED
@@ -0,0 +1,72 @@
1
+ /**
2
+ * auth.ts — JWT token generation for App Store Connect API.
3
+ *
4
+ * Apple's App Store Connect API authenticates using JWT signed with
5
+ * ES256 (ECDSA P-256 + SHA-256). The private key comes from a .p8 file
6
+ * downloaded from App Store Connect → Users and Access → Keys.
7
+ */
8
+ import jwt from "jsonwebtoken";
9
+ const AUDIENCE = "appstoreconnect-v1";
10
+ const TOKEN_TTL_SECONDS = 20 * 60; // 20 minutes (Apple allows max 20)
11
+ /** Cached token to avoid re-signing on every request. */
12
+ let cachedToken = null;
13
+ let cachedExpiry = 0;
14
+ /**
15
+ * Generate (or return cached) a signed JWT for the App Store Connect API.
16
+ *
17
+ * @param creds The issuer ID, key ID, and PEM private key
18
+ * @param force Force a fresh token even if the cache is still valid
19
+ */
20
+ export function getToken(creds, force = false) {
21
+ const now = Math.floor(Date.now() / 1000);
22
+ // Return cached token if it has >60s of life left
23
+ if (!force && cachedToken && now < cachedExpiry - 60) {
24
+ return cachedToken;
25
+ }
26
+ const payload = {
27
+ iss: creds.issuerId,
28
+ iat: now,
29
+ exp: now + TOKEN_TTL_SECONDS,
30
+ aud: AUDIENCE,
31
+ };
32
+ cachedToken = jwt.sign(payload, creds.privateKey, {
33
+ algorithm: "ES256",
34
+ keyid: creds.keyId,
35
+ });
36
+ cachedExpiry = now + TOKEN_TTL_SECONDS;
37
+ return cachedToken;
38
+ }
39
+ /**
40
+ * Parse a .p8 file content into a PEM string suitable for jwt.sign().
41
+ * Handles both raw PEM and the Apple AuthKey format.
42
+ */
43
+ export function parsePrivateKey(raw) {
44
+ const trimmed = raw.trim();
45
+ // Already in PEM format
46
+ if (trimmed.includes("-----BEGIN PRIVATE KEY-----")) {
47
+ return trimmed;
48
+ }
49
+ // Apple .p8 files are usually already PEM, but handle edge cases
50
+ // where the header might be missing
51
+ if (trimmed.includes("-----BEGIN")) {
52
+ return trimmed;
53
+ }
54
+ // Try wrapping raw base64 content in PEM headers
55
+ return `-----BEGIN PRIVATE KEY-----\n${trimmed}\n-----END PRIVATE KEY-----`;
56
+ }
57
+ /**
58
+ * Validate that credentials look reasonable.
59
+ * Throws a descriptive Error if something is missing.
60
+ */
61
+ export function validateCredentials(creds) {
62
+ if (!creds.issuerId) {
63
+ throw new Error("Missing APP_STORE_CONNECT_ISSUER_ID. Set it via env or CLI flag.");
64
+ }
65
+ if (!creds.keyId) {
66
+ throw new Error("Missing APP_STORE_CONNECT_KEY_ID. Set it via env or CLI flag.");
67
+ }
68
+ if (!creds.privateKey) {
69
+ throw new Error("Missing APP_STORE_CONNECT_PRIVATE_KEY. Provide the .p8 file path via APP_STORE_CONNECT_P8_FILE or the key content via the env var.");
70
+ }
71
+ }
72
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,GAAG,MAAM,cAAc,CAAC;AAG/B,MAAM,QAAQ,GAAG,oBAAoB,CAAC;AACtC,MAAM,iBAAiB,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,mCAAmC;AAEtE,yDAAyD;AACzD,IAAI,WAAW,GAAkB,IAAI,CAAC;AACtC,IAAI,YAAY,GAAG,CAAC,CAAC;AAErB;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAqB,EAAE,KAAK,GAAG,KAAK;IAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAE1C,kDAAkD;IAClD,IAAI,CAAC,KAAK,IAAI,WAAW,IAAI,GAAG,GAAG,YAAY,GAAG,EAAE,EAAE,CAAC;QACrD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,MAAM,OAAO,GAAG;QACd,GAAG,EAAE,KAAK,CAAC,QAAQ;QACnB,GAAG,EAAE,GAAG;QACR,GAAG,EAAE,GAAG,GAAG,iBAAiB;QAC5B,GAAG,EAAE,QAAQ;KACd,CAAC;IAEF,WAAW,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,UAAU,EAAE;QAChD,SAAS,EAAE,OAAO;QAClB,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,CAAC,CAAC;IACH,YAAY,GAAG,GAAG,GAAG,iBAAiB,CAAC;IAEvC,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAE3B,wBAAwB;IACxB,IAAI,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAAE,CAAC;QACpD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,iEAAiE;IACjE,oCAAoC;IACpC,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACnC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,iDAAiD;IACjD,OAAO,gCAAgC,OAAO,6BAA6B,CAAC;AAC9E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAqB;IACvD,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,+DAA+D,CAChE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,oIAAoI,CACrI,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * client.ts — HTTP client for the App Store Connect REST API.
3
+ *
4
+ * Handles JWT authentication, request building, JSON:API conventions,
5
+ * error normalisation, and response formatting.
6
+ */
7
+ import type { ASCCredentials } from "./types.js";
8
+ export interface ApiRequestOptions {
9
+ method: string;
10
+ path: string;
11
+ pathParams?: Record<string, string>;
12
+ queryParams?: Record<string, string | string[]>;
13
+ body?: unknown;
14
+ credentials: ASCCredentials;
15
+ }
16
+ /**
17
+ * Execute a single App Store Connect API request.
18
+ *
19
+ * @returns the parsed JSON response body (or null for 204).
20
+ * @throws Error with a descriptive message on failure.
21
+ */
22
+ export declare function callApi(opts: ApiRequestOptions): Promise<unknown>;
23
+ /** Structured error from the App Store Connect API. */
24
+ export declare class ApiError extends Error {
25
+ status: number;
26
+ detail: unknown;
27
+ method: string;
28
+ url: string;
29
+ constructor(status: number, detail: unknown, method: string, url: string);
30
+ }
31
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,cAAc,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAoEvE;AAED,uDAAuD;AACvD,qBAAa,QAAS,SAAQ,KAAK;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;gBAEA,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;CAYzE"}
package/dist/client.js ADDED
@@ -0,0 +1,97 @@
1
+ /**
2
+ * client.ts — HTTP client for the App Store Connect REST API.
3
+ *
4
+ * Handles JWT authentication, request building, JSON:API conventions,
5
+ * error normalisation, and response formatting.
6
+ */
7
+ import { getToken } from "./auth.js";
8
+ const BASE_URL = "https://api.appstoreconnect.apple.com";
9
+ /**
10
+ * Execute a single App Store Connect API request.
11
+ *
12
+ * @returns the parsed JSON response body (or null for 204).
13
+ * @throws Error with a descriptive message on failure.
14
+ */
15
+ export async function callApi(opts) {
16
+ // Build the URL with path parameters
17
+ let url = opts.path;
18
+ for (const [key, value] of Object.entries(opts.pathParams ?? {})) {
19
+ url = url.replace(`{${key}}`, encodeURIComponent(value));
20
+ }
21
+ // Append query parameters
22
+ const urlObj = new URL(url, BASE_URL);
23
+ if (opts.queryParams) {
24
+ for (const [key, value] of Object.entries(opts.queryParams)) {
25
+ if (value === undefined || value === null || value === "")
26
+ continue;
27
+ if (Array.isArray(value)) {
28
+ for (const v of value) {
29
+ urlObj.searchParams.append(key, String(v));
30
+ }
31
+ }
32
+ else {
33
+ urlObj.searchParams.append(key, String(value));
34
+ }
35
+ }
36
+ }
37
+ // Get JWT token
38
+ const token = getToken(opts.credentials);
39
+ // Build fetch options
40
+ const fetchOpts = {
41
+ method: opts.method,
42
+ headers: {
43
+ Authorization: `Bearer ${token}`,
44
+ Accept: "application/json",
45
+ },
46
+ };
47
+ if (opts.body !== undefined && opts.method !== "GET" && opts.method !== "DELETE") {
48
+ fetchOpts.headers = {
49
+ ...fetchOpts.headers,
50
+ "Content-Type": "application/json",
51
+ };
52
+ fetchOpts.body = JSON.stringify(opts.body);
53
+ }
54
+ // Execute request
55
+ const response = await fetch(urlObj.toString(), fetchOpts);
56
+ // Parse response
57
+ const responseText = await response.text();
58
+ if (!response.ok) {
59
+ let errorDetail;
60
+ try {
61
+ errorDetail = JSON.parse(responseText);
62
+ }
63
+ catch {
64
+ errorDetail = responseText;
65
+ }
66
+ throw new ApiError(response.status, errorDetail, opts.method, url);
67
+ }
68
+ // 204 No Content or empty body
69
+ if (response.status === 204 || !responseText) {
70
+ return { status: response.status, message: "Success (no content)" };
71
+ }
72
+ try {
73
+ return JSON.parse(responseText);
74
+ }
75
+ catch {
76
+ return responseText;
77
+ }
78
+ }
79
+ /** Structured error from the App Store Connect API. */
80
+ export class ApiError extends Error {
81
+ status;
82
+ detail;
83
+ method;
84
+ url;
85
+ constructor(status, detail, method, url) {
86
+ const message = typeof detail === "object" && detail !== null && "errors" in detail
87
+ ? JSON.stringify(detail.errors, null, 2)
88
+ : `HTTP ${status}: ${String(detail).slice(0, 200)}`;
89
+ super(message);
90
+ this.name = "AppStoreConnectApiError";
91
+ this.status = status;
92
+ this.detail = detail;
93
+ this.method = method;
94
+ this.url = url;
95
+ }
96
+ }
97
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * index.ts — Entry point for appstore-connect-mcp.
4
+ *
5
+ * Usage:
6
+ * # Local (stdio) — for Claude Desktop, Cursor, etc.
7
+ * appstore-connect-mcp
8
+ * appstore-connect-mcp --transport stdio
9
+ *
10
+ * # Remote (HTTP) — for server deployment
11
+ * appstore-connect-mcp --transport http --port 3000 --host 0.0.0.0
12
+ *
13
+ * Environment variables:
14
+ * APP_STORE_CONNECT_ISSUER_ID Your App Store Connect issuer ID
15
+ * APP_STORE_CONNECT_KEY_ID Your API key ID
16
+ * APP_STORE_CONNECT_PRIVATE_KEY PEM private key content (alternative: path)
17
+ * APP_STORE_CONNECT_P8_FILE Path to your .p8 private key file
18
+ * MCP_TRANSPORT 'stdio' (default) or 'http'
19
+ * MCP_PORT HTTP port (default: 3000)
20
+ * MCP_HOST HTTP host (default: 0.0.0.0)
21
+ * MCP_VERBOSE Set to '1' for verbose logging
22
+ */
23
+ export {};
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;GAoBG"}