phygital-token-mcp 0.1.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.
Files changed (40) hide show
  1. package/README.md +59 -0
  2. package/cursor-mcp.example.json +8 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +481 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/docs.d.ts +17 -0
  7. package/dist/lib/docs.js +121 -0
  8. package/dist/lib/docs.js.map +1 -0
  9. package/dist/lib/format.d.ts +13 -0
  10. package/dist/lib/format.js +12 -0
  11. package/dist/lib/format.js.map +1 -0
  12. package/dist/lib/gating-json.d.ts +127 -0
  13. package/dist/lib/gating-json.js +346 -0
  14. package/dist/lib/gating-json.js.map +1 -0
  15. package/dist/lib/graphify.d.ts +2 -0
  16. package/dist/lib/graphify.js +35 -0
  17. package/dist/lib/graphify.js.map +1 -0
  18. package/dist/lib/instructions.d.ts +131 -0
  19. package/dist/lib/instructions.js +232 -0
  20. package/dist/lib/instructions.js.map +1 -0
  21. package/dist/lib/paths.d.ts +14 -0
  22. package/dist/lib/paths.js +77 -0
  23. package/dist/lib/paths.js.map +1 -0
  24. package/dist/lib/rpc.d.ts +3 -0
  25. package/dist/lib/rpc.js +22 -0
  26. package/dist/lib/rpc.js.map +1 -0
  27. package/dist/lib/sdk-surface.d.ts +33 -0
  28. package/dist/lib/sdk-surface.js +101 -0
  29. package/dist/lib/sdk-surface.js.map +1 -0
  30. package/dist/lib/verification.d.ts +43 -0
  31. package/dist/lib/verification.js +166 -0
  32. package/dist/lib/verification.js.map +1 -0
  33. package/docs/building-on-phygital/overview.md +46 -0
  34. package/docs/building-on-phygital/rust-cpi.md +55 -0
  35. package/docs/glossary.md +43 -0
  36. package/docs/sdk/surface-area.md +77 -0
  37. package/docs/verification/methods.md +58 -0
  38. package/docs/verification/overview.md +70 -0
  39. package/docs/verification/verify-asset-composable.md +97 -0
  40. package/package.json +52 -0
@@ -0,0 +1,70 @@
1
+ # Verification overview
2
+
3
+ Phygital assets support two fundamentally different checks. Pick the wrong one and you either annoy users with unnecessary taps or accept replayable proofs.
4
+
5
+ ## The two questions
6
+
7
+ | Kind | Question | User taps again? |
8
+ |------|----------|------------------|
9
+ | **Identification** | Which asset is this? | No |
10
+ | **Authentication** | Is the holder here right now? | Yes |
11
+
12
+ Think of identification like reading a signed badge from a prior scan. Think of authentication like requiring a live tap before a high-value action.
13
+
14
+ ## Decision tree
15
+
16
+ ```
17
+ Do you need the holder physically present right now?
18
+ ├─ NO → Identification
19
+ │ ├─ Online, replay protection → verifyDynamicUrl
20
+ │ └─ Offline / no backend → verifyDynamicUrlWithoutCounterCheck (weaker)
21
+ └─ YES → Authentication
22
+ ├─ Off-chain only (UI login, no chain) → verifyWithChallengeResponse / OverNfc
23
+ ├─ On-chain proof for your program → beginVerifyAsset composable flow (see below)
24
+ └─ Transfer ownership → beginTransfer → completeTransfer (NOT verify_asset)
25
+ ```
26
+
27
+ ## Off-chain vs on-chain authentication
28
+
29
+ `verifyWithChallengeResponse` and `verifyWithChallengeResponseOverNfc` are **off-chain only**. They prompt an NFC tap and verify the WebAuthn signature in the client. They do **not** submit a transaction.
30
+
31
+ For on-chain proof that a passkey holder signed a specific message at a specific slot, use the composable `beginVerifyAsset` flow.
32
+
33
+ ## Two ways to compose on-chain with your program
34
+
35
+ Both patterns start the same on the client: `beginVerifyAsset` → tap → `buildVerifyAssetArgs` (or `completeVerifyAsset`).
36
+
37
+ | Pattern | Client transaction | Your on-chain program |
38
+ |---------|-------------------|----------------------|
39
+ | **A — Inspect** | `[secp256r1_verify, verify_asset, your_ix]` | Scans instructions sysvar for a preceding `verify_asset`; checks `message` bytes |
40
+ | **B — CPI** | `[secp256r1_verify, your_ix]` | CPIs `phygital_token::verify_asset` using args from `buildVerifyAssetArgs` |
41
+
42
+ ### Pattern A — Client posts `verify_asset`, program inspects
43
+
44
+ The client includes the full `verify_asset` instruction (via `completeVerifyAsset` or `getVerifyAssetInstruction`). Your program runs **after** it and reads the instructions sysvar to confirm a matching `verify_asset` ran with the expected `message`.
45
+
46
+ Reference: `phygital-spend` — `require_matching_verify_asset`.
47
+
48
+ ### Pattern B — Client posts `secp256r1_verify`, program CPIs `verify_asset`
49
+
50
+ The client uses `buildVerifyAssetArgs` to get `secp256r1Verify` and the verify args, but does **not** include `verify_asset` in the transaction. Your program receives those args (via instruction data) and CPIs `verify_asset` via `VerifyAssetCpiBuilder` from `phygital-token-client`.
51
+
52
+ `secp256r1_verify` must still appear **before** your program's instruction in the transaction.
53
+
54
+ ## Message binding
55
+
56
+ - **Transfer** challenge binds the asset PDA (recipient chosen later at wallet confirm).
57
+ - **Verify asset** challenge binds arbitrary `message` bytes. Hash on-chain: `SHA256(message)`.
58
+ - **Dynamic URL** binds `counter || nonce` (uint32 BE + 8 random bytes).
59
+
60
+ Embed domain-specific bytes in `message` so a proof for one action cannot authorize another.
61
+
62
+ ## Slot freshness
63
+
64
+ `verify_asset` records `asset.last_transfer_slot`. Each verification must use a **strictly greater** slot. Complete the flow promptly after `beginVerifyAsset` (~512 slots).
65
+
66
+ ## Next docs
67
+
68
+ - [Verification methods](./methods.md) — every `verify.ts` export
69
+ - [Composable verify_asset](./verify-asset-composable.md) — `buildVerifyAssetArgs` and both patterns
70
+ - [Building on phygital](../building-on-phygital/overview.md)
@@ -0,0 +1,97 @@
1
+ # Composable `verify_asset` (TypeScript)
2
+
3
+ On-chain passkey authentication for custom programs. **Not** the same as `verifyWithChallengeResponse` (which is off-chain only).
4
+
5
+ ## Session flow
6
+
7
+ ```
8
+ beginVerifyAsset({ rpc, message })
9
+
10
+ authenticatePasskeyForVerifyAsset(session) // WebAuthn NFC tap
11
+
12
+ buildVerifyAssetArgs(session, response) // or completeVerifyAsset(...)
13
+
14
+ assemble transaction (Pattern A or B below)
15
+ ```
16
+
17
+ ## Functions
18
+
19
+ ### `beginVerifyAsset({ rpc, message: Uint8Array })`
20
+
21
+ Slot-bound challenge: `SHA256("verify_asset" || SHA256(message) || slotHash)`.
22
+
23
+ ### `buildVerifyAssetArgs(session, response)`
24
+
25
+ Returns `secp256r1Verify`, `signedMessageIndex`, `clientDataJson`, `asset`, `assetPda`.
26
+
27
+ ### `completeVerifyAsset(session, response)`
28
+
29
+ Returns `[secp256r1Verify, verifyAssetInstruction]`.
30
+
31
+ ## Pattern A — Client posts `verify_asset`, program inspects
32
+
33
+ **Client transaction order:**
34
+
35
+ ```
36
+ secp256r1_verify → verify_asset → your_program_ix
37
+ ```
38
+
39
+ ```ts
40
+ const session = await beginVerifyAsset({ rpc, message });
41
+ const response = await authenticatePasskeyForVerifyAsset(session);
42
+
43
+ const [secp256r1Verify, verifyAssetIx] = await completeVerifyAsset(
44
+ session,
45
+ response,
46
+ );
47
+
48
+ const myIx = buildMyProgramInstruction(/* binds same message bytes */);
49
+
50
+ await sendTransaction([secp256r1Verify, verifyAssetIx, myIx], { feePayer });
51
+ ```
52
+
53
+ **Your Rust program:** Scan `instructions_sysvar` for the `verify_asset` instruction that ran earlier in this transaction. Decode and verify `message` matches your canonical payload. Reference: `phygital-spend`.
54
+
55
+ ## Pattern B — Client posts `secp256r1_verify`, program CPIs `verify_asset`
56
+
57
+ **Client transaction order:**
58
+
59
+ ```
60
+ secp256r1_verify → your_program_ix
61
+ ```
62
+
63
+ ```ts
64
+ const session = await beginVerifyAsset({ rpc, message });
65
+ const response = await authenticatePasskeyForVerifyAsset(session);
66
+
67
+ const { secp256r1Verify, signedMessageIndex, clientDataJson, assetPda } =
68
+ await buildVerifyAssetArgs(session, response);
69
+
70
+ // Pass verify args to your program via instruction data
71
+ const myIx = buildMyProgramInstruction({
72
+ asset: assetPda,
73
+ secp256r1VerifyArgs: {
74
+ signedMessageIndex,
75
+ slotNumber: session.slotNumber,
76
+ clientDataJson,
77
+ },
78
+ message: session.message,
79
+ });
80
+
81
+ await sendTransaction([secp256r1Verify, myIx], { feePayer });
82
+ ```
83
+
84
+ **Your Rust program:** CPI `verify_asset` using `VerifyAssetCpiBuilder` from `phygital-token-client`. The `secp256r1_verify` instruction must appear earlier in the same transaction (verified via instructions sysvar inside `verify_asset`).
85
+
86
+ ## `verify_asset` instruction layout
87
+
88
+ Accounts: `asset` (writable), `slot_hashes`, `instructions_sysvar`.
89
+
90
+ Args: `{ secp256r1VerifyArgs: { signedMessageIndex, slotNumber, clientDataJson }, message }`.
91
+
92
+ ## On-chain effects
93
+
94
+ - Verifies WebAuthn signature against slot-bound challenge
95
+ - Sets `asset.last_transfer_slot = slotNumber`
96
+ - Emits `VerifyAssetEvent`
97
+ - Does not change token owner or balance
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "phygital-token-mcp",
3
+ "version": "0.1.1",
4
+ "description": "MCP server for the phygital-token Solana program, TypeScript SDK, and Rust client",
5
+ "license": "ISC",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/jychab/phygital-nfts.git",
9
+ "directory": "mcp/phygital-token"
10
+ },
11
+ "keywords": [
12
+ "mcp",
13
+ "model-context-protocol",
14
+ "solana",
15
+ "phygital",
16
+ "webauthn",
17
+ "nft"
18
+ ],
19
+ "type": "module",
20
+ "main": "./dist/index.js",
21
+ "bin": {
22
+ "phygital-token-mcp": "./dist/index.js"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "docs",
27
+ "README.md",
28
+ "cursor-mcp.example.json"
29
+ ],
30
+ "engines": {
31
+ "node": ">=20"
32
+ },
33
+ "dependencies": {
34
+ "@modelcontextprotocol/sdk": "^1.29.0",
35
+ "@noble/hashes": "^2.0.1",
36
+ "@solana/kit": "^6.4.0",
37
+ "phygital-token-sdk": "^0.6.0",
38
+ "zod": "^3.25.76"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^22.15.21",
42
+ "typescript": "^5.7.3"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "scripts": {
48
+ "build": "tsc -p tsconfig.json && node scripts/add-shebang.mjs",
49
+ "dev": "tsc -p tsconfig.json --watch",
50
+ "start": "node dist/index.js"
51
+ }
52
+ }