@quidli/connect-mcp 0.1.1 → 0.2.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/README.md CHANGED
@@ -1,57 +1,128 @@
1
- # @quidli/connect-mcp
1
+ # Quidli Connect MCP
2
2
 
3
- MCP server exposing [Quidli Connect](https://connect.quid.li) product APIs as tools for Cursor, Claude Desktop, and other MCP hosts.
3
+ Use [Quidli Connect](https://connect.quid.li) from Cursor, Claude Desktop, or any MCP-compatible client — wallet lookup, scores, Smart Send drops, and the Connect agent.
4
4
 
5
- ## Requirements
5
+ ## Choose how to connect
6
6
 
7
- - Node.js 20+
8
- - A Connect API key ([Enable API access](https://connect.quid.li))
9
7
 
10
- ## Cursor configuration
8
+ | | **Hosted** (`mcp.connect.quid.li`) | **Local** (`npx @quidli/connect-mcp`) |
9
+ | --------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
10
+ | **Setup** | Add a URL in MCP settings | Run a local process via `npx` |
11
+ | **Auth** | Connect API key only | API key **or** x402 pay-per-call |
12
+ | **Pros** | No install; always on Quidli infrastructure; simplest setup | Wallet private key never leaves your machine; pay per call with USDC instead of an API key |
13
+ | **Cons** | Requires a Connect API key; no pay-per-call billing | Requires Node.js 20+; `npx` may download the package on first run |
14
+ | **Limitations** | Cannot use x402 / wallet auth — do **not** send a private key to the hosted endpoint | x402 mode needs USDC on Base (mainnet `8453`); `connect_drop` requires an API key |
11
15
 
12
- ### Remote URL (recommended for production)
13
16
 
14
- Same pattern as GitHub MCP — Cursor connects to a hosted endpoint and sends your API key in headers:
17
+ Get a Connect API key at [connect.quid.li](https://connect.quid.li) → **Enable API access**.
18
+
19
+ ---
20
+
21
+ ## Hosted (recommended)
22
+
23
+ Best if you have a Connect API key and want zero local setup.
24
+
25
+ ### Cursor
26
+
27
+ **If you already have other MCP servers:** skip the deeplink and [add manually](#cursor-manual) — the one-click install can overwrite your entire `mcp.json` in some Cursor versions.
28
+
29
+ [Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=quidli-connect&config=eyJ1cmwiOiJodHRwczovL21jcC5jb25uZWN0LnF1aWQubGkiLCJoZWFkZXJzIjp7IngtYXBpLWtleSI6IiJ9fQ==)
30
+
31
+ Or paste into **Cursor Settings → MCP → Add new MCP server**:
32
+
33
+ ```
34
+ cursor://anysphere.cursor-deeplink/mcp/install?name=quidli-connect&config=eyJ1cmwiOiJodHRwczovL21jcC5jb25uZWN0LnF1aWQubGkiLCJoZWFkZXJzIjp7IngtYXBpLWtleSI6IiJ9fQ==
35
+ ```
36
+
37
+ Then open **Cursor Settings → MCP → quidli-connect** and set `headers.x-api-key` to your Connect API key.
38
+
39
+ #### Add manually {#cursor-manual}
40
+
41
+ Merge this into `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project) under `mcpServers` — do not replace your existing entries:
42
+
43
+ ```json
44
+ "quidli-connect": {
45
+ "url": "https://mcp.connect.quid.li",
46
+ "headers": {
47
+ "x-api-key": "<your-connect-api-key>"
48
+ }
49
+ }
50
+ ```
51
+
52
+ ### Claude Desktop
53
+
54
+ 1. Open **Claude → Settings → Connectors** (or **Settings → Developer → Edit Config** on older versions).
55
+ 2. Add a custom MCP connector with URL `https://mcp.connect.quid.li` and header `x-api-key: <your-connect-api-key>`.
56
+
57
+ Or merge this into your config file and restart Claude:
58
+
59
+ - **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
60
+ - **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
15
61
 
16
62
  ```json
17
63
  {
18
64
  "mcpServers": {
19
- "connect": {
65
+ "quidli-connect": {
20
66
  "url": "https://mcp.connect.quid.li",
21
67
  "headers": {
22
- "x-api-key": "set-your-api-key-here"
68
+ "x-api-key": "<your-connect-api-key>"
23
69
  }
24
70
  }
25
71
  }
26
72
  }
27
73
  ```
28
74
 
29
- After one-click install, open **Cursor Settings → MCP → connect** and replace `set-your-api-key-here` with your real API key from [connect.quid.li](https://connect.quid.li) (Enable API access). Until you do, the server returns `401` with setup instructions.
30
-
31
- **Add to Cursor** deeplink (placeholder key pre-filled):
75
+ If your Claude version does not support remote `url` connectors, use the local bridge instead (still hosted API, runs a small local helper):
32
76
 
33
- ```
34
- cursor://anysphere.cursor-deeplink/mcp/install?name=connect&config=eyJ1cmwiOiJodHRwczovL21jcC5jb25uZWN0LnF1aWQubGkIiwiaGVhZGVycyI6eyJ4LWFwaS1rZXkiOiJzZXQteW91ci1hcGkta2V5LWhlcmUifX0=
77
+ ```json
78
+ {
79
+ "mcpServers": {
80
+ "quidli-connect": {
81
+ "command": "npx",
82
+ "args": [
83
+ "-y",
84
+ "mcp-remote@latest",
85
+ "--http",
86
+ "https://mcp.connect.quid.li",
87
+ "--header",
88
+ "x-api-key:${CONNECT_API_KEY}"
89
+ ],
90
+ "env": {
91
+ "CONNECT_API_KEY": "<your-connect-api-key>"
92
+ }
93
+ }
94
+ }
95
+ }
35
96
  ```
36
97
 
37
- Or generate programmatically:
98
+ Requires **Node.js 20+** for the bridge. Restart Claude Desktop after saving. You should see a hammer icon in the chat input when tools are available.
38
99
 
39
- ```typescript
40
- import { buildCursorMcpInstallDeeplink } from '@quidli/connect-mcp/deeplink';
41
- ```
100
+ Until a valid API key is set, requests return `401` with setup instructions.
101
+
102
+ ---
103
+
104
+ ## Local (stdio)
105
+
106
+ Best if you want pay-per-call with a wallet, or prefer credentials in a local env file.
107
+
108
+ Requires **Node.js 20+**.
109
+
110
+ ### Cursor
111
+
112
+ Add one of the following to `.cursor/mcp.json` (project) or your global MCP settings.
42
113
 
43
- ### Local stdio (npm / development)
114
+ #### Option A — API key
44
115
 
45
- Add to `.cursor/mcp.json` (or global MCP settings):
116
+ Same billing model as hosted; credentials stay on your machine.
46
117
 
47
118
  ```json
48
119
  {
49
120
  "mcpServers": {
50
- "connect": {
121
+ "quidli-connect": {
51
122
  "command": "npx",
52
123
  "args": ["-y", "@quidli/connect-mcp"],
53
124
  "env": {
54
- "CONNECT_API_KEY": "<your-api-key>",
125
+ "CONNECT_API_KEY": "<your-connect-api-key>",
55
126
  "CONNECT_API_BASE_URL": "https://api.connect.quid.li"
56
127
  }
57
128
  }
@@ -59,59 +130,91 @@ Add to `.cursor/mcp.json` (or global MCP settings):
59
130
  }
60
131
  ```
61
132
 
62
- `CONNECT_API_KEY` is **required** for stdio mode — the process exits at startup if missing. Remote HTTP mode reads `x-api-key` from each request instead.
133
+ #### Option B — x402 pay-per-call (wallet)
63
134
 
64
- ## Standalone HTTP server (local / debugging)
135
+ No API key. Authenticated calls pay automatically when the API returns HTTP 402. Your wallet private key is only read by the local process.
65
136
 
66
- ```bash
67
- cd packages/connect-mcp
68
- npm run build
69
- CONNECT_API_BASE_URL=https://api.connect.quid.li npm run start:http
137
+ ```json
138
+ {
139
+ "mcpServers": {
140
+ "quidli-connect": {
141
+ "command": "npx",
142
+ "args": ["-y", "@quidli/connect-mcp"],
143
+ "env": {
144
+ "EVM_PRIVATE_KEY": "0x<wallet-with-usdc-on-base>",
145
+ "CONNECT_API_BASE_URL": "https://api.connect.quid.li",
146
+ "CONNECT_X402_EVM_NETWORK": "8453"
147
+ }
148
+ }
149
+ }
150
+ }
70
151
  ```
71
152
 
72
- Environment:
153
+ Use `84532` for Base Sepolia when pointing at a staging API.
73
154
 
74
- | Variable | Default | Description |
75
- |----------|---------|-------------|
76
- | `CONNECT_MCP_HTTP_HOST` | `0.0.0.0` | Bind address |
77
- | `CONNECT_MCP_HTTP_PORT` | `8080` | Listen port |
78
- | `CONNECT_API_BASE_URL` | `https://api.connect.quid.li` | Upstream Connect API |
155
+ ### Claude Desktop
79
156
 
80
- Health check: `GET /health`
157
+ 1. Open **Claude → Settings → Developer → Edit Config** (enable Developer mode first if you do not see it).
158
+ 2. Merge one of the blocks below into `mcpServers` in:
81
159
 
82
- ## Tools (7)
160
+ - **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
161
+ - **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
83
162
 
84
- | Tool | HTTP | Auth |
85
- |------|------|------|
86
- | `connect_get_price` | `GET /price` | none |
87
- | `connect_lookup` | `POST /lookup` | api-key |
88
- | `connect_scores_batch` | `POST /scores` | api-key |
89
- | `connect_scores_by_account` | `GET /scores/:platform/:identifier` | api-key |
90
- | `connect_scores_by_username` | `GET /scores/u/:username` | api-key |
91
- | `connect_drop` | `POST /drop` | api-key |
92
- | `connect_agent_prompt` | `POST /agent` | api-key |
163
+ 3. Restart Claude Desktop.
93
164
 
94
- Not exposed: `POST /lookup/exposed`, agent feedback, member/admin routes.
165
+ #### Option A — API key
95
166
 
96
- ## Auth notes
97
-
98
- - **MCP uses api-key only.** x402 pay-per-call and Privy Bearer are HTTP-only (use [API docs](https://connect.quid.li/docs) or skills directly).
99
- - `connect_get_price` is public on the HTTP API and does not send `x-api-key`.
167
+ ```json
168
+ {
169
+ "mcpServers": {
170
+ "quidli-connect": {
171
+ "command": "npx",
172
+ "args": ["-y", "@quidli/connect-mcp"],
173
+ "env": {
174
+ "CONNECT_API_KEY": "<your-connect-api-key>",
175
+ "CONNECT_API_BASE_URL": "https://api.connect.quid.li"
176
+ }
177
+ }
178
+ }
179
+ }
180
+ ```
100
181
 
101
- ## Development
182
+ #### Option B — x402 pay-per-call (wallet)
102
183
 
103
- ```bash
104
- cd packages/connect-mcp
105
- npm install
106
- npm test
107
- npm run build
108
- CONNECT_API_KEY=<key> npm start
184
+ ```json
185
+ {
186
+ "mcpServers": {
187
+ "quidli-connect": {
188
+ "command": "npx",
189
+ "args": ["-y", "@quidli/connect-mcp"],
190
+ "env": {
191
+ "EVM_PRIVATE_KEY": "0x<wallet-with-usdc-on-base>",
192
+ "CONNECT_API_BASE_URL": "https://api.connect.quid.li",
193
+ "CONNECT_X402_EVM_NETWORK": "8453"
194
+ }
195
+ }
196
+ }
197
+ }
109
198
  ```
110
199
 
111
- ## Publish
200
+ If both `CONNECT_API_KEY` and `EVM_PRIVATE_KEY` are set, the API key is used.
201
+
202
+ At least one of `CONNECT_API_KEY` or `EVM_PRIVATE_KEY` is required for local mode.
203
+
204
+ ---
205
+
206
+ ## Tools
207
+
208
+
209
+ | Tool | What it does |
210
+ | ---------------------------- | --------------------------------------------------------- |
211
+ | `connect_get_price` | List reference prices (no auth) |
212
+ | `connect_lookup` | Resolve social identities to EVM and SOL wallet addresses |
213
+ | `connect_scores_batch` | Batch scores for accounts or usernames |
214
+ | `connect_scores_by_account` | Scores for one linked account |
215
+ | `connect_scores_by_username` | Scores by Connect username |
216
+ | `connect_drop` | Smart Send (batch token transfer) — **API key only** |
217
+ | `connect_agent_prompt` | Natural-language agent for recipients discovery |
112
218
 
113
- ```bash
114
- npm publish --access public
115
- ```
116
219
 
117
- (Requires `@quidli` npm org access.)
220
+ Ask your client to use these tools when you need Connect data or actions.
package/dist/client.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { ConnectClientConfig } from './config.js';
2
2
  import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
3
3
  export type HttpMethod = 'GET' | 'POST';
4
+ export type ConnectAuthMode = 'api-key' | 'x402';
4
5
  export interface ConnectRequestOptions {
5
6
  method: HttpMethod;
6
7
  path: string;
@@ -11,6 +12,9 @@ export interface ConnectRequestOptions {
11
12
  }
12
13
  export declare class ConnectClient {
13
14
  private readonly config;
15
+ private readonly authMode;
16
+ private readonly paidFetch?;
14
17
  constructor(config: ConnectClientConfig);
18
+ private resolveFetch;
15
19
  request(options: ConnectRequestOptions): Promise<CallToolResult>;
16
20
  }
package/dist/client.js CHANGED
@@ -1,9 +1,22 @@
1
1
  import { mapHttpError } from './errors.js';
2
2
  import { errorResult, successResult } from './result.js';
3
+ import { createPaidFetch } from './x402-fetch.js';
3
4
  export class ConnectClient {
4
5
  config;
6
+ authMode;
7
+ paidFetch;
5
8
  constructor(config) {
6
9
  this.config = config;
10
+ this.authMode = config.apiKey ? 'api-key' : 'x402';
11
+ if (!config.apiKey && config.evmPrivateKey) {
12
+ this.paidFetch = createPaidFetch(config.evmPrivateKey, config.x402EvmNetwork);
13
+ }
14
+ }
15
+ resolveFetch(authenticated) {
16
+ if (authenticated && this.paidFetch) {
17
+ return this.paidFetch;
18
+ }
19
+ return fetch;
7
20
  }
8
21
  async request(options) {
9
22
  const { method, path, body, query, timeoutMs } = options;
@@ -19,7 +32,7 @@ export class ConnectClient {
19
32
  const headers = {
20
33
  accept: 'application/json',
21
34
  };
22
- if (authenticated) {
35
+ if (authenticated && this.config.apiKey) {
23
36
  headers['x-api-key'] = this.config.apiKey;
24
37
  }
25
38
  if (body !== undefined) {
@@ -29,8 +42,9 @@ export class ConnectClient {
29
42
  const timeout = timeoutMs
30
43
  ? setTimeout(() => controller.abort(), timeoutMs)
31
44
  : undefined;
45
+ const httpFetch = this.resolveFetch(authenticated);
32
46
  try {
33
- const response = await fetch(url, {
47
+ const response = await httpFetch(url, {
34
48
  method,
35
49
  headers,
36
50
  body: body !== undefined ? JSON.stringify(body) : undefined,
@@ -39,9 +53,9 @@ export class ConnectClient {
39
53
  const raw = await response.json().catch(() => ({}));
40
54
  if (!response.ok) {
41
55
  if (response.status === 504) {
42
- return errorResult(mapHttpError(504, raw));
56
+ return errorResult(mapHttpError(504, raw, this.authMode));
43
57
  }
44
- return errorResult(mapHttpError(response.status, raw));
58
+ return errorResult(mapHttpError(response.status, raw, this.authMode));
45
59
  }
46
60
  return successResult({
47
61
  httpStatus: response.status,
package/dist/config.d.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  export interface ConnectClientConfig {
2
2
  baseUrl: string;
3
- apiKey: string;
3
+ /** When set, sent on every authenticated Connect API request. */
4
+ apiKey?: string;
5
+ /** When apiKey is unset, authenticated requests pay via x402 on 402. */
6
+ evmPrivateKey?: `0x${string}`;
7
+ /** EVM chain id for x402 (default 8453 = Base mainnet). */
8
+ x402EvmNetwork: number;
4
9
  }
5
10
  export interface HttpServerConfig {
6
11
  host: string;
@@ -8,4 +13,7 @@ export interface HttpServerConfig {
8
13
  baseUrl: string;
9
14
  }
10
15
  export declare function loadHttpServerConfig(env?: NodeJS.ProcessEnv): HttpServerConfig;
16
+ /** Stdio MCP: CONNECT_API_KEY and/or EVM_PRIVATE_KEY (at least one required). */
11
17
  export declare function loadConfig(env?: NodeJS.ProcessEnv): ConnectClientConfig;
18
+ /** Hosted HTTP MCP: api-key from request header only. */
19
+ export declare function createHostedClientConfig(apiKey: string, baseUrl: string): ConnectClientConfig;
package/dist/config.js CHANGED
@@ -1,6 +1,19 @@
1
+ import { normalizeEvmPrivateKey } from './x402-fetch.js';
1
2
  const DEFAULT_BASE_URL = 'https://api.connect.quid.li';
2
3
  const DEFAULT_HTTP_HOST = '0.0.0.0';
3
4
  const DEFAULT_HTTP_PORT = 8080;
5
+ const DEFAULT_X402_EVM_NETWORK = 8453;
6
+ function parseX402EvmNetwork(env) {
7
+ const raw = env.CONNECT_X402_EVM_NETWORK?.trim() || env.X402_EVM_NETWORK?.trim() || String(DEFAULT_X402_EVM_NETWORK);
8
+ const network = Number(raw);
9
+ if (!Number.isInteger(network) || network < 1) {
10
+ throw new Error(`CONNECT_X402_EVM_NETWORK must be a positive integer (got "${raw}")`);
11
+ }
12
+ return network;
13
+ }
14
+ function loadBaseUrl(env) {
15
+ return (env.CONNECT_API_BASE_URL?.trim() || DEFAULT_BASE_URL).replace(/\/$/, '');
16
+ }
4
17
  export function loadHttpServerConfig(env = process.env) {
5
18
  const host = env.CONNECT_MCP_HTTP_HOST?.trim() || DEFAULT_HTTP_HOST;
6
19
  const portRaw = env.CONNECT_MCP_HTTP_PORT?.trim() || String(DEFAULT_HTTP_PORT);
@@ -8,14 +21,28 @@ export function loadHttpServerConfig(env = process.env) {
8
21
  if (!Number.isInteger(port) || port < 1 || port > 65535) {
9
22
  throw new Error(`CONNECT_MCP_HTTP_PORT must be a valid port (got "${portRaw}")`);
10
23
  }
11
- const baseUrl = (env.CONNECT_API_BASE_URL?.trim() || DEFAULT_BASE_URL).replace(/\/$/, '');
12
- return { host, port, baseUrl };
24
+ return { host, port, baseUrl: loadBaseUrl(env) };
13
25
  }
26
+ /** Stdio MCP: CONNECT_API_KEY and/or EVM_PRIVATE_KEY (at least one required). */
14
27
  export function loadConfig(env = process.env) {
15
- const apiKey = env.CONNECT_API_KEY?.trim();
16
- if (!apiKey) {
17
- throw new Error('CONNECT_API_KEY is required. Get a key at https://connect.quid.li (Enable API access).');
28
+ const apiKey = env.CONNECT_API_KEY?.trim() || undefined;
29
+ const evmPrivateKey = normalizeEvmPrivateKey(env.EVM_PRIVATE_KEY);
30
+ const x402EvmNetwork = parseX402EvmNetwork(env);
31
+ if (!apiKey && !evmPrivateKey) {
32
+ throw new Error('CONNECT_API_KEY or EVM_PRIVATE_KEY is required. Get an API key at https://connect.quid.li (Enable API access), or set EVM_PRIVATE_KEY for pay-per-call x402.');
18
33
  }
19
- const baseUrl = (env.CONNECT_API_BASE_URL?.trim() || DEFAULT_BASE_URL).replace(/\/$/, '');
20
- return { apiKey, baseUrl };
34
+ return {
35
+ baseUrl: loadBaseUrl(env),
36
+ apiKey,
37
+ evmPrivateKey: apiKey ? undefined : evmPrivateKey,
38
+ x402EvmNetwork,
39
+ };
40
+ }
41
+ /** Hosted HTTP MCP: api-key from request header only. */
42
+ export function createHostedClientConfig(apiKey, baseUrl) {
43
+ return {
44
+ baseUrl,
45
+ apiKey,
46
+ x402EvmNetwork: DEFAULT_X402_EVM_NETWORK,
47
+ };
21
48
  }
package/dist/deeplink.js CHANGED
@@ -7,7 +7,7 @@ export function buildCursorRemoteMcpConfig(apiKey = CONNECT_MCP_API_KEY_PLACEHOL
7
7
  },
8
8
  };
9
9
  }
10
- export function buildCursorMcpInstallDeeplink(serverName = 'connect', config = buildCursorRemoteMcpConfig()) {
10
+ export function buildCursorMcpInstallDeeplink(serverName = 'quidli-connect', config = buildCursorRemoteMcpConfig()) {
11
11
  const encoded = Buffer.from(JSON.stringify(config), 'utf8').toString('base64');
12
12
  return `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(serverName)}&config=${encoded}`;
13
13
  }
package/dist/errors.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export declare function parseNestErrorMessage(body: unknown): string;
2
- export declare function mapHttpError(status: number, body: unknown): string;
2
+ export type ConnectAuthMode = 'api-key' | 'x402';
3
+ export declare function mapHttpError(status: number, body: unknown, authMode?: ConnectAuthMode): string;
package/dist/errors.js CHANGED
@@ -10,15 +10,19 @@ export function parseNestErrorMessage(body) {
10
10
  }
11
11
  return 'Request failed';
12
12
  }
13
- export function mapHttpError(status, body) {
13
+ export function mapHttpError(status, body, authMode = 'api-key') {
14
14
  const detail = parseNestErrorMessage(body);
15
15
  switch (status) {
16
16
  case 400:
17
17
  return detail;
18
18
  case 401:
19
- return `Unauthorized: ${detail}. Verify CONNECT_API_KEY at https://connect.quid.li`;
19
+ return authMode === 'api-key'
20
+ ? `Unauthorized: ${detail}. Verify CONNECT_API_KEY at https://connect.quid.li`
21
+ : `Unauthorized: ${detail}. Verify EVM_PRIVATE_KEY and wallet USDC balance for x402.`;
20
22
  case 402:
21
- return `Payment required (${detail}). MCP requires a valid Connect API key — x402 is not supported in MCP.`;
23
+ return authMode === 'api-key'
24
+ ? `Payment required (${detail}). Set CONNECT_API_KEY or use local stdio with EVM_PRIVATE_KEY for x402.`
25
+ : `Payment failed (${detail}). Ensure your wallet has USDC on the expected network and EVM_PRIVATE_KEY is correct.`;
22
26
  case 404:
23
27
  return detail;
24
28
  case 504:
package/dist/mount.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
2
+ import { createHostedClientConfig } from './config.js';
2
3
  import { createMcpServer } from './create-mcp-server.js';
3
4
  import { validateRequestApiKey } from './http-auth.js';
4
5
  export { resolveRequestHost } from './request-host.js';
@@ -49,7 +50,7 @@ export function mountConnectMcpHttp(router, options) {
49
50
  return;
50
51
  }
51
52
  try {
52
- const server = createMcpServer({ apiKey: auth.apiKey, baseUrl });
53
+ const server = createMcpServer(createHostedClientConfig(auth.apiKey, baseUrl));
53
54
  const transport = new StreamableHTTPServerTransport({
54
55
  sessionIdGenerator: undefined, // stateless — no session tracking
55
56
  enableJsonResponse: true,
@@ -0,0 +1,2 @@
1
+ export declare function normalizeEvmPrivateKey(value: string | undefined): `0x${string}` | undefined;
2
+ export declare function createPaidFetch(evmPrivateKey: `0x${string}`, chainId: number): typeof fetch;
@@ -0,0 +1,30 @@
1
+ import { x402Client, wrapFetchWithPayment } from '@x402/fetch';
2
+ import { ExactEvmScheme } from '@x402/evm/exact/client';
3
+ import { toClientEvmSigner } from '@x402/evm';
4
+ import { privateKeyToAccount } from 'viem/accounts';
5
+ import { createPublicClient, http } from 'viem';
6
+ import { base, baseSepolia } from 'viem/chains';
7
+ const EVM_CHAIN_BY_ID = {
8
+ 8453: base,
9
+ 84532: baseSepolia,
10
+ };
11
+ export function normalizeEvmPrivateKey(value) {
12
+ const trimmed = value?.trim();
13
+ if (!trimmed) {
14
+ return undefined;
15
+ }
16
+ return (trimmed.startsWith('0x') ? trimmed : `0x${trimmed}`);
17
+ }
18
+ function getEvmPublicClient(chainId) {
19
+ const chain = EVM_CHAIN_BY_ID[chainId] ?? base;
20
+ return createPublicClient({ chain, transport: http() });
21
+ }
22
+ export function createPaidFetch(evmPrivateKey, chainId) {
23
+ const account = privateKeyToAccount(evmPrivateKey);
24
+ const evmSigner = toClientEvmSigner(account, getEvmPublicClient(chainId));
25
+ const client = new x402Client();
26
+ const scheme = new ExactEvmScheme(evmSigner);
27
+ client.register(`eip155:${chainId}`, scheme);
28
+ client.register('eip155:*', scheme);
29
+ return wrapFetchWithPayment(fetch, client);
30
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quidli/connect-mcp",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for Quidli Connect product APIs",
5
5
  "keywords": [
6
6
  "mcp",
@@ -13,6 +13,11 @@
13
13
  "agent"
14
14
  ],
15
15
  "homepage": "https://connect.quid.li",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/Quidli/sns-backend.git",
19
+ "directory": "packages/connect-mcp"
20
+ },
16
21
  "author": {
17
22
  "name": "Quidli",
18
23
  "url": "https://quid.xyz"
@@ -47,10 +52,14 @@
47
52
  },
48
53
  "dependencies": {
49
54
  "@modelcontextprotocol/sdk": "^1.25.2",
55
+ "@x402/evm": "~2.5.0",
56
+ "@x402/fetch": "~2.5.0",
50
57
  "express": "^5.2.1",
58
+ "viem": "^2.50.4",
51
59
  "zod": "^3.24.2"
52
60
  },
53
61
  "devDependencies": {
62
+ "@types/express": "^5.0.6",
54
63
  "@types/node": "^22.13.10",
55
64
  "typescript": "^5.8.2",
56
65
  "vitest": "^3.0.9"