@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/dist/index.js ADDED
@@ -0,0 +1,129 @@
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
+ import { readFileSync } from "node:fs";
24
+ import { createMcpServer } from "./server.js";
25
+ import { startStdio, startHttp } from "./transport.js";
26
+ import { getToken, parsePrivateKey, validateCredentials } from "./auth.js";
27
+ function parseArgs(argv) {
28
+ const result = {};
29
+ for (let i = 2; i < argv.length; i++) {
30
+ const arg = argv[i];
31
+ if (arg.startsWith("--")) {
32
+ const key = arg.slice(2);
33
+ const next = argv[i + 1];
34
+ if (next && !next.startsWith("--")) {
35
+ result[key] = next;
36
+ i++;
37
+ }
38
+ else {
39
+ result[key] = true;
40
+ }
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+ function loadConfig() {
46
+ const args = parseArgs(process.argv);
47
+ // Transport
48
+ const transport = (args.transport ||
49
+ process.env.MCP_TRANSPORT ||
50
+ "stdio");
51
+ // Credentials
52
+ const issuerId = args["issuer-id"] ||
53
+ process.env.APP_STORE_CONNECT_ISSUER_ID ||
54
+ "";
55
+ const keyId = args["key-id"] ||
56
+ process.env.APP_STORE_CONNECT_KEY_ID ||
57
+ "";
58
+ // Private key: env var content or file path
59
+ let privateKey = process.env.APP_STORE_CONNECT_PRIVATE_KEY || "";
60
+ const p8File = args["p8-file"] ||
61
+ process.env.APP_STORE_CONNECT_P8_FILE ||
62
+ "";
63
+ if (!privateKey && p8File) {
64
+ privateKey = readFileSync(p8File, "utf-8");
65
+ }
66
+ // Also check legacy env var names
67
+ const legacyKey = process.env.ASC_PRIVATE_KEY || process.env.APPSTORE_CONNECT_PRIVATE_KEY;
68
+ if (!privateKey && legacyKey) {
69
+ privateKey = legacyKey;
70
+ }
71
+ const credentials = {
72
+ issuerId,
73
+ keyId,
74
+ privateKey: privateKey ? parsePrivateKey(privateKey) : "",
75
+ };
76
+ const verbose = args.verbose === true || process.env.MCP_VERBOSE === "1";
77
+ const port = parseInt(args.port || process.env.MCP_PORT || "3000", 10);
78
+ const host = args.host || process.env.MCP_HOST || "0.0.0.0";
79
+ return {
80
+ credentials,
81
+ transport,
82
+ port,
83
+ host,
84
+ verbose,
85
+ };
86
+ }
87
+ async function main() {
88
+ const config = loadConfig();
89
+ try {
90
+ validateCredentials(config.credentials);
91
+ }
92
+ catch (err) {
93
+ console.error(`Error: ${err.message}`);
94
+ console.error("\nSee https://github.com/topcheer/appstore-connect-mcp#setup for help.");
95
+ process.exit(1);
96
+ }
97
+ // Verify the key works by generating a test token
98
+ try {
99
+ getToken(config.credentials);
100
+ }
101
+ catch (err) {
102
+ console.error(`Error: Failed to sign JWT — invalid private key. ${err.message}`);
103
+ process.exit(1);
104
+ }
105
+ if (config.verbose) {
106
+ console.error(`[appstore-connect-mcp] Starting in ${config.transport} mode`);
107
+ }
108
+ if (config.transport === "http") {
109
+ // HTTP mode: factory creates a fresh server per session
110
+ const createServer = () => createMcpServer({
111
+ credentials: config.credentials,
112
+ verbose: config.verbose,
113
+ });
114
+ await startHttp(createServer, config.host ?? "0.0.0.0", config.port ?? 3000);
115
+ }
116
+ else {
117
+ // Stdio mode: single server instance
118
+ const server = createMcpServer({
119
+ credentials: config.credentials,
120
+ verbose: config.verbose,
121
+ });
122
+ await startStdio(server);
123
+ }
124
+ }
125
+ main().catch((err) => {
126
+ console.error("Fatal error:", err);
127
+ process.exit(1);
128
+ });
129
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * server.ts — MCP server core.
3
+ *
4
+ * Creates a Model Context Protocol server that exposes all App Store Connect
5
+ * API operations as MCP tools. Uses the low-level Server class for efficient
6
+ * handling of 1200+ dynamically-generated tools.
7
+ */
8
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
9
+ import type { ASCCredentials } from "./types.js";
10
+ export interface CreateServerOptions {
11
+ credentials: ASCCredentials;
12
+ verbose?: boolean;
13
+ }
14
+ /**
15
+ * Create and configure the MCP server.
16
+ *
17
+ * Registers:
18
+ * - ListTools handler → returns all generated tools + 3 meta-tools
19
+ * - CallTool handler → dispatches to the API or meta-tool
20
+ */
21
+ export declare function createMcpServer(opts: CreateServerOptions): Server;
22
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAKnE,OAAO,KAAK,EAAE,cAAc,EAAW,MAAM,YAAY,CAAC;AAG1D,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,cAAc,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CA+NjE"}
package/dist/server.js ADDED
@@ -0,0 +1,208 @@
1
+ /**
2
+ * server.ts — MCP server core.
3
+ *
4
+ * Creates a Model Context Protocol server that exposes all App Store Connect
5
+ * API operations as MCP tools. Uses the low-level Server class for efficient
6
+ * handling of 1200+ dynamically-generated tools.
7
+ */
8
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
9
+ import { ListToolsRequestSchema, CallToolRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
10
+ import { loadTools, buildInputSchema, executeTool } from "./tools.js";
11
+ /**
12
+ * Create and configure the MCP server.
13
+ *
14
+ * Registers:
15
+ * - ListTools handler → returns all generated tools + 3 meta-tools
16
+ * - CallTool handler → dispatches to the API or meta-tool
17
+ */
18
+ export function createMcpServer(opts) {
19
+ const { credentials, verbose } = opts;
20
+ const toolsData = loadTools();
21
+ // Build a lookup map for O(1) dispatch
22
+ const toolMap = new Map();
23
+ for (const t of toolsData.tools) {
24
+ toolMap.set(t.name, t);
25
+ }
26
+ const server = new Server({
27
+ name: "appstore-connect-mcp",
28
+ version: "1.0.0",
29
+ }, {
30
+ capabilities: {
31
+ tools: {},
32
+ },
33
+ });
34
+ // ── ListTools handler ──────────────────────────────────────────
35
+ server.setRequestHandler(ListToolsRequestSchema, async (request) => {
36
+ const cursor = request.params?.cursor;
37
+ const PAGE_SIZE = 100;
38
+ const startIndex = cursor ? parseInt(cursor, 10) || 0 : 0;
39
+ const allTools = toolsData.tools;
40
+ const page = allTools.slice(startIndex, startIndex + PAGE_SIZE);
41
+ const hasNext = startIndex + PAGE_SIZE < allTools.length;
42
+ const mcpTools = page.map((tool) => ({
43
+ name: tool.name,
44
+ description: `[${tool.category}] ${tool.summary} (${tool.method} ${tool.path})`,
45
+ inputSchema: buildInputSchema(tool),
46
+ }));
47
+ // On the first page, also add meta-tools
48
+ if (startIndex === 0) {
49
+ mcpTools.unshift({
50
+ name: "search_apis",
51
+ description: "Search App Store Connect API operations by keyword. Returns matching tool names, methods, and paths.",
52
+ inputSchema: {
53
+ type: "object",
54
+ properties: {
55
+ query: {
56
+ type: "string",
57
+ description: "Search keyword (e.g. 'app', 'build', 'subscription', 'review')",
58
+ },
59
+ category: {
60
+ type: "string",
61
+ description: "Filter by category (e.g. 'Apps', 'Builds')",
62
+ },
63
+ method: {
64
+ type: "string",
65
+ enum: ["GET", "POST", "PATCH", "DELETE"],
66
+ description: "Filter by HTTP method",
67
+ },
68
+ },
69
+ required: ["query"],
70
+ },
71
+ }, {
72
+ name: "list_categories",
73
+ description: "List all API categories (resource groups) available in the App Store Connect API.",
74
+ inputSchema: {
75
+ type: "object",
76
+ properties: {},
77
+ },
78
+ }, {
79
+ name: "get_tool_details",
80
+ description: "Get full details of a specific API operation including all parameters and their descriptions.",
81
+ inputSchema: {
82
+ type: "object",
83
+ properties: {
84
+ name: {
85
+ type: "string",
86
+ description: "The tool name (operationId), e.g. 'apps_getCollection'",
87
+ },
88
+ },
89
+ required: ["name"],
90
+ },
91
+ });
92
+ }
93
+ return {
94
+ tools: mcpTools,
95
+ ...(hasNext ? { nextCursor: String(startIndex + PAGE_SIZE) } : {}),
96
+ };
97
+ });
98
+ // ── CallTool handler ───────────────────────────────────────────
99
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
100
+ const { name, arguments: args } = request.params;
101
+ const toolArgs = (args ?? {});
102
+ if (verbose) {
103
+ console.error(`[appstore-connect-mcp] tool call: ${name}`);
104
+ }
105
+ // ── Meta-tools ───────────────────────────────────────────────
106
+ if (name === "search_apis") {
107
+ const query = String(toolArgs.query || "").toLowerCase();
108
+ const category = toolArgs.category;
109
+ const method = toolArgs.method;
110
+ const matches = toolsData.tools.filter((t) => {
111
+ if (category && t.category !== category)
112
+ return false;
113
+ if (method && t.method !== method)
114
+ return false;
115
+ const haystack = `${t.name} ${t.summary} ${t.path} ${t.category}`.toLowerCase();
116
+ return haystack.includes(query);
117
+ });
118
+ const results = matches.slice(0, 50).map((t) => ({
119
+ name: t.name,
120
+ summary: t.summary,
121
+ method: t.method,
122
+ path: t.path,
123
+ category: t.category,
124
+ }));
125
+ return {
126
+ content: [
127
+ {
128
+ type: "text",
129
+ text: JSON.stringify({
130
+ query,
131
+ totalMatches: matches.length,
132
+ showing: results.length,
133
+ results,
134
+ }, null, 2),
135
+ },
136
+ ],
137
+ };
138
+ }
139
+ if (name === "list_categories") {
140
+ return {
141
+ content: [
142
+ {
143
+ type: "text",
144
+ text: JSON.stringify({
145
+ apiVersion: toolsData.apiVersion,
146
+ totalTools: toolsData.stats.total,
147
+ totalCategories: toolsData.categories.length,
148
+ categories: toolsData.categories,
149
+ }, null, 2),
150
+ },
151
+ ],
152
+ };
153
+ }
154
+ if (name === "get_tool_details") {
155
+ const toolName = String(toolArgs.name);
156
+ const tool = toolMap.get(toolName);
157
+ if (!tool) {
158
+ return {
159
+ content: [{ type: "text", text: `Tool not found: ${toolName}` }],
160
+ isError: true,
161
+ };
162
+ }
163
+ return {
164
+ content: [
165
+ {
166
+ type: "text",
167
+ text: JSON.stringify(tool, null, 2),
168
+ },
169
+ ],
170
+ };
171
+ }
172
+ // ── API tools ────────────────────────────────────────────────
173
+ const tool = toolMap.get(name);
174
+ if (!tool) {
175
+ return {
176
+ content: [
177
+ {
178
+ type: "text",
179
+ text: `Unknown tool: ${name}. Use search_apis to find available operations.`,
180
+ },
181
+ ],
182
+ isError: true,
183
+ };
184
+ }
185
+ try {
186
+ const result = await executeTool(tool, toolArgs, credentials);
187
+ // Format response — ensure it's compact text for the LLM
188
+ const text = typeof result === "string" ? result : JSON.stringify(result, null, 2);
189
+ return {
190
+ content: [
191
+ {
192
+ type: "text",
193
+ text: text.length > 50000 ? text.slice(0, 50000) + "\n... (truncated)" : text,
194
+ },
195
+ ],
196
+ };
197
+ }
198
+ catch (err) {
199
+ const message = err instanceof Error ? err.message : String(err);
200
+ return {
201
+ content: [{ type: "text", text: `API Error: ${message}` }],
202
+ isError: true,
203
+ };
204
+ }
205
+ });
206
+ return server;
207
+ }
208
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * tools.ts — Tool registry: loads tools.json, builds MCP input schemas,
3
+ * and dispatches tool calls to the API client.
4
+ */
5
+ import type { ToolDef, ToolsData, ASCCredentials } from "./types.js";
6
+ /** Load the generated tools data from tools.json. */
7
+ export declare function loadTools(): ToolsData;
8
+ /**
9
+ * Build a JSON Schema input for an MCP tool from its definition.
10
+ *
11
+ * Path params become top-level required string properties.
12
+ * Query params become optional properties (arrays / strings / enums).
13
+ * POST/PATCH operations get a `_body` object property.
14
+ */
15
+ export declare function buildInputSchema(tool: ToolDef): object;
16
+ /**
17
+ * Execute a tool call: extract params, call the API, return the result.
18
+ *
19
+ * @returns the API response (already JSON-parsed).
20
+ */
21
+ export declare function executeTool(tool: ToolDef, args: Record<string, unknown>, credentials: ASCCredentials): Promise<unknown>;
22
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKrE,qDAAqD;AACrD,wBAAgB,SAAS,IAAI,SAAS,CAGrC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CA4DtD;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,EAAE,cAAc,GAC1B,OAAO,CAAC,OAAO,CAAC,CAmClB"}
package/dist/tools.js ADDED
@@ -0,0 +1,118 @@
1
+ /**
2
+ * tools.ts — Tool registry: loads tools.json, builds MCP input schemas,
3
+ * and dispatches tool calls to the API client.
4
+ */
5
+ import { readFileSync } from "node:fs";
6
+ import { fileURLToPath } from "node:url";
7
+ import { dirname, join } from "node:path";
8
+ import { callApi } from "./client.js";
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ /** Load the generated tools data from tools.json. */
11
+ export function loadTools() {
12
+ const raw = readFileSync(join(__dirname, "tools.json"), "utf-8");
13
+ return JSON.parse(raw);
14
+ }
15
+ /**
16
+ * Build a JSON Schema input for an MCP tool from its definition.
17
+ *
18
+ * Path params become top-level required string properties.
19
+ * Query params become optional properties (arrays / strings / enums).
20
+ * POST/PATCH operations get a `_body` object property.
21
+ */
22
+ export function buildInputSchema(tool) {
23
+ const properties = {};
24
+ const required = [];
25
+ // Path parameters
26
+ for (const p of tool.pathParams) {
27
+ properties[p.name] = {
28
+ type: "string",
29
+ description: p.description || `Path parameter: ${p.name}`,
30
+ };
31
+ if (p.required) {
32
+ required.push(p.name);
33
+ }
34
+ }
35
+ // Query parameters
36
+ for (const p of tool.queryParams) {
37
+ const schemaType = p.schema?.type;
38
+ if (schemaType === "array") {
39
+ const items = p.schema?.items;
40
+ properties[p.name] = {
41
+ type: "array",
42
+ items: {
43
+ type: items?.type || "string",
44
+ ...(items?.enum ? { enum: items.enum } : {}),
45
+ },
46
+ description: p.description || `Query parameter: ${p.name}`,
47
+ };
48
+ }
49
+ else if (p.schema?.enum) {
50
+ properties[p.name] = {
51
+ type: "string",
52
+ enum: p.schema.enum,
53
+ description: p.description || `Query parameter: ${p.name}`,
54
+ };
55
+ }
56
+ else {
57
+ properties[p.name] = {
58
+ type: schemaType || "string",
59
+ description: p.description || `Query parameter: ${p.name}`,
60
+ };
61
+ }
62
+ if (p.required) {
63
+ required.push(p.name);
64
+ }
65
+ }
66
+ // Request body for POST/PATCH
67
+ if (tool.hasBody) {
68
+ properties["_body"] = {
69
+ type: "object",
70
+ description: "JSON:API request body. Follow the App Store Connect API JSON:API format: { data: { type, attributes, relationships } }.",
71
+ };
72
+ required.push("_body");
73
+ }
74
+ return {
75
+ type: "object",
76
+ properties,
77
+ ...(required.length > 0 ? { required } : {}),
78
+ };
79
+ }
80
+ /**
81
+ * Execute a tool call: extract params, call the API, return the result.
82
+ *
83
+ * @returns the API response (already JSON-parsed).
84
+ */
85
+ export async function executeTool(tool, args, credentials) {
86
+ // Separate path params, query params, and body
87
+ const pathParams = {};
88
+ const queryParams = {};
89
+ let body = undefined;
90
+ for (const p of tool.pathParams) {
91
+ if (p.name in args) {
92
+ pathParams[p.name] = String(args[p.name]);
93
+ }
94
+ }
95
+ for (const p of tool.queryParams) {
96
+ if (p.name in args && args[p.name] !== undefined) {
97
+ const val = args[p.name];
98
+ if (Array.isArray(val)) {
99
+ queryParams[p.name] = val.map(String);
100
+ }
101
+ else {
102
+ queryParams[p.name] = String(val);
103
+ }
104
+ }
105
+ }
106
+ if (tool.hasBody && "_body" in args) {
107
+ body = args["_body"];
108
+ }
109
+ return callApi({
110
+ method: tool.method,
111
+ path: tool.path,
112
+ pathParams,
113
+ queryParams,
114
+ body,
115
+ credentials,
116
+ });
117
+ }
118
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}