@quidli/connect-mcp 0.6.0 → 0.6.3
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 +12 -6
- package/dist/mount.d.ts +2 -1
- package/dist/mount.js +30 -0
- package/dist/schemas.d.ts +94 -2
- package/dist/schemas.js +62 -2
- package/dist/tools/register.d.ts +1 -1
- package/dist/tools/register.js +34 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -34,23 +34,23 @@ See [Choose how to connect](#choose-how-to-connect) below for API keys, x402 wal
|
|
|
34
34
|
|
|
35
35
|
Then ask your agent:
|
|
36
36
|
|
|
37
|
-
> Resolve the
|
|
37
|
+
> Resolve the GitHub handle `justinquidli` to a wallet.
|
|
38
38
|
|
|
39
39
|
```json
|
|
40
40
|
{
|
|
41
41
|
"status": "completed",
|
|
42
42
|
"results": [
|
|
43
43
|
{
|
|
44
|
-
"type": "
|
|
45
|
-
"value": "
|
|
46
|
-
"ethWalletAddress": "
|
|
44
|
+
"type": "github",
|
|
45
|
+
"value": "justinquidli",
|
|
46
|
+
"ethWalletAddress": "0x6a48ADE3bE3F9f0b8B4c9af61Bb654A219311699",
|
|
47
47
|
"solWalletAddress": "9DD2CqPKZJoo7ZRgCXxJNMjhzfgVihSKtkZpn8qnEWK9"
|
|
48
48
|
}
|
|
49
49
|
]
|
|
50
50
|
}
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
Resolves across
|
|
53
|
+
Resolves across GitHub, X, Telegram, Discord, LinkedIn, Farcaster, email and phone — and generates a wallet for people who have never used Quidli.
|
|
54
54
|
|
|
55
55
|
Lookup, scores, and price run without a key under a shared anonymous quota. Add a [Connect API key](https://connect.quid.li) for higher limits, your own profile (`connect_me`), and Smart Send.
|
|
56
56
|
|
|
@@ -375,4 +375,10 @@ mistake.
|
|
|
375
375
|
| `connect_drop_balance` | Smart Send wallet balances on a chain — **API key only** |
|
|
376
376
|
|
|
377
377
|
|
|
378
|
-
Ask your client to use these tools when you need Connect data or actions.
|
|
378
|
+
Ask your client to use these tools when you need Connect data or actions.
|
|
379
|
+
|
|
380
|
+
## Contributing
|
|
381
|
+
|
|
382
|
+
This repository is a read-only mirror, regenerated on every release — changes
|
|
383
|
+
committed here are overwritten. Please open an issue rather than a pull request.
|
|
384
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
package/dist/mount.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IRouter } from 'express';
|
|
1
|
+
import type { IRouter, Request } from 'express';
|
|
2
2
|
import { AnonymousToolQuota } from './anonymous-quota.js';
|
|
3
3
|
export { resolveRequestHost } from './request-host.js';
|
|
4
4
|
export interface ConnectMcpMountOptions {
|
|
@@ -8,4 +8,5 @@ export interface ConnectMcpMountOptions {
|
|
|
8
8
|
}
|
|
9
9
|
export declare function resolveEmbeddedApiBaseUrl(port: number, env?: NodeJS.ProcessEnv): string;
|
|
10
10
|
export declare function isConnectMcpHost(hostname: string, env?: NodeJS.ProcessEnv): boolean;
|
|
11
|
+
export declare function normalizeAcceptHeader(req: Pick<Request, 'headers'>): void;
|
|
11
12
|
export declare function mountConnectMcpHttp(router: IRouter, options: ConnectMcpMountOptions): void;
|
package/dist/mount.js
CHANGED
|
@@ -39,6 +39,35 @@ export function isConnectMcpHost(hostname, env = process.env) {
|
|
|
39
39
|
normalized === 'mcp.staging.connect.quid.li' ||
|
|
40
40
|
normalized.endsWith('.mcp.connect.quid.li'));
|
|
41
41
|
}
|
|
42
|
+
// The MCP SDK's StreamableHTTPServerTransport requires the Accept header to
|
|
43
|
+
// name BOTH application/json and text/event-stream literally, and rejects
|
|
44
|
+
// anything else with 406. That is stricter than HTTP content negotiation: a
|
|
45
|
+
// wildcard Accept (the default for curl, fetch and most HTTP libraries, and
|
|
46
|
+
// for clients that omit the header entirely) does accept both, but is still
|
|
47
|
+
// refused. Directory health checkers and plain HTTP integrators hit this.
|
|
48
|
+
//
|
|
49
|
+
// So rewrite the header to the canonical form whenever the client's own Accept
|
|
50
|
+
// already permits both types (absent, wildcard, or the relevant type
|
|
51
|
+
// wildcards). A client that genuinely accepts neither is left alone and still
|
|
52
|
+
// gets its 406.
|
|
53
|
+
const CANONICAL_ACCEPT = 'application/json, text/event-stream';
|
|
54
|
+
export function normalizeAcceptHeader(req) {
|
|
55
|
+
const raw = req.headers.accept;
|
|
56
|
+
const value = Array.isArray(raw) ? raw.join(',') : (raw ?? '');
|
|
57
|
+
// No Accept header means "anything" per RFC 9110.
|
|
58
|
+
if (!value.trim()) {
|
|
59
|
+
req.headers.accept = CANONICAL_ACCEPT;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const types = value
|
|
63
|
+
.split(',')
|
|
64
|
+
.map((part) => part.split(';')[0].trim().toLowerCase())
|
|
65
|
+
.filter(Boolean);
|
|
66
|
+
const permits = (type) => types.includes(type) || types.includes('*/*') || types.includes(`${type.split('/')[0]}/*`);
|
|
67
|
+
if (permits('application/json') && permits('text/event-stream')) {
|
|
68
|
+
req.headers.accept = CANONICAL_ACCEPT;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
42
71
|
export function mountConnectMcpHttp(router, options) {
|
|
43
72
|
const { baseUrl } = options;
|
|
44
73
|
const env = options.env ?? process.env;
|
|
@@ -50,6 +79,7 @@ export function mountConnectMcpHttp(router, options) {
|
|
|
50
79
|
// No in-memory session map, so Cloud Run restarts / multiple instances
|
|
51
80
|
// never cause "Missing or invalid MCP session" errors.
|
|
52
81
|
router.all('/', async (req, res) => {
|
|
82
|
+
normalizeAcceptHeader(req);
|
|
53
83
|
const gate = gateHostedMcpRequest(req, { env, anonymousQuota });
|
|
54
84
|
if (!gate.ok) {
|
|
55
85
|
sendJsonRpcError(res, gate.status, gate.message, {
|
package/dist/schemas.d.ts
CHANGED
|
@@ -83,6 +83,93 @@ export declare const dropInputSchema: {
|
|
|
83
83
|
chainId: z.ZodNumber;
|
|
84
84
|
tokenContract: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
85
85
|
recipients: z.ZodArray<z.ZodObject<{
|
|
86
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "wallet"]>;
|
|
87
|
+
id: z.ZodOptional<z.ZodString>;
|
|
88
|
+
username: z.ZodOptional<z.ZodString>;
|
|
89
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
90
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "wallet"]>;
|
|
91
|
+
id: z.ZodOptional<z.ZodString>;
|
|
92
|
+
username: z.ZodOptional<z.ZodString>;
|
|
93
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
94
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "wallet"]>;
|
|
95
|
+
id: z.ZodOptional<z.ZodString>;
|
|
96
|
+
username: z.ZodOptional<z.ZodString>;
|
|
97
|
+
}, z.ZodTypeAny, "passthrough">>, "many">;
|
|
98
|
+
amountInWeiPerRecipient: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
99
|
+
ignoreFailedRecipients: z.ZodOptional<z.ZodBoolean>;
|
|
100
|
+
trustFilter: z.ZodOptional<z.ZodObject<{
|
|
101
|
+
context: z.ZodOptional<z.ZodString>;
|
|
102
|
+
mode: z.ZodEnum<["require", "skip"]>;
|
|
103
|
+
}, "strip", z.ZodTypeAny, {
|
|
104
|
+
mode: "require" | "skip";
|
|
105
|
+
context?: string | undefined;
|
|
106
|
+
}, {
|
|
107
|
+
mode: "require" | "skip";
|
|
108
|
+
context?: string | undefined;
|
|
109
|
+
}>>;
|
|
110
|
+
};
|
|
111
|
+
export declare const trustIdentitySchema: z.ZodObject<{
|
|
112
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
113
|
+
id: z.ZodOptional<z.ZodString>;
|
|
114
|
+
username: z.ZodOptional<z.ZodString>;
|
|
115
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
116
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
117
|
+
id: z.ZodOptional<z.ZodString>;
|
|
118
|
+
username: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
120
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
121
|
+
id: z.ZodOptional<z.ZodString>;
|
|
122
|
+
username: z.ZodOptional<z.ZodString>;
|
|
123
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
124
|
+
export declare const trustCreateInputSchema: {
|
|
125
|
+
to: z.ZodObject<{
|
|
126
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
127
|
+
id: z.ZodOptional<z.ZodString>;
|
|
128
|
+
username: z.ZodOptional<z.ZodString>;
|
|
129
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
130
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
131
|
+
id: z.ZodOptional<z.ZodString>;
|
|
132
|
+
username: z.ZodOptional<z.ZodString>;
|
|
133
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
134
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
135
|
+
id: z.ZodOptional<z.ZodString>;
|
|
136
|
+
username: z.ZodOptional<z.ZodString>;
|
|
137
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
138
|
+
level: z.ZodNumber;
|
|
139
|
+
context: z.ZodOptional<z.ZodString>;
|
|
140
|
+
expiresIn: z.ZodOptional<z.ZodNumber>;
|
|
141
|
+
};
|
|
142
|
+
export declare const trustRevokeInputSchema: {
|
|
143
|
+
to: z.ZodObject<{
|
|
144
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
145
|
+
id: z.ZodOptional<z.ZodString>;
|
|
146
|
+
username: z.ZodOptional<z.ZodString>;
|
|
147
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
148
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
149
|
+
id: z.ZodOptional<z.ZodString>;
|
|
150
|
+
username: z.ZodOptional<z.ZodString>;
|
|
151
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
152
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
153
|
+
id: z.ZodOptional<z.ZodString>;
|
|
154
|
+
username: z.ZodOptional<z.ZodString>;
|
|
155
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
156
|
+
context: z.ZodOptional<z.ZodString>;
|
|
157
|
+
};
|
|
158
|
+
export declare const trustCheckInputSchema: {
|
|
159
|
+
from: z.ZodObject<{
|
|
160
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
161
|
+
id: z.ZodOptional<z.ZodString>;
|
|
162
|
+
username: z.ZodOptional<z.ZodString>;
|
|
163
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
164
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
165
|
+
id: z.ZodOptional<z.ZodString>;
|
|
166
|
+
username: z.ZodOptional<z.ZodString>;
|
|
167
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
168
|
+
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
169
|
+
id: z.ZodOptional<z.ZodString>;
|
|
170
|
+
username: z.ZodOptional<z.ZodString>;
|
|
171
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
172
|
+
targets: z.ZodArray<z.ZodObject<{
|
|
86
173
|
type: z.ZodEnum<["email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "wallet", "username"]>;
|
|
87
174
|
id: z.ZodOptional<z.ZodString>;
|
|
88
175
|
username: z.ZodOptional<z.ZodString>;
|
|
@@ -95,6 +182,11 @@ export declare const dropInputSchema: {
|
|
|
95
182
|
id: z.ZodOptional<z.ZodString>;
|
|
96
183
|
username: z.ZodOptional<z.ZodString>;
|
|
97
184
|
}, z.ZodTypeAny, "passthrough">>, "many">;
|
|
98
|
-
|
|
99
|
-
|
|
185
|
+
context: z.ZodOptional<z.ZodString>;
|
|
186
|
+
};
|
|
187
|
+
export declare const trustGraphInputSchema: {
|
|
188
|
+
platform: z.ZodEnum<["wallet", "email", "phone", "telegram", "discord", "farcaster", "twitter", "github", "linkedin", "slack", "username"]>;
|
|
189
|
+
identifier: z.ZodString;
|
|
190
|
+
context: z.ZodOptional<z.ZodString>;
|
|
191
|
+
direction: z.ZodOptional<z.ZodEnum<["out", "in"]>>;
|
|
100
192
|
};
|
package/dist/schemas.js
CHANGED
|
@@ -16,6 +16,23 @@ const recipientTypeSchema = z.enum([
|
|
|
16
16
|
'username',
|
|
17
17
|
]);
|
|
18
18
|
const exposureRecipientTypeSchema = recipientTypeSchema;
|
|
19
|
+
const dropSocialTypeSchema = z.enum([
|
|
20
|
+
'email',
|
|
21
|
+
'phone',
|
|
22
|
+
'telegram',
|
|
23
|
+
'discord',
|
|
24
|
+
'farcaster',
|
|
25
|
+
'twitter',
|
|
26
|
+
'github',
|
|
27
|
+
]);
|
|
28
|
+
const dropRecipientTypeSchema = z.enum([...dropSocialTypeSchema.options, 'wallet']);
|
|
29
|
+
const dropRecipientSchema = z
|
|
30
|
+
.object({
|
|
31
|
+
type: dropRecipientTypeSchema,
|
|
32
|
+
id: z.string().optional(),
|
|
33
|
+
username: z.string().optional(),
|
|
34
|
+
})
|
|
35
|
+
.passthrough();
|
|
19
36
|
/** Unified recipient — API validates fully; MCP forwards JSON. */
|
|
20
37
|
export const linkedAccountSchema = z
|
|
21
38
|
.object({
|
|
@@ -94,9 +111,9 @@ export const dropInputSchema = {
|
|
|
94
111
|
.optional()
|
|
95
112
|
.describe('EVM ERC-20 contract or Solana SPL mint. Omit or null for the native token (ETH/POL/AVAX, or SOL on 1399811149). Do not use the zero address.'),
|
|
96
113
|
recipients: z
|
|
97
|
-
.array(
|
|
114
|
+
.array(dropRecipientSchema)
|
|
98
115
|
.min(1)
|
|
99
|
-
.describe('Wallet or social recipients (all wallet or all social, no mix). Optional amountInWei per recipient uses the same smallest-unit rules as amountInWeiPerRecipient. On
|
|
116
|
+
.describe('Wallet or social recipients (all wallet or all social, no mix). Social types: email, phone, telegram, discord, farcaster, twitter, github (numeric id or username). linkedin and slack are not supported — use connect_lookup first, then type wallet. Optional amountInWei per recipient uses the same smallest-unit rules as amountInWeiPerRecipient. On EVM, wallet ids are 0x addresses; on Solana, base58 pubkeys. Social lookup payouts use ethWalletAddress on EVM and solWalletAddress on Solana.'),
|
|
100
117
|
amountInWeiPerRecipient: z
|
|
101
118
|
.string()
|
|
102
119
|
.optional()
|
|
@@ -106,4 +123,47 @@ export const dropInputSchema = {
|
|
|
106
123
|
.boolean()
|
|
107
124
|
.optional()
|
|
108
125
|
.describe('When true, send to recipients that resolved successfully and skip failed lookups.'),
|
|
126
|
+
trustFilter: z
|
|
127
|
+
.object({
|
|
128
|
+
context: z.string().optional().describe('Restrict to this trust context. Omit to match any.'),
|
|
129
|
+
mode: z.enum(['require', 'skip']).describe('require = fail if anyone is outside the graph; skip = drop them'),
|
|
130
|
+
})
|
|
131
|
+
.optional()
|
|
132
|
+
.describe('Keep only recipients in the sender EAS trust graph.'),
|
|
133
|
+
};
|
|
134
|
+
export const trustIdentitySchema = linkedAccountSchema;
|
|
135
|
+
export const trustCreateInputSchema = {
|
|
136
|
+
to: trustIdentitySchema.describe('Identity to trust (wallet, social, or Connect username)'),
|
|
137
|
+
level: z.number().int().min(1).max(100).describe('Trust level 1–100'),
|
|
138
|
+
context: z.string().max(64).optional().describe('Optional context such as team:quidli'),
|
|
139
|
+
expiresIn: z.number().int().positive().optional().describe('Optional lifetime in seconds'),
|
|
140
|
+
};
|
|
141
|
+
export const trustRevokeInputSchema = {
|
|
142
|
+
to: trustIdentitySchema.describe('Identity to untrust'),
|
|
143
|
+
context: z.string().max(64).optional().describe('Revoke only this context. Omit to revoke all contexts for the pair.'),
|
|
144
|
+
};
|
|
145
|
+
export const trustCheckInputSchema = {
|
|
146
|
+
from: trustIdentitySchema.describe('Graph owner'),
|
|
147
|
+
targets: z.array(trustIdentitySchema).min(1).describe('Identities to test'),
|
|
148
|
+
context: z.string().max(64).optional().describe('If set, only this context matches'),
|
|
149
|
+
};
|
|
150
|
+
export const trustGraphInputSchema = {
|
|
151
|
+
platform: z
|
|
152
|
+
.enum([
|
|
153
|
+
'wallet',
|
|
154
|
+
'email',
|
|
155
|
+
'phone',
|
|
156
|
+
'telegram',
|
|
157
|
+
'discord',
|
|
158
|
+
'farcaster',
|
|
159
|
+
'twitter',
|
|
160
|
+
'github',
|
|
161
|
+
'linkedin',
|
|
162
|
+
'slack',
|
|
163
|
+
'username',
|
|
164
|
+
])
|
|
165
|
+
.describe('Identity platform, or username for a Connect username'),
|
|
166
|
+
identifier: z.string().min(1),
|
|
167
|
+
context: z.string().max(64).optional(),
|
|
168
|
+
direction: z.enum(['out', 'in']).optional().describe('out = who they trust (default); in = who trusts them'),
|
|
109
169
|
};
|
package/dist/tools/register.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import type { ConnectClient } from '../client.js';
|
|
3
|
-
export declare const CONNECT_MCP_TOOL_NAMES: readonly ["connect_get_price", "connect_get_chains", "connect_lookup", "connect_lookup_exposed", "connect_scores_batch", "connect_scores_by_account", "connect_scores_by_username", "connect_me", "connect_drop", "connect_drop_balance"];
|
|
3
|
+
export declare const CONNECT_MCP_TOOL_NAMES: readonly ["connect_get_price", "connect_get_chains", "connect_lookup", "connect_lookup_exposed", "connect_scores_batch", "connect_scores_by_account", "connect_scores_by_username", "connect_me", "connect_drop", "connect_drop_balance", "connect_trust_create", "connect_trust_revoke", "connect_trust_check", "connect_trust_graph"];
|
|
4
4
|
export declare function registerTools(server: McpServer, client: ConnectClient): void;
|
package/dist/tools/register.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dropBalanceInputSchema, dropInputSchema, lookupExposedInputSchema, lookupInputSchema, scoresBatchInputSchema, scoresByAccountInputSchema, scoresByUsernameInputSchema, } from '../schemas.js';
|
|
1
|
+
import { dropBalanceInputSchema, dropInputSchema, lookupExposedInputSchema, lookupInputSchema, scoresBatchInputSchema, scoresByAccountInputSchema, scoresByUsernameInputSchema, trustCheckInputSchema, trustCreateInputSchema, trustGraphInputSchema, trustRevokeInputSchema, } from '../schemas.js';
|
|
2
2
|
export const CONNECT_MCP_TOOL_NAMES = [
|
|
3
3
|
'connect_get_price',
|
|
4
4
|
'connect_get_chains',
|
|
@@ -10,6 +10,10 @@ export const CONNECT_MCP_TOOL_NAMES = [
|
|
|
10
10
|
'connect_me',
|
|
11
11
|
'connect_drop',
|
|
12
12
|
'connect_drop_balance',
|
|
13
|
+
'connect_trust_create',
|
|
14
|
+
'connect_trust_revoke',
|
|
15
|
+
'connect_trust_check',
|
|
16
|
+
'connect_trust_graph',
|
|
13
17
|
];
|
|
14
18
|
/**
|
|
15
19
|
* Tool annotations. `readOnlyHint` is load-bearing, not decorative: clients
|
|
@@ -42,7 +46,7 @@ export function registerTools(server, client) {
|
|
|
42
46
|
path: '/lookup/exposed',
|
|
43
47
|
body: { recipient },
|
|
44
48
|
}));
|
|
45
|
-
server.tool('connect_scores_batch', 'Batch scores for linked accounts or Connect usernames. Optional filter
|
|
49
|
+
server.tool('connect_scores_batch', 'Batch scores for linked accounts or Connect usernames. One result per request user. Optional filter sets passedFilter (quidli 0–100, neynar/lens 0–1, ethos 0–2800).', scoresBatchInputSchema, READ_ONLY, async ({ users, filter }) => client.request({
|
|
46
50
|
method: 'POST',
|
|
47
51
|
path: '/scores',
|
|
48
52
|
body: { users, ...(filter ? { filter } : {}) },
|
|
@@ -59,8 +63,8 @@ export function registerTools(server, client) {
|
|
|
59
63
|
method: 'GET',
|
|
60
64
|
path: '/account/me',
|
|
61
65
|
}));
|
|
62
|
-
server.tool('connect_drop', 'Execute a Smart Send from the API key owner Connect embedded wallet. EVM: batch native or ERC-20 (need native gas plus the token). Solana (chainId 1399811149): SOL or SPL from the Solana embedded wallet
|
|
63
|
-
'Solana native (tokenContract null): no ATA. Sending to a
|
|
66
|
+
server.tool('connect_drop', 'Execute a Smart Send from the API key owner Connect embedded wallet. EVM: batch native or ERC-20 (need native gas plus the token). Solana (chainId 1399811149): SOL or SPL from the Solana embedded wallet; packs up to 20 native or 10 SPL recipients per transaction. Social recipient types: email, phone, telegram, discord, farcaster, twitter, github (id or username). linkedin and slack are not on /drop — use connect_lookup first, then type wallet. After connect_lookup, EVM payouts use ethWalletAddress (never solWalletAddress); Solana payouts use solWalletAddress (never ethWalletAddress). Social types on /drop resolve server-side; for type wallet, pass the resolved payout address for the target chain. Omit tokenContract or set it to null for the native token; pass an ERC-20 contract or SPL mint otherwise — do not use the zero address. Amounts are smallest-unit integer strings (ETH 18 decimals, SOL 9, USDC usually 6). ' +
|
|
67
|
+
'Solana native (tokenContract null): no ATA. Sending to a recipient without an existing funded account requires amount ≥ 890880 lamports (rent-exempt minimum for a system account); that SOL stays with the recipient. Below that the tx fails. Sender also pays a ~5000-lamport fee. ' +
|
|
64
68
|
'Solana SPL: tokens sit in Associated Token Accounts (ATA), not on the wallet pubkey. Recipients need not already hold the token — the API prepends CreateIdempotent. The sender (not the recipient) pays ~2039280 lamports (~0.002039 SOL) rent per newly created dest ATA, plus tx fees, on top of the token amount (which can be as small as 1 unit). A 400 "Insufficient funds" on SPL is often missing SOL for ATA rent, not missing USDC. Token-2022 is not supported; USDC mint is EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v. ' +
|
|
65
69
|
'Always call connect_drop_balance first. Returns 201 when submitted or 202 when recipients still processing — retry with the same idempotencyKey.', dropInputSchema, SPENDS_FUNDS, async ({ ignoreFailedRecipients, ...body }) => client.request({
|
|
66
70
|
method: 'POST',
|
|
@@ -73,10 +77,35 @@ export function registerTools(server, client) {
|
|
|
73
77
|
}));
|
|
74
78
|
server.tool('connect_drop_balance', 'Get native and token balances for the API key owner Smart Send embedded wallet on a chain. Always call before connect_drop. Zero balances are omitted, so a missing token means balance 0. ' +
|
|
75
79
|
'EVM: confirm native gas plus the ERC-20 being sent. ' +
|
|
76
|
-
'Solana (chainId 1399811149): SOL in this response is spendable lamports on the wallet pubkey (rent locked in existing token accounts is not included). Native SOL drop to a
|
|
80
|
+
'Solana (chainId 1399811149): SOL in this response is spendable lamports on the wallet pubkey (rent locked in existing token accounts is not included). Native SOL drop to a recipient without an existing funded account: amount itself must be ≥ 890880 lamports and sender SOL must cover amount + ~5000 lamports fee. SPL drop: token balance ≥ total amount, and SOL ≥ tx fee + ~2039280 lamports (~0.002039 SOL) per recipient that may need a new Associated Token Account — even when sending USDC. Insufficient SOL for ATA rent fails before the token transfer.', dropBalanceInputSchema, READ_ONLY, async ({ chainId }) => client.request({
|
|
77
81
|
method: 'GET',
|
|
78
82
|
path: '/drop/balance',
|
|
79
83
|
requireApiKey: true,
|
|
80
84
|
query: { chainId: String(chainId) },
|
|
81
85
|
}));
|
|
86
|
+
server.tool('connect_trust_create', 'Create a unidirectional trust attestation on Base (EAS) from the API key owner embedded wallet to a wallet or social identity. Identical active attestations are returned without a new transaction. Requires CONNECT_API_KEY, Smart Send attestation signer enrolled, and ETH on Base for gas.', trustCreateInputSchema, SPENDS_FUNDS, async (body) => client.request({
|
|
87
|
+
method: 'POST',
|
|
88
|
+
path: '/trust',
|
|
89
|
+
body,
|
|
90
|
+
requireApiKey: true,
|
|
91
|
+
}));
|
|
92
|
+
server.tool('connect_trust_revoke', 'Revoke active trust attestations from the API key owner to a target. Optional context limits which attestations are revoked. Requires CONNECT_API_KEY and ETH on Base.', trustRevokeInputSchema, SPENDS_FUNDS, async (body) => client.request({
|
|
93
|
+
method: 'POST',
|
|
94
|
+
path: '/trust/revoke',
|
|
95
|
+
body,
|
|
96
|
+
requireApiKey: true,
|
|
97
|
+
}));
|
|
98
|
+
server.tool('connect_trust_check', 'Check whether identities sit in a trust graph at depth 1. Omit context to match any context.', trustCheckInputSchema, READ_ONLY, async (body) => client.request({
|
|
99
|
+
method: 'POST',
|
|
100
|
+
path: '/trust/check',
|
|
101
|
+
body,
|
|
102
|
+
}));
|
|
103
|
+
server.tool('connect_trust_graph', 'List outgoing or incoming trust edges for an identity at depth 1.', trustGraphInputSchema, READ_ONLY, async ({ platform, identifier, context, direction }) => client.request({
|
|
104
|
+
method: 'GET',
|
|
105
|
+
path: `/trust/graph/${encodeURIComponent(platform)}/${encodeURIComponent(identifier)}`,
|
|
106
|
+
query: {
|
|
107
|
+
context,
|
|
108
|
+
direction,
|
|
109
|
+
},
|
|
110
|
+
}));
|
|
82
111
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quidli/connect-mcp",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "MCP server for agent identity and reputation: resolve social handles to wallet addresses, score onchain reputation, and send USDC from any MCP client.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"./http": "./dist/http.js"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
|
-
"build": "tsc &&
|
|
58
|
+
"build": "tsc && node --input-type=commonjs -e \"const fs=require('fs'); for (const f of ['dist/index.js','dist/index-http.js']) fs.chmodSync(f, 0o755)\"",
|
|
59
59
|
"prepublishOnly": "npm run build",
|
|
60
60
|
"start": "node dist/index.js",
|
|
61
61
|
"start:http": "node dist/index-http.js",
|