storekit-verify-mcp
by tranzen21
README.md
# storekit-verify-mcp
**Decode and cryptographically verify Apple App Store Server Notifications V2 — as an MCP server and a CLI.**
Apple delivers subscription webhooks (`SUBSCRIBED`, `DID_RENEW`, `EXPIRED`, `REFUND`, …) as signed JWS payloads. Verifying them properly means checking the ES256 signature, walking a 3-certificate chain to a pinned Apple root, checking Apple's policy OIDs, and doing it again for the nested transaction and renewal payloads. Most servers either skip verification entirely or trust a decode. This tool does it right, and explains what each notification means while it's at it.
I built this logic for [Talli](https://talliapp.co), my live App Store app, where server-side webhook verification drives subscription entitlements. This is that experience packaged as a standalone tool.
## What it checks
- ✅ ES256 signature of the outer `signedPayload` **and** the nested `signedTransactionInfo` / `signedRenewalInfo`
- ✅ Full x5c chain: leaf → intermediate → root, each link's signature verified
- ✅ Root pinned to **Apple Root CA – G3** (bundled, SHA-256 fingerprint documented in source)
- ✅ Apple's policy OIDs on the leaf (receipt signing) and intermediate (WWDR)
- ✅ Certificate validity windows at the payload's `signedDate`
- ✅ Optional `bundleId` and `environment` (Sandbox/Production) assertions
## MCP server
Add to Claude Code:
```bash
claude mcp add storekit-verify -- npx -y github:tranzen21/storekit-verify-mcp
```
Or any MCP client:
```json
{
"mcpServers": {
"storekit-verify": {
"command": "npx",
"args": ["-y", "github:tranzen21/storekit-verify-mcp"]
}
}
}
```
### Tools
| Tool | What it does |
|---|---|
| `verify_notification` | Full cryptographic verification → `{valid, errors[], decoded}` |
| `decode_notification` | Decode without verification (inspect payloads fast) |
| `decode_transaction` | Decode a single signed transaction/renewal JWS |
| `explain_notification_type` | What a `notificationType`/`subtype` means and how to handle it |
Ask your agent things like *"verify this webhook body and tell me if I should revoke entitlement"* — it can decode, verify, and explain in one pass.
## CLI
```bash
# Verify a webhook body (file or stdin). Exit code 0 = valid.
npx github:tranzen21/storekit-verify-mcp storekit-verify verify webhook.json \
--bundle-id com.example.app --environment Production
# Decode without verification
storekit-verify decode webhook.json
# What does DID_FAIL_TO_RENEW / GRACE_PERIOD mean?
storekit-verify explain DID_FAIL_TO_RENEW GRACE_PERIOD
```
## Library
```ts
import { verifyNotification } from "storekit-verify-mcp";
const result = await verifyNotification(requestBody, {
expectedBundleId: "com.example.app",
expectedEnvironment: "Production",
});
if (!result.valid) throw new Error(result.errors.join("; "));
// result.decoded.payload.notificationType, result.decoded.transactionInfo, ...
```
## Development
```bash
npm install
npm run fixtures # generates a test CA chain (openssl) + signed sample payloads
npm test # builds + runs node:test suite
```
The test suite covers: valid chain verification, root-pin rejection, mismatched-key signatures, tampered payloads, bundle/environment mismatches, expired certificates, and malformed input.
## Notes
- Requires Node 20+.
- No network calls at runtime: the Apple root is bundled; verification is fully offline.
- Not affiliated with or endorsed by Apple. For the official server library, see [apple/app-store-server-library-node](https://github.com/apple/app-store-server-library-node) — this project exists to make the same verification available to MCP agents and as a zero-setup CLI.
## License
MIT © Marcquin Taylor
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues