Atlas / MCP servers / erayendes / Heimdall App Store Connect

Heimdall App Store ConnectBLOCK

mcp/erayendes/heimdall-app-store-connect

Heimdall — MCP server for the Apple App Store Connect API and App Store Server API (StoreKit 2). 890 tools across 13 profiles, generated from Apple's OpenAPI spec, plus one-call macros for worldwide pricing, submission readiness and metadata diffs, and confirm-before-write safety. Works with Claude,

Verdict
BLOCK
Grade
F
Trust score
46 /100
Exposed tools
47 37r · 10w · 0d
Transport
stdio
License
MIT
Stars
51
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](https://www.npmjs.com/package/@erayendes/asc-mcp) [](https://www.npmjs.com/package/@erayendes/asc-mcp) [](https://github.com/erayendes/app-store-connect-mcp/actions/workflows/ci.yml) [](LICENSE) [](https://milowda.com)

A real agent session over MCP, sped up. The App Store Connect account is a stand-in so the recording can be public — regenerate with vhs assets/demo/demo.tape.

🇬🇧 English · 🇹🇷 Türkçe

English

Heimdall. One tool for your entire App Store Connect account.

An MCP server for the App Store Connect API and the App Store Server API (StoreKit 2), with every tool generated from Apple's own OpenAPI specification. 13 profiles, 32 sub-profiles, 902 tools.

Apps and metadata, versions and phased releases, TestFlight, subscriptions and in-app purchases, pricing, reviews, Game Center, Xcode Cloud, provisioning, webhooks, and sales and finance reports.

Ask and it answers. Tell it and it's done.

-
Read from source at commit ed0ab83ee84cOBSERVED · 2026-10-08
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (npm)
claude mcp add asc-mcp --env ASC_PRIVATE_KEY=${ASC_PRIVATE_KEY} -- npx -y @erayendes/[email protected]
03

Exposed tools (47)

37 read · 10 write · 0 destructive.

ToolRiskDescription
PremiumreadFull access.
analytics__get_reportreadRead an App Store analytics report as rows, in one step. Give the app (name, bundle ID
appreadApp name, bundle ID or Apple ID.
app_idreadNumeric Apple ID of the app.
asc__account_statusreadShow every app in the account with the version that is live, the version in
asc__callreadRead through any tool this profile owns, even one that is not in your tool list —
asc__describereadShow the exact input schema of any tool this profile owns, including ones not
asc__discover_domainsreadList what this server can reach and what it cannot: in profile mode the profiles
asc__loadwriteAdd one of this server
asc__profile_removedreadThis MCP server is configured for the App Store Connect profile
asc__search_toolsreadSearch all App Store Connect operations by keyword, including domains that are
asc__statusreadReport server configuration, spec version, loaded domains, JWT token state
daysreadLookback window in days. Default 7.
listing__diff_metadatareadCompare the store text of two app versions locale by locale, in one call, and
listing__get_screenshotsreadList the screenshots on an app’s store listing in one step: which locales
listing__upload_screenshotwriteUpload a screenshot image file to an app’s store listing in one step. Give the app
metadata_ai__apply_localizationswriteWrite store text for several languages at once from a file the user prepared — the
metadata_ai__audit_localizationsreadCompare an app version’s store text across every language and report what is missing
metadata_ai__draft_translationreadReturn one language’s store text plus an instruction for you to draft it in the
preflight__check_subscriptionreadCheck subscription catalog readiness before submitting for review. Give the app
preflight__check_versionwriteCheck whether an app version is complete enough to submit, in one call, and
price-checkreadShow what a subscription costs worldwide, where the prices are inconsistent, and
pricing__equalize_pricewriteSet one anchor price and let Apple derive the equivalent price in every other
pricing__get_app_pricereadRead current and scheduled app purchase prices by territory, including currency,
pricing__get_iap_pricereadRead current and scheduled in-app purchase prices by territory, including currency,
pricing__get_subscription_pricereadWhat a subscription costs customers today — in one country, or in every country at
pricing__set_iap_pricewriteChange or set an in-app purchase (IAP) price in one territory (country) without
pricing__set_subscription_pricewriteChange or set a subscription price in one territory (country) in a single step.
release-readinessreadDecide whether an app version can be submitted: what is missing, and what the
release__submitwriteSend an App Store version to Apple for review in one call — it opens the submission,
review-triagereadRead the recent App Store reviews for an app, sort them by what needs answering,
reviews_ai__daily_briefingreadFetch the last N days of reviews for an app, with volume and rating trend (computed
reviews_ai__draft_responsereadFetch one customer review and return it with an instruction for you to draft a reply
reviews_ai__triagereadFetch recent reviews for an app and return them with an instruction for you to group
storekit__check_entitlementreadAnswer the single question
storekit__extend_renewal_datereadExtend a subscriber
storekit__get_notification_historyreadRetrieve App Store Server Notification delivery history, including failures.
storekit__get_refund_historyreadList every refunded transaction for a customer. Useful for auditing refund
storekit__get_subscription_statusesreadGet the status of every subscription a customer holds, including expiry date,
storekit__get_transaction_historyreadGet a customer
storekit__get_transaction_inforeadGet a single transaction: product, price, dates, ownership type and revocation
storekit__lookup_orderwriteLook up all transactions tied to an order ID from a customer receipt.
storekit__request_test_notificationwriteAsk Apple to send a test notification to your configured webhook endpoint.
subscriptionreadSubscription name or product ID. Optional if the app has one.
testflight__assign_build_to_groupsreadAssign one processed, unexpired TestFlight build to named beta groups. Checks existing assignments and reports each group, including partial failures. External groups may need beta app review before testers can install the build. RELEASE-level write.
testflight__feedback_digestreadSummarize what TestFlight beta testers are reporting: recent crash and screenshot feedback
versionreadVersion string. Defaults to the one being prepared.
04

Trust audit

BLOCKgrade F · trust 46/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryWARN
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)FAIL
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
none-observed
Network
declared (7 observation(s))
Shell
declared (2 observation(s))
Dependencies
not all pinned
Secrets in source
found

Findings (24)

CRITICALHard-coded secrets · secret.private_key · CWE-798, CWE-321
.env.example:7
# ASC_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIG..."
CRITICALHard-coded secrets · secret.private_key · CWE-798, CWE-321
.gitleaks.toml:5
# GitHub. A generic `-----BEGIN PRIVATE KEY-----` in a commit is exactly the
CRITICALPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
<tool:asc__status>:1
Report server configuration, spec version, loaded domains, JWT token state
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/core/keychain.ts:49
output = exec(
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
src/core/keychain.ts:108
exec(
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
MEDIUMInventory / provenance · inv.binary · CWE-1104
scripts/generate-profiles.ts
generate-profiles.ts
Why it matters. a compiled or binary member cannot be reviewed from source
Fix. ship source, or explain the binary in the README
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
assets/demo/fixture-server.mjs:86
server.listen(port, '127.0.0.1', () => console.log(`fixture on http://127.0.0.1:${port}`));
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
assets/demo/setup-demo.sh:23
export ASC_BASE_URL="http://127.0.0.1:8787"
MEDIUMObfuscation / stealth · obf.zero_width · CWE-506, CWE-94
src/tools/metadata-i18n.ts:192
const trimmed = text.replace(/^/, '').trim();
MEDIUMHard-coded secrets · secret.private_key · CWE-798, CWE-321
.github/workflows/ci.yml:174
# caught and a bare `-----BEGIN PRIVATE KEY-----` is not. That block is
MEDIUMHard-coded secrets · secret.private_key · CWE-798, CWE-321
tests/keychain.test.ts:19
const exec = vi.fn().mockReturnValue('-----BEGIN PRIVATE KEY-----\nMIG...\n');
MEDIUMHard-coded secrets · secret.private_key · CWE-798, CWE-321
tests/keychain.test.ts:22
expect(pem).toBe('-----BEGIN PRIVATE KEY-----\nMIG...');
LOWInventory / provenance · inv.hidden_file · CWE-1104
.gitleaks.toml
.gitleaks.toml
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
src/tools/screenshots.ts:380
const checksum = createHash('md5').update(bytes).digest('hex');
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
tests/screenshots.test.ts:218
createHash('md5').update(bytes).digest('hex')
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
tests/reviews-ai-stdio.test.ts:79
ASC_BASE_URL: 'http://127.0.0.1:1',
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
tests/reviews-ai-stdio.test.ts:234
c = client([], { env: { ASC_BASE_URL: `http://127.0.0.1:${port}` } });
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
tests/testflight.test.ts:159
baseUrl: 'http://127.0.0.1:1', readOnly: false, confirmWrites: 'all',
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
package.json
@apple/app-store-server-library, @modelcontextprotocol/sdk, @anthropic-ai/claude-agent-sdk, @types/node, tsx, typescript, vitest
Why it matters. 7 dependency range(s) float
Fix. pin exact versions or ship a lockfile
LOWPrompt injection · prompt.authority_framing · CWE-94, CWE-1427
<tool:Premium>:1
Full access.
LOWPrompt injection · prompt.credential_read · CWE-94, CWE-1427
AGENTS.md:41
**Going after the key is the most common way a session goes wrong.** In recorded eval runs, of the sessions that abandoned the tools, the largest group went hunting for the private key — `security fin
Why it matters. asks the agent to read credentials
LOWPrompt injection · prompt.credential_read · CWE-94, CWE-1427
README.md:56
<sub>One pass, and safe throughout: the access details it needs, then a live credential check. Then your choices — the profiles and sub-profiles you want, and the key ends up in the Keychain, not in a
Why it matters. asks the agent to read credentials
LOWPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
README.md:101
Apple never returns a key's role from any endpoint, so **App Manager** — not Admin — is the right default for day-to-day release work; Admin only earns its place for user management and for the one-ti
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine
INFOInventory / provenance · inv.oversize · CWE-1104
spec/openapi.json
spec/openapi.json
Why it matters. 7228461 bytes not read

Gates applied: critical_finding, no_behavioural_pass, undeclared_transfer.

Audited 2026-10-08 · audit v0.4.1 · source sha ed0ab83ee84cfull audit observations/trust-audit/mcp-server/erayendes__heimdall-app-store-connect.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-08ed0ab83ee84cBLOCKF46first audit
06

Questions

What is the Heimdall App Store Connect MCP server?

Heimdall — MCP server for the Apple App Store Connect API and App Store Server API (StoreKit 2). 890 tools across 13 profiles, generated from Apple's OpenAPI spec, plus one-call macros for worldwide pricing, submission readiness and metadata diffs, and confirm-before-write safety. Works with Claude,

What tools does Heimdall App Store Connect expose?

47 in total: 37 read-only, 10 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.

Is Heimdall App Store Connect safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (46/100) and found 5 critical or high issues in the source. Each one is listed on this page with the file and line it is on.

What credentials does Heimdall App Store Connect need?

It reads ASC_KEY_ID, ASC_PRIVATE_KEY, ASC_PRIVATE_KEY_KEYCHAIN, ASC_PRIVATE_KEY_PATH and TOKEN_REPORT from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does Heimdall App Store Connect run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as @erayendes/asc-mcp at 2.5.0.

How current is this page?

The grade is for one exact copy of the source (ed0ab83ee84c), read on 2026-10-08. The repository is watched and re-audited when it changes.

Advertisement