@ziggs-ai/ziggs-mcp 0.6.0 → 0.6.2

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.
@@ -73,14 +73,29 @@ function proposalToItem(p, origin) {
73
73
  sayReject: `reject ${id}`,
74
74
  };
75
75
  }
76
+ function linkRequesterHeadline(c) {
77
+ // ZIG-1039: consent cards lead with a readable name + org, id as fallback.
78
+ const name = c.requesterDisplayName?.trim();
79
+ const org = c.requesterOrgName?.trim();
80
+ if (name && org)
81
+ return `${name} (${org})`;
82
+ if (name)
83
+ return name;
84
+ return c.requesterAgentId;
85
+ }
76
86
  function linkToItem(c, origin) {
77
87
  const id = c.requestId;
78
88
  const note = c.message?.trim() || null;
89
+ const headline = linkRequesterHeadline(c);
79
90
  return {
80
91
  kind: 'link_request',
81
92
  agreementId: id,
82
- title: truncateText(`Agent link · ${c.requesterAgentId}`),
83
- subtitle: note ? truncateText(note, 96) : null,
93
+ title: truncateText(`Agent link · ${headline}`),
94
+ subtitle: note
95
+ ? truncateText(note, 96)
96
+ : c.requesterAgentId && headline !== c.requesterAgentId
97
+ ? truncateText(`id: ${c.requesterAgentId}`, 96)
98
+ : null,
84
99
  proposedAt: c.requestedAt,
85
100
  proposedAtLabel: formatWhen(c.requestedAt),
86
101
  appUrl: agreementAppUrl(origin, id),
package/dist/tools.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from 'node:crypto';
2
2
  import { z } from 'zod';
3
- import { getAgreement, getMyAgreements, listMyChats, proposeUnified, delegateAgreement, provisionRelayWorkers, respondToAgreement, revokeAgreement, counterAgreement, fulfillAgreement, sendChatMessage, ConnectionsClient, PaymentsClient, ContextReadClient, GrantsClient, InboxClient, createTask, updateTaskState, replaceTaskPlan, listTasks, getTask, getBackendUrl, fetchMyOrgs, fetchDelegateAccess, GRANTS_CAPABILITIES, contextReadCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, recordArtifactCapability, openConversationCapability, connectionProxyCapability, requestConnectionCapability, agreementClaimCapability, marketplaceViewCapability, } from '@ziggs-ai/api-client';
3
+ import { getAgreement, getMyAgreements, listMyChats, proposeUnified, delegateAgreement, provisionRelayWorkers, respondToAgreement, revokeAgreement, counterAgreement, fulfillAgreement, sendChatMessage, ConnectionsClient, PaymentsClient, ContextReadClient, GrantsClient, InboxClient, createTask, updateTaskState, replaceTaskPlan, listTasks, getTask, getBackendUrl, fetchMyOrgs, fetchDelegateAccess, GRANTS_CAPABILITIES, contextReadCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, recordArtifactCapability, openConversationCapability, connectionProxyCapability, requestConnectionCapability, agreementClaimCapability, marketplaceViewCapability, linkSummary, } from '@ziggs-ai/api-client';
4
4
  import { decodeOperatorKeyClaims } from './operatorKey.js';
5
5
  import { registerTrustTools } from './trustTools.js';
6
6
  import { registerPaymentTools } from './paymentTools.js';
@@ -395,7 +395,7 @@ export function registerZiggsTools(server, creds, cfg) {
395
395
  return toolError(e.message);
396
396
  }
397
397
  });
398
- server.tool('ziggs_agreement_propose', 'Propose an agreement — direct, broadcast, or link; there are no separate publish tools. DIRECT: proposedTo = one counterparty id, chatId required. Omit providerId (or set it to proposedTo) to commission the recipient (they work, your side pays); set providerId to your own agent id to offer (you work, proposedTo pays); a third-party providerId brokers (they work, proposedTo pays) and requires that provider to have a matching active offer. BROADCAST: proposedTo "everyone" (fully public) or "org" (your active org only), chatId optional — with no providerId this publishes a QUEST (whoever claims does the work, your side pays); with providerId = your own id it publishes a STANDING OFFER (you work, the claimer pays). Claiming is ziggs_agreement_claim; browsing is ziggs_marketplace_view. LINK: engagementKind "link" with proposedTo = an agent id proposes bilateral trust (no chat, no money; the target owner approves via ziggs_agreement_respond). The payer is always derived server-side as the non-providing side — there is no payer input. engagementKind "service" (default) = one deliverable; "hire" = ongoing engagement. Agreements are STANDING by default (lifecycle "open": no expiry, unlimited tasks) — hire once, then keep spawning tasks under the same agreement; set expiresAt (time-bound) or maxExecutions (count-bound) only when the engagement should end on its own. price is recorded on the agreement but does not itself trigger a transfer.', {
398
+ server.tool('ziggs_agreement_propose', 'Propose an agreement — direct, broadcast, or link; there are no separate publish tools. DIRECT: proposedTo = one counterparty id, chatId required. Omit providerId (or set it to proposedTo) to commission the recipient (they work, your side pays); set providerId to your own agent id to offer (you work, proposedTo pays); a third-party providerId brokers (they work, proposedTo pays) and requires that provider to have a matching active offer. BROADCAST: proposedTo "everyone" (fully public) or "org" (your active org only), chatId optional — with no providerId this publishes a QUEST (whoever claims does the work, your side pays); with providerId = your own id it publishes a STANDING OFFER (you work, the claimer pays). Claiming is ziggs_agreement_claim; browsing is ziggs_marketplace_view. LINK: engagementKind "link" with proposedTo = an agent id proposes bilateral trust (no chat, no money). The server routes parties.proposedTo to that agent\'s owner human (a person decides who their delegate trusts) — the id you pass may differ from parties.proposedTo in the response; when it does, `note` explains the rewrite. Approve via ziggs_agreement_respond. The payer is always derived server-side as the non-providing side — there is no payer input. engagementKind "service" (default) = one deliverable; "hire" = ongoing engagement. Agreements are STANDING by default (lifecycle "open": no expiry, unlimited tasks) — hire once, then keep spawning tasks under the same agreement; set expiresAt (time-bound) or maxExecutions (count-bound) only when the engagement should end on its own. price is recorded on the agreement but does not itself trigger a transfer.', {
399
399
  proposedTo: z
400
400
  .string()
401
401
  .describe('Counterparty id for a direct proposal, or "everyone"/"org" to broadcast'),
@@ -408,7 +408,11 @@ export function registerZiggsTools(server, creds, cfg) {
408
408
  .string()
409
409
  .optional()
410
410
  .describe('Who does the work. Direct: omitted = proposedTo (commission), your id = offer, another id = broker. Broadcast: omitted = quest, your id = standing offer.'),
411
- price: z.number().optional().describe('Optional; does not trigger transfer by itself'),
411
+ price: z
412
+ .number()
413
+ .optional()
414
+ .describe('Amount in CENTS — 500 means $5.00. Optional; does not trigger a transfer by itself. ' +
415
+ 'When you quote it to a human, convert: saying "$500" for 500 is off by 100x.'),
412
416
  engagementKind: z
413
417
  .enum(['hire', 'service', 'link'])
414
418
  .optional()
@@ -445,9 +449,20 @@ export function registerZiggsTools(server, creds, cfg) {
445
449
  lifecycle,
446
450
  billing,
447
451
  }, creds);
452
+ // ZIG-957: link mutations return linkSummary, not the raw Mongo doc.
453
+ const agreementOut = shape === 'link' && agreement ? linkSummary(agreement) : agreement;
454
+ // ZIG-1039: surface the owner-routing rewrite so agents do not think
455
+ // the id they passed was ignored silently.
456
+ const routedProposedTo = shape === 'link' &&
457
+ agreement?.parties?.proposedTo &&
458
+ proposedTo &&
459
+ proposedTo !== agreement.parties.proposedTo
460
+ ? `Routed approval to the target agent's owner (${agreement.parties.proposedTo}): a person decides who their delegate trusts. You passed proposedTo=${proposedTo}.`
461
+ : undefined;
448
462
  return textResult({
449
463
  shape,
450
- agreement,
464
+ agreement: agreementOut,
465
+ ...(routedProposedTo ? { note: routedProposedTo } : {}),
451
466
  ...(shape === 'quest' || shape === 'offer'
452
467
  ? {
453
468
  nextSteps: 'Published to the marketplace — claimable via ziggs_agreement_claim; it also appears in ziggs_marketplace_view.',
@@ -466,10 +481,16 @@ export function registerZiggsTools(server, creds, cfg) {
466
481
  chatId: z.string().describe('Chat the delegation is coordinated in'),
467
482
  description: z.string().describe('What the sub-agreement covers'),
468
483
  parentTaskId: z.string().optional(),
469
- price: z.number().optional(),
484
+ price: z
485
+ .number()
486
+ .optional()
487
+ .describe('Amount in CENTS — 500 means $5.00.'),
470
488
  expiresAt: z.string().optional(),
471
489
  maxExecutions: z.number().int().positive().optional(),
472
- lifecycle: z.string().optional(),
490
+ lifecycle: z
491
+ .enum(['open', 'time-bound', 'count-bound'])
492
+ .optional()
493
+ .describe("Usually inferred: expiresAt → 'time-bound', maxExecutions → 'count-bound', neither → 'open' (standing)."),
473
494
  agreementDescription: z.string().optional(),
474
495
  }, WRITE, async ({ parentAgreementId, executorId, chatId, description, parentTaskId, price, expiresAt, maxExecutions, lifecycle, agreementDescription, }) => {
475
496
  try {
@@ -504,7 +525,9 @@ export function registerZiggsTools(server, creds, cfg) {
504
525
  const updated = await respondToAgreement(agreementId, action, creds, {
505
526
  ownerUserId: ownerId,
506
527
  });
507
- return textResult({ agreement: updated });
528
+ // ZIG-957: link approvals/rejects share the same summary shape as claim/revoke.
529
+ const agreement = updated?.engagementKind === 'link' ? linkSummary(updated) : updated;
530
+ return textResult({ agreement });
508
531
  }
509
532
  catch (e) {
510
533
  return toolError(e.message);
@@ -516,13 +539,17 @@ export function registerZiggsTools(server, creds, cfg) {
516
539
  try {
517
540
  const result = await revokeAgreement(agreementId, creds);
518
541
  const isLink = result.agreement?.engagementKind === 'link';
542
+ // ZIG-957: same summary shape as create/list/claim link tools (not the raw Mongo doc).
543
+ const agreement = result.agreement
544
+ ? (isLink ? linkSummary(result.agreement) : result.agreement)
545
+ : undefined;
519
546
  return textResult({
520
547
  status: 'revoked',
521
548
  agreementId,
522
549
  ...(isLink
523
550
  ? { note: 'Link revoked — unpublished cross-org reach to this peer is blocked again.' }
524
551
  : {}),
525
- agreement: result.agreement,
552
+ agreement,
526
553
  });
527
554
  }
528
555
  catch (e) {
@@ -537,8 +564,11 @@ export function registerZiggsTools(server, creds, cfg) {
537
564
  .optional()
538
565
  .describe('Revised agreement description / terms'),
539
566
  expiresAt: z.string().optional().describe('Revised expiry (ISO-8601)'),
540
- lifecycle: z.string().optional().describe('Revised lifecycle'),
541
- maxExecutions: z.number().optional().describe('Revised max executions'),
567
+ lifecycle: z
568
+ .enum(['open', 'time-bound', 'count-bound'])
569
+ .optional()
570
+ .describe('Revised lifecycle: open | time-bound | count-bound'),
571
+ maxExecutions: z.number().int().positive().optional().describe('Revised max executions'),
542
572
  description: z
543
573
  .string()
544
574
  .optional()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/ziggs-mcp",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "MCP server for Claude Code, Cursor, and other MCP hosts — act as your Ziggs delegate agent",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@modelcontextprotocol/sdk": "^1.29.0",
39
- "@ziggs-ai/api-client": "^0.6.0",
39
+ "@ziggs-ai/api-client": "^0.6.1",
40
40
  "dotenv": "^16.6.1",
41
41
  "zod": "^3.24.2"
42
42
  },