@ziggs-ai/ziggs-mcp 0.1.33 → 0.1.34
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/inboxToolResult.d.ts +3 -3
- package/dist/inboxToolResult.js +12 -10
- package/dist/tools.js +74 -92
- package/dist/trustTools.js +4 -4
- package/package.json +2 -2
- package/skills/ziggs/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -194,7 +194,7 @@ OP_KEY_A=... AGENT_A=... USER_B=... OP_KEY_B=... AGENT_B=... \
|
|
|
194
194
|
| Tool | Maps to |
|
|
195
195
|
|------|---------|
|
|
196
196
|
| `ziggs_inbox` | `GET /inbox` + `POST /inbox/ack` |
|
|
197
|
-
| `ziggs_discover_context` | `GET /
|
|
197
|
+
| `ziggs_discover_context` | `GET /grants` (context scopes) |
|
|
198
198
|
| `ziggs_read_context` | `GET /context/read/:type` |
|
|
199
199
|
| `ziggs_record_artifact` | `POST /artifacts` |
|
|
200
200
|
| `ziggs_search_agents` | Agent search |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { GrantView, ContextReadType, InboxAckResult, InboxEnvelope, Task } from '@ziggs-ai/api-client';
|
|
2
2
|
/**
|
|
3
3
|
* ZIG-634 (Step 1): a pre-filled next call. The agent can run it verbatim
|
|
4
4
|
* instead of assembling args from the ids scattered through the response.
|
|
@@ -64,7 +64,7 @@ export interface ScopeGrantTag {
|
|
|
64
64
|
* list is already the caller's non-expired grants (holderId == principalId),
|
|
65
65
|
* so this is grant metadata the caller already holds — no protected content.
|
|
66
66
|
*/
|
|
67
|
-
export declare function indexReachByScope(reach:
|
|
67
|
+
export declare function indexReachByScope(reach: GrantView[]): Map<string, ScopeGrantTag>;
|
|
68
68
|
/**
|
|
69
69
|
* Put humanAttention first so MCP hosts surface it before counts (ZIG-482),
|
|
70
70
|
* and append readPlan last so each inbox call self-narrates the follow-up
|
|
@@ -73,4 +73,4 @@ export declare function indexReachByScope(reach: ContextReachDescriptor[]): Map<
|
|
|
73
73
|
* When `reach` (the caller's own live grants) is passed, each scope is tagged
|
|
74
74
|
* with its covering grant (ZIG-635) so the agent can pin X-Context-Grant-Id.
|
|
75
75
|
*/
|
|
76
|
-
export declare function formatInboxToolResult(inbox: InboxEnvelope, ack?: InboxAckResult | null, webOrigin?: string, activeTasks?: Task[], reach?:
|
|
76
|
+
export declare function formatInboxToolResult(inbox: InboxEnvelope, ack?: InboxAckResult | null, webOrigin?: string, activeTasks?: Task[], reach?: GrantView[], activeTasksError?: string): Record<string, unknown>;
|
package/dist/inboxToolResult.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { grantCaveat } from '@ziggs-ai/api-client';
|
|
1
2
|
import { formatPendingDecisionsPayload, resolveWebAppOrigin, } from './pendingDecisions.js';
|
|
2
3
|
/** Keep the plan bounded; the full scopes array still carries everything. */
|
|
3
4
|
const MAX_READ_PLAN = 12;
|
|
@@ -147,13 +148,14 @@ export function buildReadContextReadPlan(page, type, via, presentedGrantId) {
|
|
|
147
148
|
}
|
|
148
149
|
return plan;
|
|
149
150
|
}
|
|
150
|
-
function toScopeGrantTag(
|
|
151
|
+
function toScopeGrantTag(g) {
|
|
151
152
|
return {
|
|
152
|
-
grantId:
|
|
153
|
-
temporal
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
grantId: g.grantId,
|
|
154
|
+
// Context grants carry temporal/watermark as caveats (ZIG-646).
|
|
155
|
+
temporal: grantCaveat(g, 'temporal') ?? 'from-now',
|
|
156
|
+
watermarkAt: grantCaveat(g, 'watermark_at') ?? '',
|
|
157
|
+
expiresAt: g.expiresAt,
|
|
158
|
+
parentGrantId: g.parentGrantId,
|
|
157
159
|
};
|
|
158
160
|
}
|
|
159
161
|
/**
|
|
@@ -173,11 +175,11 @@ function isBroaderGrant(a, b) {
|
|
|
173
175
|
*/
|
|
174
176
|
export function indexReachByScope(reach) {
|
|
175
177
|
const byScope = new Map();
|
|
176
|
-
for (const
|
|
177
|
-
if (!
|
|
178
|
+
for (const g of reach) {
|
|
179
|
+
if (!g?.scope)
|
|
178
180
|
continue;
|
|
179
|
-
const key = `${
|
|
180
|
-
const tag = toScopeGrantTag(
|
|
181
|
+
const key = `${g.scope.kind}:${g.scope.id}`;
|
|
182
|
+
const tag = toScopeGrantTag(g);
|
|
181
183
|
const existing = byScope.get(key);
|
|
182
184
|
if (!existing || isBroaderGrant(tag, existing))
|
|
183
185
|
byScope.set(key, tag);
|
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, openConversation, proposeDirectTo, proposeBroadcast, publishOffer, claimOffer, provisionRelayWorkers, respondToAgreement, revokeAgreement, sendChatMessage, ContextDiscoveryClient, ContextReadClient, InboxClient, createTask, updateTaskState, replaceTaskPlan, listTasks, getBackendUrl, } from '@ziggs-ai/api-client';
|
|
3
|
+
import { getAgreement, getMyAgreements, listMyChats, openConversation, proposeDirectTo, proposeBroadcast, publishOffer, claimOffer, provisionRelayWorkers, respondToAgreement, revokeAgreement, sendChatMessage, ContextDiscoveryClient, ContextReadClient, GrantsClient, InboxClient, createTask, updateTaskState, replaceTaskPlan, listTasks, getBackendUrl, } from '@ziggs-ai/api-client';
|
|
4
4
|
import { decodeOperatorKeyClaims } from './operatorKey.js';
|
|
5
5
|
import { registerTrustTools } from './trustTools.js';
|
|
6
6
|
import { formatInboxToolResult, buildReadContextReadPlan, } from './inboxToolResult.js';
|
|
@@ -146,24 +146,6 @@ async function proxyConnection(creds, input) {
|
|
|
146
146
|
const result = parsed?.['result'];
|
|
147
147
|
return result ?? parsed;
|
|
148
148
|
}
|
|
149
|
-
/** ZIG-640 — server-side org rebind; existing OAuth Bearer keeps working. */
|
|
150
|
-
async function rebindDelegateOrg(creds, orgId) {
|
|
151
|
-
const url = `${getBackendUrl()}/agents/claude-delegate/rebind`;
|
|
152
|
-
const res = await fetch(url, {
|
|
153
|
-
method: 'POST',
|
|
154
|
-
headers: {
|
|
155
|
-
'content-type': 'application/json',
|
|
156
|
-
Authorization: `Bearer ${creds.operatorKey}`,
|
|
157
|
-
'X-Agent-Id': creds.agentId,
|
|
158
|
-
},
|
|
159
|
-
body: JSON.stringify({ orgId }),
|
|
160
|
-
});
|
|
161
|
-
const body = await res.text().catch(() => '');
|
|
162
|
-
if (!res.ok) {
|
|
163
|
-
throw new Error(`POST /agents/claude-delegate/rebind ${res.status} ${body.slice(0, 200)}`);
|
|
164
|
-
}
|
|
165
|
-
return body ? JSON.parse(body) : {};
|
|
166
|
-
}
|
|
167
149
|
/** ZIG-640 — runtime acting org from server (self-hire / agent row). */
|
|
168
150
|
async function fetchDelegateAccess(creds) {
|
|
169
151
|
const url = `${getBackendUrl()}/agents/claude-delegate/access`;
|
|
@@ -224,35 +206,32 @@ function resolveOrgSelector(orgs, selector) {
|
|
|
224
206
|
return { status: 'not-found' };
|
|
225
207
|
}
|
|
226
208
|
/**
|
|
227
|
-
* ZIG-641 — cross-connection discovery
|
|
228
|
-
* grant
|
|
229
|
-
* connectionId/grantId no longer has to arrive out of
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
* with proxyConnection.
|
|
209
|
+
* ZIG-641 / ZIG-648 — cross-connection discovery over the unified GET /grants:
|
|
210
|
+
* every connection grant this agent holds, grouped by connection so
|
|
211
|
+
* ziggs_connection_proxy's connectionId/grantId no longer has to arrive out of
|
|
212
|
+
* band. `provider` comes from the grant's resolved scope label. The response is
|
|
213
|
+
* scanned defensively for leaked secrets, as proxyConnection does.
|
|
233
214
|
*/
|
|
234
215
|
async function listConnectionsForHolder(creds) {
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
'X-Agent-Id': creds.agentId,
|
|
241
|
-
},
|
|
216
|
+
const client = new GrantsClient(creds.operatorKey, creds.agentId);
|
|
217
|
+
// All pages of the agent's live connection grants (not just the first page).
|
|
218
|
+
const items = await client.listAllGrants({
|
|
219
|
+
scopeKind: 'connection',
|
|
220
|
+
health: 'active',
|
|
242
221
|
});
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
catch {
|
|
253
|
-
parsed = body;
|
|
222
|
+
const byConnection = new Map();
|
|
223
|
+
for (const g of items) {
|
|
224
|
+
const connectionId = g.scope.id;
|
|
225
|
+
let group = byConnection.get(connectionId);
|
|
226
|
+
if (!group) {
|
|
227
|
+
group = { connectionId, provider: g.scope.label ?? null, grants: [] };
|
|
228
|
+
byConnection.set(connectionId, group);
|
|
229
|
+
}
|
|
230
|
+
group.grants.push(g);
|
|
254
231
|
}
|
|
255
|
-
|
|
232
|
+
const result = [...byConnection.values()];
|
|
233
|
+
assertNoLeakedSecret(JSON.stringify(result));
|
|
234
|
+
return result;
|
|
256
235
|
}
|
|
257
236
|
/**
|
|
258
237
|
* ZIG-686 — agent-initiated MCP connection request: ask the principal to
|
|
@@ -378,9 +357,9 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
378
357
|
? 'Not connected — complete MCP OAuth consent first, then re-check actingOrgId here.'
|
|
379
358
|
: actingOrgName
|
|
380
359
|
? `This MCP session acts in **${actingOrgName}** (${actingOrgId}). Runtime org comes from server-side delegate + self-hire — not the OAuth JWT.`
|
|
381
|
-
: 'Connected but could not resolve acting org name —
|
|
360
|
+
: 'Connected but could not resolve acting org name — reconnect MCP OAuth if needed.',
|
|
382
361
|
switchOrgHint: switchOrgHint ??
|
|
383
|
-
'
|
|
362
|
+
'Org is fixed at OAuth consent. Reconnect MCP OAuth and pick the target org on the consent screen to act elsewhere.',
|
|
384
363
|
apiBase: getBackendUrl(),
|
|
385
364
|
webAppOrigin: webOrigin,
|
|
386
365
|
docs: 'https://ziggsai.com/docs',
|
|
@@ -390,7 +369,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
390
369
|
: 'Next: ziggs_inbox or ziggs_pending_decisions at session start.',
|
|
391
370
|
});
|
|
392
371
|
});
|
|
393
|
-
server.tool('ziggs_list_my_orgs', 'List every org you (the operator) belong to — { orgId, name, kind, role }. Unlike ziggs_discover_context (granted scopes only), this is your full membership
|
|
372
|
+
server.tool('ziggs_list_my_orgs', 'List every org you (the operator) belong to — { orgId, name, kind, role }. Unlike ziggs_discover_context (granted scopes only), this is your full membership — useful before OAuth reconnect when the human wants to pick a target org.', {}, READ_ONLY, async () => {
|
|
394
373
|
try {
|
|
395
374
|
const orgs = await fetchMyOrgs(creds);
|
|
396
375
|
return textResult({ count: orgs.length, orgs });
|
|
@@ -399,40 +378,24 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
399
378
|
return toolError(e.message);
|
|
400
379
|
}
|
|
401
380
|
});
|
|
402
|
-
server.tool('ziggs_switch_org', '
|
|
381
|
+
server.tool('ziggs_switch_org', 'Deprecated: org is fixed at OAuth consent. Reconnect MCP OAuth and pick the target org on the consent screen — this tool no longer switches org server-side.', {
|
|
403
382
|
org: z
|
|
404
383
|
.string()
|
|
405
|
-
.
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
if (resolved.status === 'not-found') {
|
|
421
|
-
return toolError(`No org matches "${selector}". You belong to: ${JSON.stringify(orgs)}`);
|
|
422
|
-
}
|
|
423
|
-
const result = await rebindDelegateOrg(creds, resolved.orgId);
|
|
424
|
-
return textResult({
|
|
425
|
-
ok: true,
|
|
426
|
-
resolvedOrgId: resolved.orgId,
|
|
427
|
-
...result,
|
|
428
|
-
note: result.unchanged
|
|
429
|
-
? 'Already acting in this org — no changes made.'
|
|
430
|
-
: 'Org rebind complete. Existing OAuth token unchanged; call ziggs_auth_status to verify actingOrgId.',
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
catch (e) {
|
|
434
|
-
return toolError(e.message);
|
|
435
|
-
}
|
|
384
|
+
.optional()
|
|
385
|
+
.describe('Ignored — kept for backward compatibility with older prompts'),
|
|
386
|
+
confirm: z.literal(true).optional(),
|
|
387
|
+
}, WRITE, async () => {
|
|
388
|
+
return textResult({
|
|
389
|
+
ok: false,
|
|
390
|
+
deprecated: true,
|
|
391
|
+
message: 'ziggs_switch_org no longer switches org. Org is bound at MCP OAuth consent. Reconnect the Ziggs MCP server in your client, pick the desired org on the consent screen, then call ziggs_auth_status to verify actingOrgId.',
|
|
392
|
+
reconnectSteps: [
|
|
393
|
+
'Remove or disable the Ziggs MCP connection in your client',
|
|
394
|
+
'Re-add https://mcp.ziggsai.com/mcp (or your .mcp.json entry)',
|
|
395
|
+
'On the Ziggs consent screen, select the org you want',
|
|
396
|
+
'Call ziggs_auth_status and confirm actingOrgId',
|
|
397
|
+
],
|
|
398
|
+
});
|
|
436
399
|
});
|
|
437
400
|
server.tool('ziggs_pending_decisions', ZIGGS_PENDING_DECISIONS_DESCRIPTION, {}, READ_ONLY, async () => {
|
|
438
401
|
try {
|
|
@@ -575,24 +538,26 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
575
538
|
return toolError(e.message);
|
|
576
539
|
}
|
|
577
540
|
});
|
|
578
|
-
server.tool('ziggs_propose_agreement', 'Propose a direct agreement to one counterparty in a chat
|
|
541
|
+
server.tool('ziggs_propose_agreement', 'Propose a direct agreement to one counterparty (proposedTo) in a chat. The payer is always derived server-side as the non-providing side — there is no payer input. 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). Set providerId to a third-party agent id to broker (they work, proposedTo pays) — that provider must have an active published offer whose terms match this proposal (price, lifecycle, engagementKind, etc.) or the call fails naming the mismatched field. engagementKind "service" (default) = one deliverable; "hire" = ongoing engagement. price is recorded on the agreement but does not itself trigger a transfer.', {
|
|
579
542
|
proposedTo: z.string(),
|
|
580
543
|
chatId: z.string(),
|
|
581
544
|
description: z.string(),
|
|
545
|
+
providerId: z
|
|
546
|
+
.string()
|
|
547
|
+
.optional()
|
|
548
|
+
.describe('Who does the work. Omitted = proposedTo (commission). Your agent id = offer. Another agent id = broker/matchmaking.'),
|
|
582
549
|
price: z.number().optional().describe('Optional; does not trigger transfer by itself'),
|
|
583
550
|
engagementKind: z
|
|
584
551
|
.enum(['hire', 'service'])
|
|
585
552
|
.optional()
|
|
586
553
|
.describe("'service' (default) = one-off deliverable; 'hire' = ongoing engagement"),
|
|
587
|
-
}, WRITE, async ({ proposedTo, chatId, description, price, engagementKind }) => {
|
|
554
|
+
}, WRITE, async ({ proposedTo, chatId, description, providerId, price, engagementKind }) => {
|
|
588
555
|
try {
|
|
589
556
|
const agreement = await proposeDirectTo({
|
|
590
557
|
proposedTo,
|
|
591
558
|
chatId,
|
|
592
559
|
description,
|
|
593
|
-
|
|
594
|
-
// and the payer is derived server-side as the creator's side.
|
|
595
|
-
providerId: proposedTo,
|
|
560
|
+
providerId: providerId?.trim() || proposedTo,
|
|
596
561
|
price,
|
|
597
562
|
engagementKind: engagementKind ?? 'service',
|
|
598
563
|
}, creds);
|
|
@@ -768,13 +733,18 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
768
733
|
activeTasksError = e.message;
|
|
769
734
|
}
|
|
770
735
|
// ZIG-635: tag each scope with the covering grant from the caller's own
|
|
771
|
-
//
|
|
736
|
+
// held context grants. Best-effort — the inbox still works untagged.
|
|
737
|
+
// All pages of live grants only (GET /grants also returns expired/revoked
|
|
738
|
+
// and paginates), so a scope isn't left untagged behind the first page.
|
|
772
739
|
let reach = [];
|
|
773
740
|
try {
|
|
774
|
-
reach = await new
|
|
741
|
+
reach = await new GrantsClient(creds.operatorKey, creds.agentId).listAllGrants({
|
|
742
|
+
scopeKind: ['chat', 'agreement', 'org'],
|
|
743
|
+
health: 'active',
|
|
744
|
+
});
|
|
775
745
|
}
|
|
776
746
|
catch {
|
|
777
|
-
// omit grant tags when
|
|
747
|
+
// omit grant tags when the grants read fails
|
|
778
748
|
}
|
|
779
749
|
return textResult(formatInboxToolResult(inbox, acked, cfg.ZIGGS_WEB_URL, activeTasks, reach, activeTasksError));
|
|
780
750
|
}
|
|
@@ -782,11 +752,23 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
782
752
|
return toolError(e.message);
|
|
783
753
|
}
|
|
784
754
|
});
|
|
785
|
-
server.tool('ziggs_discover_context', 'List every context grant this delegate holds, as
|
|
755
|
+
server.tool('ziggs_discover_context', 'List every context grant this delegate holds, as canonical grants — grantId, scope, caveats (temporal + watermark_at), expiresAt, health (no content). The single "what is my reach" tool; pass a grantId to ziggs_read_context to pin a specific grant. Cursor-paginated: pass cursor from a prior nextCursor to page.', {
|
|
756
|
+
cursor: z
|
|
757
|
+
.string()
|
|
758
|
+
.optional()
|
|
759
|
+
.describe('Opaque cursor from a prior nextCursor'),
|
|
760
|
+
limit: z.number().optional().describe('Page size (default server-side)'),
|
|
761
|
+
}, READ_ONLY, async ({ cursor, limit }) => {
|
|
786
762
|
try {
|
|
787
|
-
const client = new
|
|
788
|
-
const
|
|
789
|
-
|
|
763
|
+
const client = new GrantsClient(creds.operatorKey, creds.agentId);
|
|
764
|
+
const { items, nextCursor } = await client.listGrants({
|
|
765
|
+
scopeKind: ['chat', 'agreement', 'org'],
|
|
766
|
+
// Reach = live grants only; revoked/expired are not reachable.
|
|
767
|
+
health: 'active',
|
|
768
|
+
cursor,
|
|
769
|
+
limit,
|
|
770
|
+
});
|
|
771
|
+
return textResult({ count: items.length, grants: items, nextCursor });
|
|
790
772
|
}
|
|
791
773
|
catch (e) {
|
|
792
774
|
return toolError(e.message);
|
|
@@ -1001,7 +983,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
1001
983
|
}
|
|
1002
984
|
});
|
|
1003
985
|
server.tool('ziggs_list_my_connections', 'Discover the third-party connections (credentials like GitHub/Jira, NOT agent-to-agent Links — see ziggs_list_links for that) you hold grants for (e.g. "is GitHub connected?") without the owner sharing connectionId/grantId out of band. ' +
|
|
1004
|
-
'Returns, per connection: connectionId, provider,
|
|
986
|
+
'Returns, per connection: connectionId, provider, and the grant(s) you hold — each as the canonical grant shape (grantId, scope, caveats, and grant health active/expired/revoked). ' +
|
|
1005
987
|
'Read-only — never returns credential material. Feed the connectionId + a grantId with health "active" into ziggs_connection_proxy to actually use it.', {}, READ_ONLY, async () => {
|
|
1006
988
|
try {
|
|
1007
989
|
const connections = await listConnectionsForHolder(creds);
|
package/dist/trustTools.js
CHANGED
|
@@ -57,7 +57,7 @@ export function registerTrustTools(server, creds, cfg) {
|
|
|
57
57
|
return toolError(e.message);
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
|
-
server.tool('ziggs_issue_grant', 'Issue bounded context access. Chat scope: admits agent via POST /chats/:id/members (agent-invite → pending_approval until humans consent). Agreement/org scope:
|
|
60
|
+
server.tool('ziggs_issue_grant', 'Issue bounded context access. Chat scope: admits agent via POST /chats/:id/members (agent-invite → pending_approval until humans consent) — this works for you as a delegate. Agreement/org scope: issuing a NEW root grant is a human-authority action; if you are acting for a principal you are denied (AGENT_LACKS_HUMAN_AUTHORITY) — instead use ziggs_delegate_grant to hand a peer a narrower slice of a grant you already hold, or ask your human to issue it. Defaults: from-now, narrow scope.', {
|
|
61
61
|
holderId: z.string().describe('Bare agent id receiving the grant'),
|
|
62
62
|
scopeKind: grantScopeKindSchema,
|
|
63
63
|
scopeId: z.string().describe('chatId, agreementId, or orgId'),
|
|
@@ -210,7 +210,7 @@ export function registerTrustTools(server, creds, cfg) {
|
|
|
210
210
|
const { agreement } = await claimAgreement(agreementId, creds);
|
|
211
211
|
return textResult({
|
|
212
212
|
status: 'linked',
|
|
213
|
-
message: 'Link invite claimed — you are now linked. A link is reach-only:
|
|
213
|
+
message: 'Link invite claimed — you are now linked. A link is reach-only: open a chat with the peer (ziggs_open_conversation) and grant it chat access with ziggs_issue_grant, or share a slice of a grant you already hold with ziggs_delegate_grant, before reading context.',
|
|
214
214
|
agreement,
|
|
215
215
|
});
|
|
216
216
|
}
|
|
@@ -252,7 +252,7 @@ export function registerTrustTools(server, creds, cfg) {
|
|
|
252
252
|
links: summaries,
|
|
253
253
|
...(hasActive
|
|
254
254
|
? {
|
|
255
|
-
nextSteps: 'A link is reach-only.
|
|
255
|
+
nextSteps: 'A link is reach-only. Open a chat with the peer (ziggs_open_conversation, participantId = peer agent id) and grant it chat access with ziggs_issue_grant, or share a slice of a grant you hold with ziggs_delegate_grant, before reading context.',
|
|
256
256
|
}
|
|
257
257
|
: {}),
|
|
258
258
|
});
|
|
@@ -279,7 +279,7 @@ export function registerTrustTools(server, creds, cfg) {
|
|
|
279
279
|
return toolError(e.message);
|
|
280
280
|
}
|
|
281
281
|
});
|
|
282
|
-
server.tool('ziggs_revoke_grant', 'Revoke a context grant and its descendants (DELETE /context/grants/:id). You can revoke (narrow) any grant you hold — this needs no special scope. Revoking a grant you issued or
|
|
282
|
+
server.tool('ziggs_revoke_grant', 'Revoke a context grant and its descendants (DELETE /context/grants/:id). You can revoke (narrow) any grant you hold — this needs no special scope. Revoking a grant you do NOT hold (one you issued, or on a scope you own) is a human-authority action: as a delegate you are limited to grants you hold; the human/owner does the rest.', {
|
|
283
283
|
grantId: z.string(),
|
|
284
284
|
}, DESTRUCTIVE, async ({ grantId }) => {
|
|
285
285
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/ziggs-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
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.1.
|
|
39
|
+
"@ziggs-ai/api-client": "^0.1.29",
|
|
40
40
|
"dotenv": "^16.6.1",
|
|
41
41
|
"zod": "^3.24.2"
|
|
42
42
|
},
|
package/skills/ziggs/SKILL.md
CHANGED
|
@@ -38,8 +38,8 @@ The sections below elaborate this protocol with tools, examples, and edge cases.
|
|
|
38
38
|
|
|
39
39
|
## Session start — pending decisions + inbox
|
|
40
40
|
|
|
41
|
-
1. Call **`ziggs_auth_status`** after OAuth connect — check **`actingOrgId`** / **`actingOrgName`** (runtime org, not JWT).
|
|
42
|
-
2. To
|
|
41
|
+
1. Call **`ziggs_auth_status`** after OAuth connect — check **`actingOrgId`** / **`actingOrgName`** (runtime org, not JWT). Org is fixed at consent (ZIG-852).
|
|
42
|
+
2. To act in another org: **reconnect MCP OAuth** and pick that org on the consent screen, then re-check **`ziggs_auth_status`**. Use **`ziggs_list_my_orgs`** to help the human choose a target org name before reconnecting.
|
|
43
43
|
3. Call **`ziggs_pending_decisions`** — if `pendingCount > 0`, **paste `decisionChatCard` for the human** before anything else. Wait for explicit approve/reject; then `ziggs_respond_to_agreement`.
|
|
44
44
|
3. Call **`ziggs_inbox`** (optionally pass **`ack`** for scopes you already handled in the prior turn).
|
|
45
45
|
4. Read the envelope: scope news counts, `humanAttention`, and **`decisionChatCard`** when present.
|