@ziggs-ai/ziggs-mcp 0.3.1 → 0.4.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 +1 -1
- package/dist/capabilityAdapter.d.ts +25 -0
- package/dist/capabilityAdapter.js +75 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +11 -2
- package/dist/connectionCreds.js +1 -0
- package/dist/paymentTools.d.ts +9 -8
- package/dist/paymentTools.js +12 -248
- package/dist/tools.js +178 -441
- package/dist/trustTools.d.ts +4 -1
- package/dist/trustTools.js +21 -230
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -208,7 +208,7 @@ OP_KEY_A=... AGENT_A=... USER_B=... OP_KEY_B=... AGENT_B=... \
|
|
|
208
208
|
| `ziggs_revoke_agreement` | `DELETE /agreements/:id` — any agreement (hire/service/quest/link) |
|
|
209
209
|
| `ziggs_smoke_impersonation` | [Internal/debug] connectivity check — only when `ZIGGS_MCP_DEBUG=1`; not part of normal delegate workflow |
|
|
210
210
|
| `ziggs_context_snapshot` | `GET /context/snapshot?via=chat:` — one-shot chat orientation (history + agreements + roster), grant-fenced |
|
|
211
|
-
| `ziggs_list_my_agreements` | `GET /agreements?scope=mine` |
|
|
211
|
+
| `ziggs_list_my_agreements` | `GET /agreements?scope=mine&partyOnly=true` — agreements you are a party to; `scope: "reachable"` drops `partyOnly` for every agreement your grant can read |
|
|
212
212
|
| `ziggs_get_agreement` | `GET /agreements/:id` |
|
|
213
213
|
| `ziggs_list_chats` | `GET /chats/mine` |
|
|
214
214
|
| `ziggs_open_conversation` | `POST /chats` |
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type ZodRawShape } from 'zod';
|
|
3
|
+
import type { CapabilityDefinition, CapabilityParam, Creds } from '@ziggs-ai/api-client';
|
|
4
|
+
/** One JSON text-content result shape for every MCP tool (was copied 3×). */
|
|
5
|
+
export declare function textResult(data: unknown): {
|
|
6
|
+
content: {
|
|
7
|
+
type: "text";
|
|
8
|
+
text: string;
|
|
9
|
+
}[];
|
|
10
|
+
};
|
|
11
|
+
export declare function toZodShape(params: Record<string, CapabilityParam>): ZodRawShape;
|
|
12
|
+
export interface RegisterCapabilityOptions {
|
|
13
|
+
/** Web-app origin for human-facing URLs (claim links etc.). */
|
|
14
|
+
webUrl?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Description override for wording assembled from MCP-local shared consts
|
|
17
|
+
* (e.g. the delegate-protocol reporting rule, ZIG-557) — schema and handler
|
|
18
|
+
* still come from the shared definition.
|
|
19
|
+
*/
|
|
20
|
+
description?: string;
|
|
21
|
+
/** Surface-local response decoration (e.g. the read-plan on ziggs_read_context). */
|
|
22
|
+
transformResult?: (result: unknown, args: Record<string, unknown>) => unknown;
|
|
23
|
+
}
|
|
24
|
+
export declare function registerCapability(server: McpServer, cap: CapabilityDefinition, creds: Creds, opts?: RegisterCapabilityOptions): void;
|
|
25
|
+
export declare function registerCapabilities(server: McpServer, caps: CapabilityDefinition[], creds: Creds, opts?: RegisterCapabilityOptions): void;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { READ_ONLY, WRITE, DESTRUCTIVE } from './toolAnnotations.js';
|
|
3
|
+
import { toolError } from './toolError.js';
|
|
4
|
+
/** One JSON text-content result shape for every MCP tool (was copied 3×). */
|
|
5
|
+
export function textResult(data) {
|
|
6
|
+
return {
|
|
7
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* ZIG-956 — the MCP surface adapter for shared capability definitions
|
|
12
|
+
* (api-client `capabilities/`). Lowers the neutral param DSL to zod v3 (the
|
|
13
|
+
* MCP SDK's ZodRawShape; api-client itself carries no zod, and agent-sdk is on
|
|
14
|
+
* zod v4, so the schema is defined once and lowered per surface).
|
|
15
|
+
*/
|
|
16
|
+
function zodParam(param) {
|
|
17
|
+
let t;
|
|
18
|
+
switch (param.type) {
|
|
19
|
+
case 'string':
|
|
20
|
+
t = param.enum ? z.enum(param.enum) : z.string();
|
|
21
|
+
break;
|
|
22
|
+
case 'number':
|
|
23
|
+
t = z.number();
|
|
24
|
+
break;
|
|
25
|
+
case 'boolean':
|
|
26
|
+
t = z.boolean();
|
|
27
|
+
break;
|
|
28
|
+
case 'object':
|
|
29
|
+
t = z.record(z.unknown());
|
|
30
|
+
break;
|
|
31
|
+
case 'array': {
|
|
32
|
+
const items = param.items;
|
|
33
|
+
const inner = items?.type === 'string'
|
|
34
|
+
? items.enum
|
|
35
|
+
? z.enum(items.enum)
|
|
36
|
+
: z.string()
|
|
37
|
+
: z.record(z.unknown());
|
|
38
|
+
t = z.array(inner);
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (param.description)
|
|
43
|
+
t = t.describe(param.description);
|
|
44
|
+
if (!param.required)
|
|
45
|
+
t = t.optional();
|
|
46
|
+
return t;
|
|
47
|
+
}
|
|
48
|
+
export function toZodShape(params) {
|
|
49
|
+
const shape = {};
|
|
50
|
+
for (const [name, param] of Object.entries(params)) {
|
|
51
|
+
shape[name] = zodParam(param);
|
|
52
|
+
}
|
|
53
|
+
return shape;
|
|
54
|
+
}
|
|
55
|
+
export function registerCapability(server, cap, creds, opts = {}) {
|
|
56
|
+
const annotations = cap.annotation === 'read-only'
|
|
57
|
+
? READ_ONLY
|
|
58
|
+
: cap.annotation === 'destructive'
|
|
59
|
+
? DESTRUCTIVE
|
|
60
|
+
: WRITE;
|
|
61
|
+
server.tool(cap.names.mcp, opts.description ?? cap.descriptions.mcp, toZodShape(cap.params), annotations, async (args) => {
|
|
62
|
+
try {
|
|
63
|
+
const env = { creds, webUrl: opts.webUrl, surface: 'mcp' };
|
|
64
|
+
const result = await cap.handler(args, env);
|
|
65
|
+
return textResult(opts.transformResult ? opts.transformResult(result, args) : result);
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
return toolError(e.message);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export function registerCapabilities(server, caps, creds, opts = {}) {
|
|
73
|
+
for (const cap of caps)
|
|
74
|
+
registerCapability(server, cap, creds, opts);
|
|
75
|
+
}
|
package/dist/config.d.ts
CHANGED
|
@@ -12,6 +12,12 @@ declare const envSchema: z.ZodObject<{
|
|
|
12
12
|
ZIGGS_OWNER_USER_ID: z.ZodOptional<z.ZodString>;
|
|
13
13
|
/** Set to 1/true/yes to register internal/debug-only MCP tools (ZIG-672). */
|
|
14
14
|
ZIGGS_MCP_DEBUG: z.ZodOptional<z.ZodString>;
|
|
15
|
+
/**
|
|
16
|
+
* Set to 1/true/yes to register only the core everyday/session-start tools,
|
|
17
|
+
* skipping the heavy groups (payments, links, marketplace, connections) to
|
|
18
|
+
* cut cold-start deferred-loading (ZIG-941 #7). Unset = all tools register.
|
|
19
|
+
*/
|
|
20
|
+
ZIGGS_MCP_CORE_ONLY: z.ZodOptional<z.ZodString>;
|
|
15
21
|
}, "strip", z.ZodTypeAny, {
|
|
16
22
|
ZIGGS_OPERATOR_KEY: string;
|
|
17
23
|
ZIGGS_API_URL?: string | undefined;
|
|
@@ -20,6 +26,7 @@ declare const envSchema: z.ZodObject<{
|
|
|
20
26
|
ZIGGS_AGENT_ID?: string | undefined;
|
|
21
27
|
ZIGGS_OWNER_USER_ID?: string | undefined;
|
|
22
28
|
ZIGGS_MCP_DEBUG?: string | undefined;
|
|
29
|
+
ZIGGS_MCP_CORE_ONLY?: string | undefined;
|
|
23
30
|
}, {
|
|
24
31
|
ZIGGS_OPERATOR_KEY: string;
|
|
25
32
|
ZIGGS_API_URL?: string | undefined;
|
|
@@ -28,6 +35,7 @@ declare const envSchema: z.ZodObject<{
|
|
|
28
35
|
ZIGGS_AGENT_ID?: string | undefined;
|
|
29
36
|
ZIGGS_OWNER_USER_ID?: string | undefined;
|
|
30
37
|
ZIGGS_MCP_DEBUG?: string | undefined;
|
|
38
|
+
ZIGGS_MCP_CORE_ONLY?: string | undefined;
|
|
31
39
|
}>;
|
|
32
40
|
type EnvConfig = z.infer<typeof envSchema>;
|
|
33
41
|
export interface ZiggsMcpConfig extends EnvConfig {
|
|
@@ -35,6 +43,11 @@ export interface ZiggsMcpConfig extends EnvConfig {
|
|
|
35
43
|
resolvedAgentId: string;
|
|
36
44
|
/** When true, register internal/debug-only tools such as ziggs_smoke_impersonation. */
|
|
37
45
|
debugTools: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* When true, register only the core everyday/session-start tool tier and skip
|
|
48
|
+
* the heavy groups (payments, links, marketplace, connections) — ZIG-941 #7.
|
|
49
|
+
*/
|
|
50
|
+
coreOnly: boolean;
|
|
38
51
|
}
|
|
39
52
|
/** Load delegate credentials from the environment (ZIG-222 / ZIG-430). */
|
|
40
53
|
export declare function loadConfig(): ZiggsMcpConfig;
|
package/dist/config.js
CHANGED
|
@@ -13,8 +13,15 @@ const envSchema = z.object({
|
|
|
13
13
|
ZIGGS_OWNER_USER_ID: z.string().optional(),
|
|
14
14
|
/** Set to 1/true/yes to register internal/debug-only MCP tools (ZIG-672). */
|
|
15
15
|
ZIGGS_MCP_DEBUG: z.string().optional(),
|
|
16
|
+
/**
|
|
17
|
+
* Set to 1/true/yes to register only the core everyday/session-start tools,
|
|
18
|
+
* skipping the heavy groups (payments, links, marketplace, connections) to
|
|
19
|
+
* cut cold-start deferred-loading (ZIG-941 #7). Unset = all tools register.
|
|
20
|
+
*/
|
|
21
|
+
ZIGGS_MCP_CORE_ONLY: z.string().optional(),
|
|
16
22
|
});
|
|
17
|
-
|
|
23
|
+
/** Parse a truthy env flag (1/true/yes) — shared by ZIGGS_MCP_DEBUG and ZIGGS_MCP_CORE_ONLY. */
|
|
24
|
+
function parseBoolFlag(raw) {
|
|
18
25
|
if (!raw)
|
|
19
26
|
return false;
|
|
20
27
|
const v = raw.trim().toLowerCase();
|
|
@@ -30,6 +37,7 @@ export function loadConfig() {
|
|
|
30
37
|
ZIGGS_AGENT_ID: process.env.ZIGGS_AGENT_ID,
|
|
31
38
|
ZIGGS_OWNER_USER_ID: process.env.ZIGGS_OWNER_USER_ID,
|
|
32
39
|
ZIGGS_MCP_DEBUG: process.env.ZIGGS_MCP_DEBUG,
|
|
40
|
+
ZIGGS_MCP_CORE_ONLY: process.env.ZIGGS_MCP_CORE_ONLY,
|
|
33
41
|
};
|
|
34
42
|
const parsed = envSchema.safeParse(raw);
|
|
35
43
|
if (!parsed.success) {
|
|
@@ -49,6 +57,7 @@ export function loadConfig() {
|
|
|
49
57
|
return {
|
|
50
58
|
...parsed.data,
|
|
51
59
|
resolvedAgentId,
|
|
52
|
-
debugTools:
|
|
60
|
+
debugTools: parseBoolFlag(parsed.data.ZIGGS_MCP_DEBUG),
|
|
61
|
+
coreOnly: parseBoolFlag(parsed.data.ZIGGS_MCP_CORE_ONLY),
|
|
53
62
|
};
|
|
54
63
|
}
|
package/dist/connectionCreds.js
CHANGED
package/dist/paymentTools.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { type Creds } from '@ziggs-ai/api-client';
|
|
3
3
|
/**
|
|
4
|
-
* ZIG-896 — the wallet toolset on the MCP surface, same base names
|
|
5
|
-
* PAYMENT_TOOLS (payment_* → ziggs_payment_*),
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
4
|
+
* ZIG-896 / ZIG-956 — the wallet toolset on the MCP surface, same base names
|
|
5
|
+
* as the SDK's PAYMENT_TOOLS (payment_* → ziggs_payment_*), now registered
|
|
6
|
+
* from the shared capability definitions in api-client (one schema + handler,
|
|
7
|
+
* two thin surface adapters). Safety is unchanged: money-moving calls are
|
|
8
|
+
* policy-gated server-side (transfers above threshold return
|
|
9
|
+
* `approval_required`; the human decides on the wallet page — surfaced by
|
|
10
|
+
* ziggs_pending_decisions), and rails stay gated by the operator key's
|
|
11
|
+
* payments scopes. There is deliberately NO approve/decide tool on either
|
|
12
|
+
* agent surface — an agent must not approve its own spend.
|
|
12
13
|
*/
|
|
13
14
|
export declare function registerPaymentTools(server: McpServer, creds: Creds): void;
|
package/dist/paymentTools.js
CHANGED
|
@@ -1,252 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { READ_ONLY, WRITE, DESTRUCTIVE } from './toolAnnotations.js';
|
|
4
|
-
import { toolError } from './toolError.js';
|
|
5
|
-
function textResult(data) {
|
|
6
|
-
return {
|
|
7
|
-
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
function buildCaveats(args) {
|
|
11
|
-
const caveats = [];
|
|
12
|
-
if (args.maxAmount != null)
|
|
13
|
-
caveats.push({ type: 'max_amount', value: args.maxAmount });
|
|
14
|
-
if (args.dailyBudget != null)
|
|
15
|
-
caveats.push({ type: 'daily_budget', value: args.dailyBudget });
|
|
16
|
-
if (args.allowedRecipients != null)
|
|
17
|
-
caveats.push({ type: 'allowed_recipients', value: args.allowedRecipients });
|
|
18
|
-
if (args.expiresInSeconds != null)
|
|
19
|
-
caveats.push({ type: 'expires_at', value: Date.now() + args.expiresInSeconds * 1000 });
|
|
20
|
-
return caveats;
|
|
21
|
-
}
|
|
1
|
+
import { PAYMENT_CAPABILITIES } from '@ziggs-ai/api-client';
|
|
2
|
+
import { registerCapabilities } from './capabilityAdapter.js';
|
|
22
3
|
/**
|
|
23
|
-
* ZIG-896 — the wallet toolset on the MCP surface, same base names
|
|
24
|
-
* PAYMENT_TOOLS (payment_* → ziggs_payment_*),
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
4
|
+
* ZIG-896 / ZIG-956 — the wallet toolset on the MCP surface, same base names
|
|
5
|
+
* as the SDK's PAYMENT_TOOLS (payment_* → ziggs_payment_*), now registered
|
|
6
|
+
* from the shared capability definitions in api-client (one schema + handler,
|
|
7
|
+
* two thin surface adapters). Safety is unchanged: money-moving calls are
|
|
8
|
+
* policy-gated server-side (transfers above threshold return
|
|
9
|
+
* `approval_required`; the human decides on the wallet page — surfaced by
|
|
10
|
+
* ziggs_pending_decisions), and rails stay gated by the operator key's
|
|
11
|
+
* payments scopes. There is deliberately NO approve/decide tool on either
|
|
12
|
+
* agent surface — an agent must not approve its own spend.
|
|
31
13
|
*/
|
|
32
14
|
export function registerPaymentTools(server, creds) {
|
|
33
|
-
|
|
34
|
-
server.tool('ziggs_payment_balance', "Check the caller's current wallet balance and available balance (total minus active holds). Use before a transfer to confirm sufficient funds.", {}, READ_ONLY, async () => {
|
|
35
|
-
try {
|
|
36
|
-
return textResult(await client().balance());
|
|
37
|
-
}
|
|
38
|
-
catch (e) {
|
|
39
|
-
return toolError(e.message);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
server.tool('ziggs_payment_resolve_wallet', 'Look up a walletId by userId or agentId. Use before a transfer when you only know the recipient by their platform ID.', {
|
|
43
|
-
userId: z.string().optional().describe('User to resolve'),
|
|
44
|
-
agentId: z.string().optional().describe('Agent to resolve'),
|
|
45
|
-
}, READ_ONLY, async ({ userId, agentId }) => {
|
|
46
|
-
if (!userId && !agentId) {
|
|
47
|
-
return toolError('Provide userId or agentId to resolve a wallet');
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
const wallet = (await client().resolve({ userId, agentId }));
|
|
51
|
-
return textResult({
|
|
52
|
-
walletId: wallet?.['walletId'] || null,
|
|
53
|
-
ownerId: wallet?.['ownerId'] || null,
|
|
54
|
-
currency: wallet?.['currency'] || 'pez',
|
|
55
|
-
status: wallet?.['status'] || null,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
catch (e) {
|
|
59
|
-
return toolError(e.message);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
server.tool('ziggs_payment_transfer', 'Transfer funds to another wallet. Amounts are integer cents. As a delegate you spend under a payment grant the wallet owner issued (paymentGrantId — find yours via ziggs_list_grants scopeKind=wallet). Transfers above the owner\'s policy pause with status "approval_required": the human approves on the wallet page (it also shows in ziggs_pending_decisions) — you can wait inline with ziggs_payment_wait_for_approval, and you must NEVER approve your own transfer.', {
|
|
63
|
-
toWalletId: z
|
|
64
|
-
.string()
|
|
65
|
-
.describe('Destination wal_... id — or a userId/agentId to auto-resolve'),
|
|
66
|
-
amount: z.number().describe('Amount in integer cents, > 0'),
|
|
67
|
-
description: z.string().optional().describe('Human-readable transfer memo'),
|
|
68
|
-
idempotencyKey: z
|
|
69
|
-
.string()
|
|
70
|
-
.optional()
|
|
71
|
-
.describe('Client-supplied key to make retries safe (auto-generated when omitted)'),
|
|
72
|
-
paymentGrantId: z
|
|
73
|
-
.string()
|
|
74
|
-
.optional()
|
|
75
|
-
.describe('Payment grant to spend under (required for agent-impersonated transfers)'),
|
|
76
|
-
}, WRITE, async ({ toWalletId, amount, description, idempotencyKey, paymentGrantId }) => {
|
|
77
|
-
if (!amount || amount <= 0)
|
|
78
|
-
return toolError('amount must be positive');
|
|
79
|
-
try {
|
|
80
|
-
const result = (await client().transfer({
|
|
81
|
-
to: toWalletId,
|
|
82
|
-
amount: Math.round(amount),
|
|
83
|
-
description: description || 'Agent-initiated transfer',
|
|
84
|
-
idempotencyKey,
|
|
85
|
-
paymentGrantId,
|
|
86
|
-
}));
|
|
87
|
-
if (result['status'] === 'approval_required') {
|
|
88
|
-
return textResult({
|
|
89
|
-
status: 'approval_required',
|
|
90
|
-
approvalId: result['approvalId'] || null,
|
|
91
|
-
expiresAt: result['expiresAt'] || null,
|
|
92
|
-
reason: result['reason'] || null,
|
|
93
|
-
amount,
|
|
94
|
-
toWalletId: result['toWalletId'],
|
|
95
|
-
note: 'Transfer paused: the wallet owner must approve this amount on the wallet page (also listed by ziggs_pending_decisions). Tell the human now (pull-only MCP has no push). ' +
|
|
96
|
-
'Wait inline with ziggs_payment_wait_for_approval when you expect a quick decision (≤2 min).',
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
return textResult({
|
|
100
|
-
status: 'transferred',
|
|
101
|
-
transactionId: result['transactionId'] || null,
|
|
102
|
-
amount,
|
|
103
|
-
toWalletId: result['toWalletId'],
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
catch (e) {
|
|
107
|
-
return toolError(e.message);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
server.tool('ziggs_payment_wait_for_approval', 'Poll a paused transfer (status "approval_required") until the human decides or the timeout passes. Returns executed | rejected | expired | timeout | gone. Use for quick decisions (≤2 min); for longer waits, stop and check again next session.', {
|
|
111
|
-
approvalId: z.string().describe('Approval to wait on (from ziggs_payment_transfer)'),
|
|
112
|
-
timeoutMs: z.number().optional().describe('Max wait, default 120000'),
|
|
113
|
-
pollMs: z.number().optional().describe('Poll interval, default 3000 (min 500)'),
|
|
114
|
-
}, READ_ONLY, async ({ approvalId, timeoutMs, pollMs }) => {
|
|
115
|
-
try {
|
|
116
|
-
const result = (await client().waitForApproval(approvalId, {
|
|
117
|
-
timeoutMs,
|
|
118
|
-
pollMs,
|
|
119
|
-
}));
|
|
120
|
-
return textResult({
|
|
121
|
-
status: result['status'],
|
|
122
|
-
approvalId,
|
|
123
|
-
transactionId: result['transactionId'] || null,
|
|
124
|
-
approval: result['approval'] || null,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
catch (e) {
|
|
128
|
-
return toolError(e.message);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
server.tool('ziggs_payment_hold', "Pre-authorize (escrow) funds without moving them. Use to reserve payment at agreement formation; release with ziggs_payment_release once work is complete, or refund if it's cancelled.", {
|
|
132
|
-
amount: z.number().describe('Amount in integer cents, > 0'),
|
|
133
|
-
description: z.string().optional().describe('Human-readable hold memo'),
|
|
134
|
-
idempotencyKey: z.string().optional().describe('Client-supplied retry-safety key'),
|
|
135
|
-
}, WRITE, async ({ amount, description, idempotencyKey }) => {
|
|
136
|
-
if (!amount || amount <= 0)
|
|
137
|
-
return toolError('amount must be positive');
|
|
138
|
-
try {
|
|
139
|
-
const result = (await client().hold({
|
|
140
|
-
amount: Math.round(amount),
|
|
141
|
-
description: description || 'Agent escrow hold',
|
|
142
|
-
idempotencyKey,
|
|
143
|
-
}));
|
|
144
|
-
return textResult({
|
|
145
|
-
status: 'held',
|
|
146
|
-
transactionId: result['transaction']?.['transactionId'] || null,
|
|
147
|
-
amount,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
catch (e) {
|
|
151
|
-
return toolError(e.message);
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
server.tool('ziggs_payment_release', "Settle or refund an escrow hold. action='complete' transfers held funds to toWalletId (work done); action='refund' returns funds to the sender (work cancelled).", {
|
|
155
|
-
holdId: z.string().describe('Hold to settle (transactionId from ziggs_payment_hold)'),
|
|
156
|
-
action: z.enum(['complete', 'refund']).describe('complete = pay out, refund = return'),
|
|
157
|
-
toWalletId: z
|
|
158
|
-
.string()
|
|
159
|
-
.optional()
|
|
160
|
-
.describe('Destination wallet — required when action=complete'),
|
|
161
|
-
idempotencyKey: z.string().optional().describe('Client-supplied retry-safety key'),
|
|
162
|
-
}, WRITE, async ({ holdId, action, toWalletId, idempotencyKey }) => {
|
|
163
|
-
if (action === 'complete' && !toWalletId) {
|
|
164
|
-
return toolError('toWalletId is required when action=complete');
|
|
165
|
-
}
|
|
166
|
-
try {
|
|
167
|
-
const result = (await client().release({
|
|
168
|
-
holdId,
|
|
169
|
-
action,
|
|
170
|
-
toWalletId,
|
|
171
|
-
idempotencyKey,
|
|
172
|
-
}));
|
|
173
|
-
return textResult({
|
|
174
|
-
status: action === 'complete' ? 'settled' : 'refunded',
|
|
175
|
-
transactionId: result['transaction']?.['transactionId'] || null,
|
|
176
|
-
holdId,
|
|
177
|
-
action,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
catch (e) {
|
|
181
|
-
return toolError(e.message);
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
const grantCaveatArgs = {
|
|
185
|
-
maxAmount: z.number().optional().describe('Per-transfer ceiling in cents'),
|
|
186
|
-
dailyBudget: z.number().optional().describe('Rolling daily budget in cents'),
|
|
187
|
-
allowedRecipients: z
|
|
188
|
-
.array(z.string())
|
|
189
|
-
.optional()
|
|
190
|
-
.describe('Wallet ids the holder may pay'),
|
|
191
|
-
expiresInSeconds: z.number().optional().describe('Grant lifetime from now'),
|
|
192
|
-
};
|
|
193
|
-
server.tool('ziggs_payment_issue_grant', "Issue a payment grant delegating bounded spend from the operator's wallet to an agent holder. Caveats bound what the holder can do (max_amount, daily_budget, allowed_recipients, expiry). The holder spends by passing the grantId as paymentGrantId on transfers.", {
|
|
194
|
-
holderId: z.string().describe('Agent that will hold the grant'),
|
|
195
|
-
...grantCaveatArgs,
|
|
196
|
-
}, WRITE, async ({ holderId, ...caveatArgs }) => {
|
|
197
|
-
try {
|
|
198
|
-
const caveats = buildCaveats(caveatArgs);
|
|
199
|
-
const result = (await client().issueGrant({ holderId, caveats }));
|
|
200
|
-
const grant = result['grant'];
|
|
201
|
-
return textResult({
|
|
202
|
-
grantId: grant?.['grantId'] || null,
|
|
203
|
-
holderId: grant?.['holderId'] || holderId,
|
|
204
|
-
caveats: grant?.['caveats'] || caveats,
|
|
205
|
-
expiresAt: grant?.['expiresAt'] || null,
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
catch (e) {
|
|
209
|
-
return toolError(e.message);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
server.tool('ziggs_payment_attenuate_grant', 'Re-delegate a payment grant you hold to another agent with TIGHTER caveats (narrowing only — the child can never exceed the parent). Use to pass a bounded spend slice to a sub-agent.', {
|
|
213
|
-
grantId: z.string().describe('Parent grant to attenuate'),
|
|
214
|
-
holderId: z.string().describe('Agent that will hold the narrowed grant'),
|
|
215
|
-
...grantCaveatArgs,
|
|
216
|
-
}, WRITE, async ({ grantId, holderId, ...caveatArgs }) => {
|
|
217
|
-
try {
|
|
218
|
-
const caveats = buildCaveats(caveatArgs);
|
|
219
|
-
const result = (await client().attenuateGrant({
|
|
220
|
-
grantId,
|
|
221
|
-
holderId,
|
|
222
|
-
caveats,
|
|
223
|
-
}));
|
|
224
|
-
const grant = result['grant'];
|
|
225
|
-
return textResult({
|
|
226
|
-
grantId: grant?.['grantId'] || null,
|
|
227
|
-
parentGrantId: grant?.['parentGrantId'] || grantId,
|
|
228
|
-
holderId: grant?.['holderId'] || holderId,
|
|
229
|
-
caveats: grant?.['caveats'] || caveats,
|
|
230
|
-
expiresAt: grant?.['expiresAt'] || null,
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
catch (e) {
|
|
234
|
-
return toolError(e.message);
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
server.tool('ziggs_payment_revoke_grant', 'Revoke a payment grant (and its attenuated children). The holder can no longer spend under it.', {
|
|
238
|
-
grantId: z.string().describe('Grant to revoke'),
|
|
239
|
-
}, DESTRUCTIVE, async ({ grantId }) => {
|
|
240
|
-
try {
|
|
241
|
-
const result = (await client().revokeGrant(grantId));
|
|
242
|
-
return textResult({
|
|
243
|
-
status: 'revoked',
|
|
244
|
-
grantId,
|
|
245
|
-
revoked: result?.['revoked'] ?? null,
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
catch (e) {
|
|
249
|
-
return toolError(e.message);
|
|
250
|
-
}
|
|
251
|
-
});
|
|
15
|
+
registerCapabilities(server, PAYMENT_CAPABILITIES, creds);
|
|
252
16
|
}
|