Skip to content

Commit ddee296

Browse files
adonesky1jiexi
andauthored
feat: add metamask-connect agent skill (skills.sh) (#334)
* feat: add metamask-connect agent skill (skills.sh) Colocate the MetaMask Connect SDK agent skill in the SDK repo so it versions with the code and is installable via `npx skills add MetaMask/connect-monorepo`, with skills.sh install analytics. Single progressive-disclosure skill (Agent Skills format), mirroring MetaMask/smart-accounts-kit#264: a routing SKILL.md points into references/ (conventions, troubleshooting) and workflows/ (per-stack setup, sign/send for EVM + Solana, multichain invokeMethod, migration). Ported from MetaMask/skills#50 (now closed); source-verified against the published @metamask/connect-* packages. * docs(skills): fix stale wagmi connect-evm peer range and client wording - Correct the @wagmi/connectors metaMask() optional peer range from the stale ^1.3.0 to the current ^2.1.0 across setup-wagmi, setup-wagmi-connector, migrate-from-sdk, and migrate-wagmi-connector. The old guidance ("do not install 2.x") was inverted and would produce the peer mismatch it warned against; now points readers at `npm info @wagmi/connectors peerDependencies`. - Fix setup-evm-react-native: createEVMClient is not a singleton (only the multichain core is); each call returns a fresh wrapper. - Align Solana sign/send prerequisites with setup-solana-react: createSolanaClient need not resolve before first render (wallet registers ~1s later). * docs(skills): add Content Security Policy guidance Add a Content Security Policy section to conventions.md covering the required relay WebSocket and QR data: URI origins, optional analytics / Stencil style allowances, and a minimal example. Add pointers from the browser-specific setup guides (EVM, Solana, multichain) and a dedicated troubleshooting entry so a CSP-blocked relay (which presents as a hung connection) is diagnosable. * docs(skills): add Node.js (CLI / server) setup workflow Add workflows/setup-node.md covering headless integration: terminal ASCII QR connect via MetaMask Mobile, createMultichainClient as the recommended Node entry point (connect-multichain/connect-solana ship node builds; connect-evm delegates to the multichain node build), EVM/Solana signing through invokeMethod, the in-memory default storage caveat (no persistence across restarts) and how to supply a custom StoreClient, and the absence of polyfill/CSP requirements. Wire it into SKILL.md with a routing row and a "When to use" bullet. * docs(skills): fix prettier formatting in setup-node.md Wrap the long Buffer.from(...).toString('base64') line in the Solana invokeMethod example so it satisfies the repo's prettier (lint:misc) 80-col rule. Resolves the failing Lint CI job. * docs(skills): split conventions.md into focused references; dedupe cross-cutting blocks Reduce documentation drift surface by giving each topic a single canonical home, per the Agent Skills guidance (focused reference files, TOCs >300 lines) and mirroring MetaMask/smart-accounts-kit#264's domain-split refs. - Split the 610-line conventions.md into 7 focused, domain-organized references (evm, events, multichain, solana, react-native, csp, testing), each with its own table of contents. conventions.md is now a 93-line always-on core (import paths, config, supportedNetworks, singleton, error handling, connection state) plus a topic index routing to the rest. - Repoint the CSP cross-links in setup-evm-browser, setup-solana-browser, setup-multichain, and troubleshooting at the new canonical csp.md. - Point the two React Native setup workflows at react-native.md as the canonical polyfill/Metro reference (keeping their runnable recipes). - Update SKILL.md's always-on pointer to describe the core + focused refs. All skills/**/*.md pass prettier (3.6.2) and every internal link/anchor resolves. * docs(skills): fix dangling react-native-polyfills rule references Point migrate-from-sdk and setup-wagmi-connector workflows at the existing references/react-native.md instead of a non-existent rule. * Apply suggestions from code review Co-authored-by: jiexi <jiexiluan@gmail.com> * docs(skills): clarify wagmi connector entrypoint and multichain dep Address review feedback on conventions.md import-paths section: - State that the wagmi metaMask() connector comes from wagmi/connectors with connect-evm as an optional peer; connect-evm ships no wagmi entrypoint. - Trim the multichain dependency bullet: drop the imprecise ^1.0.0 pin and 2.0.0 history, keep the load-bearing "installed transitively" fact. * docs(skills): tighten conventions, solana, events, and multichain refs Address review feedback: - conventions: merge duplicate dapp.url bullets; add Solana disconnect scope behavior; enumerate the EVM methods that are rejected. - solana: rewrite the Chrome Android note to be actionable (the wallet-adapter beforeunload patch is internal and not inherited by consumers); reframe the RN section as a third-party adapter limitation with the multichain/invokeMethod path. - events: reframe intro so it doesn't read as EVM-only; add a Solana state-changes section pointing at core.stateChanged. - multichain: trim the bundle/lazy-transport section to the one actionable guardrail. --------- Co-authored-by: jiexi <jiexiluan@gmail.com>
1 parent 96bcafe commit ddee296

28 files changed

Lines changed: 6145 additions & 0 deletions

skills/metamask-connect/SKILL.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
name: metamask-connect
3+
description: Build dApps that integrate MetaMask via the MetaMask Connect SDK — EVM (@metamask/connect-evm), Solana (@metamask/connect-solana), and multichain (@metamask/connect-multichain), plus the wagmi metaMask() connector. Covers client setup across browser/React/React Native, connecting, signing messages, sending transactions, multichain invokeMethod across CAIP-2 scopes, migrating from @metamask/sdk, and troubleshooting connection/polyfill issues.
4+
---
5+
6+
# MetaMask Connect SDK
7+
8+
## When to use
9+
10+
- You want to set up a dApp's MetaMask integration — EVM, Solana, or both (multichain) — in vanilla browser JS/TS, React, or React Native
11+
- You want a headless integration — a Node.js CLI, server, or bot that connects to MetaMask Mobile via a terminal QR code
12+
- You want to connect/disconnect, manage the provider and session state, or switch chains
13+
- You want to sign messages (`personal_sign`, `eth_signTypedData_v4`, Solana `signMessage`) — e.g. Sign-In With Ethereum or nonce auth
14+
- You want to send transactions (`eth_sendTransaction`, Solana `sendTransaction` / `signAndSendTransaction`)
15+
- You want to operate across chains through the multichain client's `invokeMethod`
16+
- You want to use or migrate to the wagmi `metaMask()` connector
17+
- You want to migrate an existing `@metamask/sdk` integration to the Connect SDK
18+
- You need to diagnose connection failures, React Native polyfill errors, or QR/deeplink issues
19+
20+
## Installation
21+
22+
Pick the client for your integration:
23+
24+
| You need | Package | Factory |
25+
| --------------------------------- | ---------------------------------------------------------------------- | ------------------------ |
26+
| EVM only | `@metamask/connect-evm` | `createEVMClient` |
27+
| Solana only | `@metamask/connect-solana` | `createSolanaClient` |
28+
| EVM **and** Solana in one session | `@metamask/connect-multichain` | `createMultichainClient` |
29+
| You already use wagmi | wagmi `metaMask()` connector (needs `@metamask/connect-evm` as a peer) ||
30+
31+
## Always-on conventions
32+
33+
Before writing or reviewing **any** MetaMask Connect code, read [references/conventions.md](references/conventions.md) — the always-on core guardrails (import paths, required config, `supportedNetworks`, singleton behavior, error handling, connection state) plus a topic index into focused references. Then load the focused reference(s) for your task: [evm.md](references/evm.md) (chain IDs / `switchChain`), [events.md](references/events.md), [multichain.md](references/multichain.md), [solana.md](references/solana.md), [react-native.md](references/react-native.md) (polyfills / Metro), [csp.md](references/csp.md), [testing.md](references/testing.md). Each topic has a single canonical home, so apply the relevant reference alongside every workflow below.
34+
35+
## Set up (choose your stack)
36+
37+
| Building | Workflow |
38+
| --------------------------------- | -------------------------------------------------------------------------------- |
39+
| EVM dApp — vanilla browser JS/TS | [workflows/setup-evm-browser.md](workflows/setup-evm-browser.md) |
40+
| EVM dApp — React | [workflows/setup-evm-react.md](workflows/setup-evm-react.md) |
41+
| EVM dApp — React Native | [workflows/setup-evm-react-native.md](workflows/setup-evm-react-native.md) |
42+
| Solana dApp — vanilla browser | [workflows/setup-solana-browser.md](workflows/setup-solana-browser.md) |
43+
| Solana dApp — React | [workflows/setup-solana-react.md](workflows/setup-solana-react.md) |
44+
| Solana dApp — React Native | [workflows/setup-solana-react-native.md](workflows/setup-solana-react-native.md) |
45+
| EVM + Solana (multichain) | [workflows/setup-multichain.md](workflows/setup-multichain.md) |
46+
| Node.js CLI / server (headless) | [workflows/setup-node.md](workflows/setup-node.md) |
47+
| wagmi app | [workflows/setup-wagmi.md](workflows/setup-wagmi.md) |
48+
| wagmi + the connect-evm connector | [workflows/setup-wagmi-connector.md](workflows/setup-wagmi-connector.md) |
49+
50+
## Sign & send (single-chain clients)
51+
52+
Use these with a directly-created EVM or Solana client. If you set up the **multichain** client, sign/send via `invokeMethod` instead — see the multichain workflows below.
53+
54+
| Task | Workflow |
55+
| ---------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
56+
| Sign — EVM (`personal_sign`, `eth_signTypedData_v4`, `connectAndSign`) | [workflows/sign-evm-message.md](workflows/sign-evm-message.md) |
57+
| Sign — Solana (wallet-standard `signMessage`) | [workflows/sign-solana-message.md](workflows/sign-solana-message.md) |
58+
| Send — EVM (`eth_sendTransaction`, gas, receipts, `connectWith`) | [workflows/send-evm-transaction.md](workflows/send-evm-transaction.md) |
59+
| Send — Solana (`sendTransaction` / `signAndSendTransaction`) | [workflows/send-solana-transaction.md](workflows/send-solana-transaction.md) |
60+
61+
## Multichain operations (`invokeMethod` across CAIP-2 scopes)
62+
63+
Use these after `createMultichainClient` to sign or send across CAIP-2 scopes.
64+
65+
| Ecosystem | Workflow |
66+
| --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
67+
| EVM scopes (`eth_sendTransaction`, `personal_sign`, `eth_signTypedData_v4`) | [workflows/multichain-evm-operations.md](workflows/multichain-evm-operations.md) |
68+
| Solana scopes (`signTransaction`, `signAndSendTransaction`, `signMessage`) | [workflows/multichain-solana-operations.md](workflows/multichain-solana-operations.md) |
69+
70+
## Migrate
71+
72+
| Migrating from | Workflow |
73+
| ----------------------------------------------------- | ---------------------------------------------------------------------------- |
74+
| `@metamask/sdk``@metamask/connect-*` | [workflows/migrate-from-sdk.md](workflows/migrate-from-sdk.md) |
75+
| wagmi app → the new `@metamask/connect-evm` connector | [workflows/migrate-wagmi-connector.md](workflows/migrate-wagmi-connector.md) |
76+
77+
## Troubleshooting
78+
79+
When a connection hangs/fails, a React Native app crashes on a missing polyfill, QR codes or deeplinks don't work, the Solana wallet adapter doesn't detect MetaMask, or a session is lost after reload — see [references/troubleshooting.md](references/troubleshooting.md) for a symptom → cause → fix index and a diagnostic checklist.
80+
81+
## Important notes
82+
83+
These are the highest-value guardrails; [references/conventions.md](references/conventions.md) has the full, source-verified set.
84+
85+
- EVM chain IDs are **hex strings** (`'0x1'`, not `1` or `'1'`); CAIP-2 scopes use **decimal** (`eip155:1`).
86+
- Every chain the dApp touches must be in `api.supportedNetworks` with a reachable RPC URL — the check runs in the provider's `request()` path, not in `connect()`.
87+
- The multichain core is a **singleton** — create clients once at startup, never inside a React render.
88+
- Handle EIP-1193 code `4001` (user rejected) and `-32002` (extension request pending) in `catch` blocks; multichain `invokeMethod` errors arrive wrapped in `RPCInvokeMethodErr` (original code on `rpcCode`).
89+
- React Native needs polyfills (a `window` shim always; `Event`/`CustomEvent` only when also using wagmi; `react-native-get-random-values` as the first import) plus metro `extraNodeModules` shims (`stream``readable-stream`, the rest → empty stubs).
90+
91+
## Resources
92+
93+
- NPM: `@metamask/connect-evm`, `@metamask/connect-solana`, `@metamask/connect-multichain`
94+
- Source plugin: https://github.com/MetaMask/metamask-connect-cursor-plugin
95+
- Provenance: generated from that plugin's `skills/` and always-on `rules/`, source-verified against the published `@metamask/connect-*` packages.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# MetaMask Connect — Conventions & Guardrails
2+
3+
Always-on guardrails for the MetaMask Connect SDK, distilled from the [MetaMask Connect Cursor plugin](https://github.com/MetaMask/metamask-connect-cursor-plugin) rules. Apply the core rules below whenever you generate or review MetaMask Connect (`@metamask/connect-evm` / `-multichain` / `-solana`) or wagmi `metaMask()` connector code. Deeper, domain-specific guidance lives in the focused reference files indexed below — read the one(s) relevant to your task.
4+
5+
## Topic index
6+
7+
Each topic has a single canonical home. Load the file for the area you're working in:
8+
9+
| Topic | Reference |
10+
| ---------------------------------------------------------------------------- | ---------------------------------------- |
11+
| EVM chain ID format (hex vs CAIP-2), `switchChain`, validation | [evm.md](evm.md) |
12+
| Event handling — EIP-1193 events, `eventHandlers`, EIP-6963, status | [events.md](events.md) |
13+
| Multichain session lifecycle — singleton, `wallet_sessionChanged`, timeouts | [multichain.md](multichain.md) |
14+
| Solana constraints — wallet adapter, CAIP-2 genesis hashes, RPC routing | [solana.md](solana.md) |
15+
| React Native — polyfills, import order, Metro `extraNodeModules`, `openLink` | [react-native.md](react-native.md) |
16+
| Content Security Policy (browser) origins | [csp.md](csp.md) |
17+
| Testing patterns — mocking, singleton cleanup, test networks | [testing.md](testing.md) |
18+
| Symptom → cause → fix index for connection/polyfill/QR issues | [troubleshooting.md](troubleshooting.md) |
19+
20+
## Core (always-on)
21+
22+
These cross-cutting rules apply to every MetaMask Connect integration regardless of stack.
23+
24+
### Import Paths
25+
26+
- Import EVM client from `@metamask/connect-evm`
27+
- Import multichain client from `@metamask/connect-multichain`
28+
- Import Solana client from `@metamask/connect-solana`
29+
- Never import from internal sub-packages like `@metamask/connect/dist/...` or `@metamask/connect-evm/src/...`
30+
- For wagmi, import the `metaMask()` connector from `wagmi/connectors` (wagmi >= 3.6 / `@wagmi/connectors` >= 8) — it uses `@metamask/connect-evm` under the hood as an optional peer dependency. `@metamask/connect-evm` does **not** ship its own wagmi entrypoint (there is no `@metamask/connect-evm/wagmi`). See [setup-wagmi-connector.md](../workflows/setup-wagmi-connector.md)
31+
- `@metamask/connect-multichain` is a **regular (transitive) dependency** of both `@metamask/connect-evm` and `@metamask/connect-solana` — it's installed automatically and you don't need to add it to your `package.json`. (If you import `createMultichainClient` directly, you can still rely on that transitively-installed copy; both clients `console.warn` at runtime if they detect a mismatched or duplicate `@metamask/connect-multichain` resolution.)
32+
33+
### Required Configuration
34+
35+
- `dapp.name` is always required — it appears in the MetaMask connection prompt
36+
- `dapp.url` is required in Node.js and React Native (no `window.location`); in the browser it defaults to `window.location.href`, but passing it explicitly is safer
37+
- `dapp.iconUrl` is optional — displayed in MetaMask connection UI
38+
- `dapp.base64Icon` is an alternative to `iconUrl` — pass a base64-encoded icon string directly (useful when a hosted URL is unavailable, e.g., in React Native)
39+
40+
### Supported Networks
41+
42+
- Every chain the dApp interacts with must be in `api.supportedNetworks` with a reachable RPC URL
43+
- Use `getInfuraRpcUrls({ infuraApiKey: 'API_KEY', chainIds?: Hex[] })` from `@metamask/connect-evm` to populate common EVM chains — it returns a hex-keyed map for `createEVMClient`
44+
- Use `getInfuraRpcUrls({ infuraApiKey: 'API_KEY', caipChainIds?: string[] })` from `@metamask/connect-multichain` to populate CAIP-2 chains for `createMultichainClient`
45+
- Use `getInfuraRpcUrls({ infuraApiKey: 'API_KEY', networks: SolanaNetwork[] })` from `@metamask/connect-solana` to populate a network-name-keyed map for `createSolanaClient``networks` is required
46+
- Chain `0x1` (Ethereum mainnet) is auto-included in the EVM `connect()` permission request if not specified — but it is **not** auto-added to `supportedNetworks`, which must list every chain explicitly
47+
- Making an RPC request whose active chain is missing from `supportedNetworks` throws "not configured in supportedNetworks" (the check runs in the provider's `request()` path, not in `connect()`). See [evm.md → Validation Error](evm.md#validation-error)
48+
49+
### Singleton Behavior
50+
51+
- `createMultichainClient` is the singleton shared core instance
52+
- `createEVMClient` and `createSolanaClient` create chain-specific wrappers on top of that shared multichain core
53+
- Repeated client creation still reuses the existing multichain session and merged core options, but EVM/Solana wrappers can attach fresh listeners
54+
- The multichain core keeps the `dapp` object from the first call and does not overwrite it later
55+
- Never call `create*Client` inside a React component render — call it once at app startup
56+
- Do not wrap client creation in `useEffect` or other hooks that may re-run
57+
- Full merge semantics: [multichain.md → Singleton Merging](multichain.md#singleton-merging)
58+
59+
### Error Handling
60+
61+
- Code `4001`: User rejected the request — show retry UI, do not log as application error. On the EVM provider it appears as `err.code`; on the multichain client it appears as `err.rpcCode` (see below)
62+
- Code `-32002` ("request already pending") comes from the **extension transport only** — multichain MWP concurrent `connect()` instead throws a plain `Error` ("Existing connection is pending...") with no numeric code
63+
- Wrap all `connect()`, `invokeMethod()`, and signing calls in try/catch
64+
- Multichain `invokeMethod()` errors are wrapped in `RPCInvokeMethodErr` (its own `code` is `53`); the wallet's original code/message/data are preserved on `rpcCode` / `rpcMessage` / `rpcData`:
65+
66+
```typescript
67+
import { RPCInvokeMethodErr } from '@metamask/connect-multichain';
68+
69+
try {
70+
await client.invokeMethod({ scope, request });
71+
} catch (err) {
72+
if (err instanceof RPCInvokeMethodErr && err.rpcCode === 4001) {
73+
// user rejection
74+
}
75+
}
76+
```
77+
78+
- Other exported error classes: `RPCHttpErr` (code 50), `RPCReadonlyResponseErr` (51), `RPCReadonlyRequestErr` (52) — for RPC-node-routed read calls. (There are no `ProtocolError`/`StorageError`/`RpcError` exports.)
79+
80+
### Connection State
81+
82+
- Check connection state before making signing requests
83+
- Listen for `wallet_sessionChanged` to track session state reactively
84+
- Do not call `connect()` on page reload if a session already exists — listen for session restoration via events
85+
- **Multichain client:** `disconnect()` with no arguments revokes all scopes and terminates the session; `disconnect(scopes)` revokes only those scopes
86+
- **EVM client:** `disconnect()` revokes only the `eip155:*` scopes — Solana scopes on the same session survive; full teardown requires the multichain client
87+
- **Solana client:** `disconnect()` revokes only the Solana scopes — EVM scopes on the same session survive; full teardown requires the multichain client
88+
89+
### Unsupported Methods
90+
91+
- The EVM client **rejects** these methods with `Method: <name> is not supported by Metamask Connect/EVM` (they are not silently ignored): `metamask_getProviderState`, `metamask_sendDomainMetadata`, `metamask_logWeb3ShimUsage`, `wallet_registerOnboarding`, `net_version`, `wallet_getPermissions`
92+
- Since `@metamask/connect-evm` 2.0.0, `wallet_requestPermissions` resolves to a spec-shaped requested-permissions array — but `connect()` remains the canonical way to establish permissions
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# MetaMask Connect — Content Security Policy (browser)
2+
3+
The canonical reference for CSP origins the SDK needs in the browser. Not relevant in Node.js or React Native. For always-on core guardrails see [conventions.md](conventions.md).
4+
5+
A host page with a strict CSP must allow MetaMask Connect's origins, or browser integrations fail in ways that look like other bugs — a blocked relay socket presents exactly like "connection hangs".
6+
7+
**Required:**
8+
9+
- `connect-src wss://mm-sdk-relay.api.cx.metamask.io` — the relay WebSocket used for remote (mobile / no-extension) connections. It cannot be proxied or deferred from within the library, so remote connections fail without it.
10+
- `img-src data:` — the install/QR modal in `@metamask/multichain-ui` embeds the MetaMask fox as a `data:` URI inside the generated QR code (it sets `saveAsBlob: false`), so the QR will not render without it.
11+
12+
**Also consider:**
13+
14+
- `connect-src https://mm-sdk-analytics.api.cx.metamask.io` — the `@metamask/analytics` telemetry endpoint, used when analytics are enabled (the default). Unnecessary if you set `analytics: { enabled: false }`.
15+
- `style-src 'unsafe-inline'``@metamask/multichain-ui` is built with Stencil, which injects component styles at runtime into Shadow DOM. Strict CSPs without `'unsafe-inline'` (or an equivalent nonce/hash strategy) may break modal styling.
16+
- RPC endpoints you pass to `supportedNetworks` (e.g. `https://*.infura.io` or your own node provider) — add the matching `connect-src` entries for whatever you configure.
17+
- `https://metamask.app.link` and `metamask://` — mobile deeplinks / universal links. These are top-level navigations and not normally subject to `connect-src`, but strict policies using `navigate-to` / `form-action` may need to allow them.
18+
19+
Minimal example (default analytics endpoint + Infura + install modal):
20+
21+
```
22+
connect-src 'self' wss://mm-sdk-relay.api.cx.metamask.io https://mm-sdk-analytics.api.cx.metamask.io https://*.infura.io;
23+
img-src 'self' data:;
24+
style-src 'self' 'unsafe-inline';
25+
```

0 commit comments

Comments
 (0)