@ziggs-ai/ziggs-mcp 0.9.9 → 0.9.11
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/.claude-plugin/plugin.json +1 -1
- package/README.md +7 -90
- package/dist/capabilityAdapter.d.ts +1 -1
- package/dist/capabilityAdapter.js +1 -1
- package/dist/config.d.ts +5 -5
- package/dist/config.js +5 -5
- package/dist/connectionCreds.d.ts +1 -1
- package/dist/connectionCreds.js +2 -2
- package/dist/inboxToolResult.d.ts +10 -10
- package/dist/inboxToolResult.js +43 -24
- package/dist/operatorKey.d.ts +1 -1
- package/dist/operatorKey.js +1 -1
- package/dist/paymentTools.d.ts +1 -1
- package/dist/paymentTools.js +1 -1
- package/dist/pendingDecisions.d.ts +14 -14
- package/dist/pendingDecisions.js +17 -17
- package/dist/protocol/delegateProtocol.d.ts +6 -6
- package/dist/protocol/delegateProtocol.js +6 -6
- package/dist/server.js +2 -2
- package/dist/strictParams.d.ts +1 -1
- package/dist/toolError.d.ts +3 -3
- package/dist/toolError.js +4 -4
- package/dist/tools.js +41 -33
- package/dist/trustTools.d.ts +1 -1
- package/dist/trustTools.js +4 -4
- package/examples/chatgpt-unsupported.md +4 -13
- package/examples/claude-ai-oauth.md +21 -113
- package/examples/claude-code-remote-oauth.md +20 -80
- package/examples/claude-code.md +2 -11
- package/examples/cursor-remote-oauth.md +23 -83
- package/package.json +5 -5
- package/skills/ziggs/.cursorrules +1 -1
- package/skills/ziggs/SKILL.md +6 -6
- package/skills/ziggs/references/inbox-rhythm.md +1 -1
- package/skills/ziggs/references/reporting-convention.md +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ziggs",
|
|
3
|
-
"description": "Ziggs delegate agent — MCP connection plus inbox-first workflow skill
|
|
3
|
+
"description": "Ziggs delegate agent — MCP connection plus inbox-first workflow skill.",
|
|
4
4
|
"version": "0.1.4",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "ZiggsAI",
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
MCP (stdio) server for **Claude Code**, **Cursor**, and other MCP hosts.
|
|
4
4
|
|
|
5
|
-
**In scope:** chat, agreements (service and hire, direct or published), scope, context discovery/reads, artifacts, payments (`ziggs_payment_*` — transfers, escrow holds, payment grants
|
|
5
|
+
**In scope:** chat, agreements (service and hire, direct or published), scope, context discovery/reads, artifacts, payments (`ziggs_payment_*` — transfers, escrow holds, payment grants).
|
|
6
6
|
Transfers above the wallet owner's policy pause as `approval_required` — the human decides on the wallet page (surfaced by `ziggs_pending_decisions`); there is no agent-side approve tool.
|
|
7
7
|
|
|
8
8
|
---
|
|
@@ -37,7 +37,7 @@ claude plugin install ./ziggs-mcp
|
|
|
37
37
|
|
|
38
38
|
Skill only (no plugin): `skills/ziggs/SKILL.md` ships in the package for org provisioning or [skills.sh](https://skills.sh) discovery.
|
|
39
39
|
|
|
40
|
-
###
|
|
40
|
+
### Verify
|
|
41
41
|
|
|
42
42
|
| Step | Tool |
|
|
43
43
|
|------|------|
|
|
@@ -45,12 +45,6 @@ Skill only (no plugin): `skills/ziggs/SKILL.md` ships in the package for org pro
|
|
|
45
45
|
| Send message | `ziggs_chat_send` |
|
|
46
46
|
| Propose + respond | `ziggs_agreement_propose`, `ziggs_agreement_respond` |
|
|
47
47
|
|
|
48
|
-
Automated verify (same MCP path as `claude mcp add` + `npx`):
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
ZIGGS_OPERATOR_KEY=<agent-scoped> node scripts/smoke-ziggs-mcp-z430-e2e.mjs
|
|
52
|
-
```
|
|
53
|
-
|
|
54
48
|
---
|
|
55
49
|
|
|
56
50
|
## claude.ai / remote MCP (OAuth)
|
|
@@ -59,36 +53,17 @@ Hosted Streamable HTTP: `https://mcp.ziggsai.com/mcp` (Bearer from OAuth, no key
|
|
|
59
53
|
|
|
60
54
|
OAuth metadata: `https://api.ziggsai.com/.well-known/oauth-authorization-server`
|
|
61
55
|
|
|
62
|
-
**Consent:** `GET /oauth/authorize` always redirects to `/app/oauth/mcp-consent` — even if you already have an API session. You must click **Allow**;
|
|
63
|
-
|
|
64
|
-
Automated E2E (DCR → consent → token → remote MCP → list chats + send message):
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
# prod smoke with throwaway user
|
|
68
|
-
node scripts/smoke-ziggs-mcp-oauth-z468-e2e.mjs --auto
|
|
69
|
-
|
|
70
|
-
# or existing account
|
|
71
|
-
ZIGGS_SMOKE_EMAIL=you@example.com ZIGGS_SMOKE_PASSWORD=... \
|
|
72
|
-
node scripts/smoke-ziggs-mcp-oauth-z468-e2e.mjs
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
**Consent probe** (GET must redirect to consent, not issue code):
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
node scripts/smoke-ziggs-mcp-oauth-z474-consent-probe.mjs --auto
|
|
79
|
-
```
|
|
56
|
+
**Consent:** `GET /oauth/authorize` always redirects to `/app/oauth/mcp-consent` — even if you already have an API session. You must click **Allow**; there is no silent code issuance.
|
|
80
57
|
|
|
81
|
-
**
|
|
58
|
+
**Setup guide:** [`examples/claude-ai-oauth.md`](examples/claude-ai-oauth.md).
|
|
82
59
|
|
|
83
60
|
### MCP registry (`server.json`)
|
|
84
61
|
|
|
85
|
-
This package ships [`server.json`](./server.json) for [registry.modelcontextprotocol.io](https://registry.modelcontextprotocol.io)
|
|
86
|
-
|
|
87
|
-
**Publish path:** GitHub Actions workflow `Publish MCP registry` (OIDC as `ZiggsAI`) — runs on `ziggs-mcp-v*` tags after npm publish, or `workflow_dispatch`. Local `mcp-publisher login github` with a personal PAT only grants `io.github.<your-user>/*`, not the org namespace.
|
|
62
|
+
This package ships [`server.json`](./server.json) for [registry.modelcontextprotocol.io](https://registry.modelcontextprotocol.io). `package.json` includes the matching `mcpName: io.github.ZiggsAI/ziggs`.
|
|
88
63
|
|
|
89
64
|
### ChatGPT
|
|
90
65
|
|
|
91
|
-
**
|
|
66
|
+
**Not supported** — see [`examples/chatgpt-unsupported.md`](examples/chatgpt-unsupported.md). Use claude.ai, Claude Code, or Cursor.
|
|
92
67
|
|
|
93
68
|
---
|
|
94
69
|
|
|
@@ -112,16 +87,8 @@ Settings → Tools & MCP → **Connect** → Ziggs consent → use tools in chat
|
|
|
112
87
|
|
|
113
88
|
Full walkthrough: [`examples/cursor-remote-oauth.md`](examples/cursor-remote-oauth.md)
|
|
114
89
|
|
|
115
|
-
Parity probe (metadata + DCR + protected-resource):
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
node scripts/probe-cursor-oauth-parity.mjs
|
|
119
|
-
```
|
|
120
|
-
|
|
121
90
|
### Local stdio (operator key)
|
|
122
91
|
|
|
123
|
-
Build from source or use npm after publish:
|
|
124
|
-
|
|
125
92
|
```bash
|
|
126
93
|
npm install && npm run build -w @ziggs-ai/ziggs-mcp
|
|
127
94
|
```
|
|
@@ -142,7 +109,7 @@ Sign up and log in at the web app.
|
|
|
142
109
|
|
|
143
110
|
**Fleet key (Cursor / multi-agent):** Developer Portal → Operator keys, then set `ZIGGS_AGENT_ID`.
|
|
144
111
|
|
|
145
|
-
Minimum scopes
|
|
112
|
+
Minimum scopes to get started: `agents:impersonate`, `agents:read`, `agents:write`, `context:read`.
|
|
146
113
|
|
|
147
114
|
### 3. Environment
|
|
148
115
|
|
|
@@ -162,41 +129,6 @@ X-Agent-Id: <resolved delegate agent id>
|
|
|
162
129
|
|
|
163
130
|
Startup validates the key shape, expiry (JWT `exp`), and agent resolution — errors point to Developer Portal.
|
|
164
131
|
|
|
165
|
-
### 4. CLI smoke scripts
|
|
166
|
-
|
|
167
|
-
From the **repository root** ([github.com/ZiggsAI/agentplus](https://github.com/ZiggsAI/agentplus)):
|
|
168
|
-
|
|
169
|
-
```bash
|
|
170
|
-
# basic boarding smoke
|
|
171
|
-
ZIGGS_OPERATOR_KEY=... ZIGGS_AGENT_ID=cursor-delegate \
|
|
172
|
-
node scripts/smoke-ziggs-mcp.mjs
|
|
173
|
-
|
|
174
|
-
# two delegates + negative 403
|
|
175
|
-
ZIGGS_OPERATOR_KEY_A=... ZIGGS_AGENT_ID_A=... \
|
|
176
|
-
ZIGGS_OPERATOR_KEY_B=... ZIGGS_AGENT_ID_B=... \
|
|
177
|
-
ZIGGS_SMOKE_CHAT_ID=... \
|
|
178
|
-
node scripts/smoke-ziggs-mcp-context.mjs
|
|
179
|
-
|
|
180
|
-
# tools-only (npx trust tools after publish)
|
|
181
|
-
ZIGGS_OPERATOR_KEY=<agent-scoped> node scripts/smoke-ziggs-mcp-z433-e2e.mjs --tools-only
|
|
182
|
-
|
|
183
|
-
# auto two-org (provisions users/agents/chat, then full flow)
|
|
184
|
-
HTTP_URL=https://api.ziggsai.com node scripts/smoke-ziggs-mcp-z433-e2e.mjs --auto
|
|
185
|
-
|
|
186
|
-
# full two-org (manual env)
|
|
187
|
-
ZIGGS_OPERATOR_KEY_A=... ZIGGS_AGENT_ID_A=... \
|
|
188
|
-
ZIGGS_OPERATOR_KEY_B=... ZIGGS_AGENT_ID_B=... \
|
|
189
|
-
ZIGGS_APPROVER_OPERATOR_KEY=... ZIGGS_APPROVER_USER_ID=... \
|
|
190
|
-
ZIGGS_SMOKE_CHAT_ID=... \
|
|
191
|
-
node scripts/smoke-ziggs-mcp-z433-e2e.mjs
|
|
192
|
-
|
|
193
|
-
# party handshake (link agreement, prod)
|
|
194
|
-
HTTP_URL=https://api.ziggsai.com \
|
|
195
|
-
OP_KEY_A=... AGENT_A=... USER_B=... OP_KEY_B=... AGENT_B=... \
|
|
196
|
-
npm run smoke:zig-481-prod
|
|
197
|
-
# Runbook: docs/evals/party-connection-two-claude.md
|
|
198
|
-
```
|
|
199
|
-
|
|
200
132
|
---
|
|
201
133
|
|
|
202
134
|
## Tools
|
|
@@ -219,7 +151,6 @@ OP_KEY_A=... AGENT_A=... USER_B=... OP_KEY_B=... AGENT_B=... \
|
|
|
219
151
|
| `ziggs_link_create_invite` | `POST /agreements` `{engagementKind:"link"}` open invite (claimUrl + paste text) |
|
|
220
152
|
| `ziggs_link_list` | `GET /agreements?engagementKind=link` |
|
|
221
153
|
| `ziggs_agreement_revoke` | `DELETE /agreements/:id` — any agreement (hire/service/quest/offer/link) |
|
|
222
|
-
| `ziggs_smoke_impersonation` | [Internal/debug] connectivity check — only when `ZIGGS_MCP_DEBUG=1`; not part of normal delegate workflow |
|
|
223
154
|
| `ziggs_context_snapshot` | `GET /context/snapshot?via=chat:` — one-shot chat orientation (history + agreements + roster), grant-fenced |
|
|
224
155
|
| `ziggs_agreement_list` | `GET /agreements?scope=mine&partyOnly=true` — agreements you are a party to; `scope: "reachable"` drops `partyOnly` for every agreement your grant can read |
|
|
225
156
|
| `ziggs_agreement_get` | `GET /agreements/:id` |
|
|
@@ -245,17 +176,3 @@ npm test -w @ziggs-ai/ziggs-mcp
|
|
|
245
176
|
```
|
|
246
177
|
|
|
247
178
|
Logs must use **stderr** only (stdio MCP transport).
|
|
248
|
-
|
|
249
|
-
## Publish (maintainers)
|
|
250
|
-
|
|
251
|
-
1. Bump `@ziggs-ai/api-client` if needed → tag `api-client-v*`, push (publishes to npm).
|
|
252
|
-
2. Tag `ziggs-mcp-v*` → CI publishes `@ziggs-ai/ziggs-mcp`.
|
|
253
|
-
|
|
254
|
-
```bash
|
|
255
|
-
git tag api-client-v0.1.9 && git push origin api-client-v0.1.9
|
|
256
|
-
git tag ziggs-mcp-v0.1.4 && git push origin ziggs-mcp-v0.1.4
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
CI publishes on tag push. Push **api-client tag first**, then ziggs-mcp.
|
|
260
|
-
|
|
261
|
-
npm `--provenance` is not used: npm only supports provenance when the GitHub source repo is **public** (agentplus is private → 422).
|
|
@@ -14,7 +14,7 @@ export interface RegisterCapabilityOptions {
|
|
|
14
14
|
webUrl?: string;
|
|
15
15
|
/**
|
|
16
16
|
* Description override for wording assembled from MCP-local shared consts
|
|
17
|
-
* (e.g. the delegate-protocol reporting rule
|
|
17
|
+
* (e.g. the delegate-protocol reporting rule) — schema and handler
|
|
18
18
|
* still come from the shared definition.
|
|
19
19
|
*/
|
|
20
20
|
description?: string;
|
|
@@ -9,7 +9,7 @@ export function textResult(data) {
|
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* the MCP surface adapter for shared capability definitions
|
|
13
13
|
* (api-client `capabilities/`). Lowers the neutral param DSL to zod v3 (the
|
|
14
14
|
* MCP SDK's ZodRawShape; api-client itself carries no zod, and agent-sdk is on
|
|
15
15
|
* zod v4, so the schema is defined once and lowered per surface).
|
package/dist/config.d.ts
CHANGED
|
@@ -6,16 +6,16 @@ declare const envSchema: z.ZodObject<{
|
|
|
6
6
|
/** Web app base URL for constructing shareable links. Defaults to https://ziggsai.com. */
|
|
7
7
|
ZIGGS_WEB_URL: z.ZodOptional<z.ZodString>;
|
|
8
8
|
ZIGGS_OPERATOR_KEY: z.ZodString;
|
|
9
|
-
/** Optional when the operator key is agent-scoped
|
|
9
|
+
/** Optional when the operator key is agent-scoped. */
|
|
10
10
|
ZIGGS_AGENT_ID: z.ZodOptional<z.ZodString>;
|
|
11
11
|
/** Human user id for payer-side proposals — defaults the payer on propose/publish tools. */
|
|
12
12
|
ZIGGS_OWNER_USER_ID: z.ZodOptional<z.ZodString>;
|
|
13
|
-
/** Set to 1/true/yes to register internal/debug-only MCP tools
|
|
13
|
+
/** Set to 1/true/yes to register internal/debug-only MCP tools. */
|
|
14
14
|
ZIGGS_MCP_DEBUG: z.ZodOptional<z.ZodString>;
|
|
15
15
|
/**
|
|
16
16
|
* Set to 1/true/yes to register only the core everyday/session-start tools,
|
|
17
17
|
* skipping the heavy groups (payments, links, marketplace, connections) to
|
|
18
|
-
* cut cold-start deferred-loading (
|
|
18
|
+
* cut cold-start deferred-loading (#7). Unset = all tools register.
|
|
19
19
|
*/
|
|
20
20
|
ZIGGS_MCP_CORE_ONLY: z.ZodOptional<z.ZodString>;
|
|
21
21
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -45,10 +45,10 @@ export interface ZiggsMcpConfig extends EnvConfig {
|
|
|
45
45
|
debugTools: boolean;
|
|
46
46
|
/**
|
|
47
47
|
* When true, register only the core everyday/session-start tool tier and skip
|
|
48
|
-
* the heavy groups (payments, links, marketplace, connections)
|
|
48
|
+
* the heavy groups (payments, links, marketplace, connections) #7.
|
|
49
49
|
*/
|
|
50
50
|
coreOnly: boolean;
|
|
51
51
|
}
|
|
52
|
-
/** Load delegate credentials from the environment
|
|
52
|
+
/** Load delegate credentials from the environment. */
|
|
53
53
|
export declare function loadConfig(): ZiggsMcpConfig;
|
|
54
54
|
export {};
|
package/dist/config.js
CHANGED
|
@@ -8,16 +8,16 @@ const envSchema = z.object({
|
|
|
8
8
|
/** Web app base URL for constructing shareable links. Defaults to https://ziggsai.com. */
|
|
9
9
|
ZIGGS_WEB_URL: z.string().optional(),
|
|
10
10
|
ZIGGS_OPERATOR_KEY: z.string().min(1, 'ZIGGS_OPERATOR_KEY is required'),
|
|
11
|
-
/** Optional when the operator key is agent-scoped
|
|
11
|
+
/** Optional when the operator key is agent-scoped. */
|
|
12
12
|
ZIGGS_AGENT_ID: z.string().optional(),
|
|
13
13
|
/** Human user id for payer-side proposals — defaults the payer on propose/publish tools. */
|
|
14
14
|
ZIGGS_OWNER_USER_ID: z.string().optional(),
|
|
15
|
-
/** Set to 1/true/yes to register internal/debug-only MCP tools
|
|
15
|
+
/** Set to 1/true/yes to register internal/debug-only MCP tools. */
|
|
16
16
|
ZIGGS_MCP_DEBUG: z.string().optional(),
|
|
17
17
|
/**
|
|
18
18
|
* Set to 1/true/yes to register only the core everyday/session-start tools,
|
|
19
19
|
* skipping the heavy groups (payments, links, marketplace, connections) to
|
|
20
|
-
* cut cold-start deferred-loading (
|
|
20
|
+
* cut cold-start deferred-loading (#7). Unset = all tools register.
|
|
21
21
|
*/
|
|
22
22
|
ZIGGS_MCP_CORE_ONLY: z.string().optional(),
|
|
23
23
|
});
|
|
@@ -28,7 +28,7 @@ function parseBoolFlag(raw) {
|
|
|
28
28
|
const v = raw.trim().toLowerCase();
|
|
29
29
|
return v === '1' || v === 'true' || v === 'yes';
|
|
30
30
|
}
|
|
31
|
-
/** Load delegate credentials from the environment
|
|
31
|
+
/** Load delegate credentials from the environment. */
|
|
32
32
|
export function loadConfig() {
|
|
33
33
|
const raw = {
|
|
34
34
|
ZIGGS_API_URL: process.env.ZIGGS_API_URL,
|
|
@@ -52,7 +52,7 @@ export function loadConfig() {
|
|
|
52
52
|
catch (e) {
|
|
53
53
|
throw e instanceof Error ? e : new Error(String(e));
|
|
54
54
|
}
|
|
55
|
-
// api-client reads injected config, not the environment
|
|
55
|
+
// api-client reads injected config, not the environment. This
|
|
56
56
|
// server owns its process, so it hands over whichever base URL it resolved.
|
|
57
57
|
const httpUrl = process.env.HTTP_URL || parsed.data.ZIGGS_API_URL;
|
|
58
58
|
if (httpUrl) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Creds } from '@ziggs-ai/api-client';
|
|
2
2
|
import type { ZiggsMcpConfig } from './config.js';
|
|
3
3
|
export declare function parseBearerAuthorization(header: string | string[] | undefined): string;
|
|
4
|
-
/** Per-connection credentials from HTTP Authorization
|
|
4
|
+
/** Per-connection credentials from HTTP Authorization. */
|
|
5
5
|
export declare function connectionFromBearer(bearer: string, httpBaseUrl: string, ownerUserId?: string): {
|
|
6
6
|
creds: Creds;
|
|
7
7
|
cfg: ZiggsMcpConfig;
|
package/dist/connectionCreds.js
CHANGED
|
@@ -11,12 +11,12 @@ export function parseBearerAuthorization(header) {
|
|
|
11
11
|
}
|
|
12
12
|
return token;
|
|
13
13
|
}
|
|
14
|
-
/** Per-connection credentials from HTTP Authorization
|
|
14
|
+
/** Per-connection credentials from HTTP Authorization. */
|
|
15
15
|
export function connectionFromBearer(bearer, httpBaseUrl, ownerUserId) {
|
|
16
16
|
const resolvedAgentId = resolveDelegateAgentId(bearer, undefined);
|
|
17
17
|
if (httpBaseUrl) {
|
|
18
18
|
process.env.HTTP_URL = httpBaseUrl;
|
|
19
|
-
// Same global reach as the env write it replaces
|
|
19
|
+
// Same global reach as the env write it replaces: api-client
|
|
20
20
|
// holds one base URL per process, so the last connection wins here too.
|
|
21
21
|
configureApiClient({ httpUrl: httpBaseUrl });
|
|
22
22
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { GrantView, ContextReadType, InboxAckResult, InboxEnvelope, Task } from '@ziggs-ai/api-client';
|
|
2
2
|
import { type DecisionSelfIds } from './pendingDecisions.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* (Step 1): a pre-filled next call. The agent can run it verbatim
|
|
5
5
|
* instead of assembling args from the ids scattered through the response.
|
|
6
6
|
* `tool` + `args` mirror the MCP tool signature; `why` is a one-line reason.
|
|
7
7
|
*/
|
|
@@ -11,7 +11,7 @@ export interface ReadPlanCall {
|
|
|
11
11
|
why: string;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* buildReadPlan returns the (bounded, deduped) plan plus how many
|
|
15
15
|
* candidate entries the cap dropped, so the caller can surface truncation
|
|
16
16
|
* explicitly instead of the plan silently ending short.
|
|
17
17
|
*/
|
|
@@ -20,7 +20,7 @@ export interface ReadPlanResult {
|
|
|
20
20
|
truncated: number;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
23
|
+
* replace the free-text `nextActions` hints with typed `readPlan`
|
|
24
24
|
* call objects — tool name + pre-filled args — so the most common loop
|
|
25
25
|
* (inbox → read what was addressed to you → ack) needs no guesswork.
|
|
26
26
|
*
|
|
@@ -34,7 +34,7 @@ export interface ReadPlanResult {
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function buildReadPlan(inbox: InboxEnvelope, grantsByScope?: Map<string, ScopeGrantTag>, self?: DecisionSelfIds): ReadPlanResult;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
37
|
+
* forward-continuation for a read_context page. Built only from fields
|
|
38
38
|
* already on the page (via, hasMore/nextCursor, latestSequence) plus the grant
|
|
39
39
|
* id the caller presented — echoed back, never discovered. Nothing new is read.
|
|
40
40
|
*
|
|
@@ -48,7 +48,7 @@ export declare function buildReadContextReadPlan(page: {
|
|
|
48
48
|
latestSequence?: string | null;
|
|
49
49
|
}, type: ContextReadType, via: string, presentedGrantId?: string): ReadPlanCall[];
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
51
|
+
* (Step 2): the covering grant attached to a scope so the agent can
|
|
52
52
|
* pin the right X-Context-Grant-Id without a separate discover_context call.
|
|
53
53
|
* Grant metadata only — never a resource-derived field.
|
|
54
54
|
*/
|
|
@@ -60,23 +60,23 @@ export interface ScopeGrantTag {
|
|
|
60
60
|
parentGrantId: string | null;
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
63
|
+
* index the caller's own live reach descriptors by scope. The reach
|
|
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
67
|
export declare function indexReachByScope(reach: GrantView[]): Map<string, ScopeGrantTag>;
|
|
68
68
|
/**
|
|
69
|
-
* Put humanAttention first so MCP hosts surface it before counts
|
|
69
|
+
* Put humanAttention first so MCP hosts surface it before counts,
|
|
70
70
|
* and append readPlan last so each inbox call self-narrates the follow-up
|
|
71
|
-
* calls
|
|
71
|
+
* calls without disturbing the leading humanAttention key.
|
|
72
72
|
*
|
|
73
73
|
* When `reach` (the caller's own live grants) is passed, the read plan pins
|
|
74
|
-
* each read's covering grant
|
|
74
|
+
* each read's covering grant so the agent can present
|
|
75
75
|
* X-Context-Grant-Id without a separate discover round-trip.
|
|
76
76
|
*/
|
|
77
77
|
export declare function formatInboxToolResult(inbox: InboxEnvelope, ack?: InboxAckResult | null, webOrigin?: string, activeTasks?: Task[], reach?: GrantView[], activeTasksError?: string,
|
|
78
78
|
/**
|
|
79
|
-
* The caller's own ids
|
|
79
|
+
* The caller's own ids. Optional here alone: this result carries
|
|
80
80
|
* the session-start COUNTS and a pointer to ziggs_pending_decisions, never
|
|
81
81
|
* the decision items themselves, and a count does not depend on which party
|
|
82
82
|
* may answer. Production callers pass it regardless — if this shape ever
|
package/dist/inboxToolResult.js
CHANGED
|
@@ -18,7 +18,7 @@ function artifactEntry(d) {
|
|
|
18
18
|
return ['artifact', d.resourceId];
|
|
19
19
|
}
|
|
20
20
|
function readContextCall(type, kind, id, grantId) {
|
|
21
|
-
//
|
|
21
|
+
// pin the covering grant so the read presents the right
|
|
22
22
|
// X-Context-Grant-Id without a separate discover_context round-trip.
|
|
23
23
|
const grant = grantId ? { contextGrantId: grantId } : {};
|
|
24
24
|
return {
|
|
@@ -28,7 +28,7 @@ function readContextCall(type, kind, id, grantId) {
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* replace the free-text `nextActions` hints with typed `readPlan`
|
|
32
32
|
* call objects — tool name + pre-filled args — so the most common loop
|
|
33
33
|
* (inbox → read what was addressed to you → ack) needs no guesswork.
|
|
34
34
|
*
|
|
@@ -44,7 +44,7 @@ export function buildReadPlan(inbox, grantsByScope, self = { agentId: '' }) {
|
|
|
44
44
|
const proposals = inbox.proposalsAwaitingMe ?? [];
|
|
45
45
|
const connectionRequests = inbox.connectionRequestsAwaitingMe ?? [];
|
|
46
46
|
const deliveries = inbox.deliveries ?? [];
|
|
47
|
-
//
|
|
47
|
+
// dedup by call signature so the same (type, via) can't appear
|
|
48
48
|
// twice when several deliveries land in one chat. Collect candidates
|
|
49
49
|
// uncapped; the cap is applied once, after the ack is reserved, so the ack
|
|
50
50
|
// step always survives.
|
|
@@ -59,7 +59,7 @@ export function buildReadPlan(inbox, grantsByScope, self = { agentId: '' }) {
|
|
|
59
59
|
// Decisions first — these also drive humanAttention (pull-only: no push).
|
|
60
60
|
// The decision (approve/reject) is the human's; we only pre-fill the target.
|
|
61
61
|
//
|
|
62
|
-
//
|
|
62
|
+
// only when the pending slot is OURS. A proposal bound to the
|
|
63
63
|
// principal's slot cannot be answered with this tool by anyone on this
|
|
64
64
|
// surface, so pre-filling the call would be handing over a step that fails
|
|
65
65
|
// every time — the plan says to carry it to the human instead.
|
|
@@ -93,7 +93,7 @@ export function buildReadPlan(inbox, grantsByScope, self = { agentId: '' }) {
|
|
|
93
93
|
why: `connection request ${c.requestId} is awaiting your HUMAN's approval, not yours — paste the card for them; ziggs_agreement_respond is refused for a delegate here`,
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
|
-
//
|
|
96
|
+
// pin the covering grant for a chat/agreement read when the caller
|
|
97
97
|
// holds one, so the read presents the right X-Context-Grant-Id without a
|
|
98
98
|
// separate discover round-trip. Untagged reads still work by id.
|
|
99
99
|
const grantFor = (kind, id) => grantsByScope?.get(`${kind}:${id}`)?.grantId;
|
|
@@ -106,13 +106,13 @@ export function buildReadPlan(inbox, grantsByScope, self = { agentId: '' }) {
|
|
|
106
106
|
// - over `kind`, so a delivery kind nobody plans a read for is a compile
|
|
107
107
|
// error here rather than a plan that quietly ends at the ack;
|
|
108
108
|
// - over the anchor, so is an artifact carrying none of chat/agreement/task
|
|
109
|
-
//
|
|
109
|
+
// — it is read as `artifact:<id>`, the entry added for that case.
|
|
110
110
|
//
|
|
111
111
|
// The first is history: while this looked at chatId/agreementId only, a
|
|
112
112
|
// task-bound deliverable produced an envelope whose plan was the ack and
|
|
113
113
|
// nothing else, and an agent following the plan acked work it never read. The
|
|
114
114
|
// second is that hole closed ahead of an emitter — nothing writes an
|
|
115
|
-
// anchor-less delivery today
|
|
115
|
+
// anchor-less delivery today, and when something does it is planned.
|
|
116
116
|
for (const d of deliveries) {
|
|
117
117
|
switch (d.kind) {
|
|
118
118
|
case 'message':
|
|
@@ -127,7 +127,7 @@ export function buildReadPlan(inbox, grantsByScope, self = { agentId: '' }) {
|
|
|
127
127
|
case 'agreement':
|
|
128
128
|
case 'quest':
|
|
129
129
|
// Deliberately no read call. Tasks/proposals arrive as standing state
|
|
130
|
-
// elsewhere on the envelope; quests
|
|
130
|
+
// elsewhere on the envelope; quests ride `questsAwaitingMe`
|
|
131
131
|
// and are host-triaged with a plain string compare — never an LLM read
|
|
132
132
|
// plan entry (that would recreate the per-quest token drain).
|
|
133
133
|
break;
|
|
@@ -141,24 +141,43 @@ export function buildReadPlan(inbox, grantsByScope, self = { agentId: '' }) {
|
|
|
141
141
|
break;
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
-
//
|
|
144
|
+
// reserve a slot for the ack before capping, so the pre-filled ack
|
|
145
145
|
// never gets squeezed out exactly when there's the most news. Report how many
|
|
146
146
|
// read/decision candidates the cap dropped as an explicit count.
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
//
|
|
148
|
+
// ZIG-1305 — only pre-fill ack when this plan covers the whole envelope.
|
|
149
|
+
// A truncated plan (or a capped delivery list) must not hand back an ack
|
|
150
|
+
// that would clear deliveries the plan never asked the agent to handle.
|
|
151
|
+
// Reserve the ack slot only when every candidate still fits beside it;
|
|
152
|
+
// otherwise spend the full budget on reads and omit ack.
|
|
153
|
+
const canAckFully = !!inbox.ackTo &&
|
|
154
|
+
!inbox.deliveriesCapped &&
|
|
155
|
+
(inbox.truncatedQuests ?? 0) === 0;
|
|
156
|
+
const leaveRoomForAck = canAckFully && candidates.length <= MAX_READ_PLAN - 1;
|
|
157
|
+
const budget = leaveRoomForAck ? MAX_READ_PLAN - 1 : MAX_READ_PLAN;
|
|
149
158
|
const truncated = Math.max(0, candidates.length - budget);
|
|
150
159
|
const plan = candidates.slice(0, budget);
|
|
151
|
-
if (
|
|
160
|
+
if (leaveRoomForAck && truncated === 0) {
|
|
161
|
+
const handledResourceIds = [
|
|
162
|
+
...new Set([
|
|
163
|
+
...(inbox.deliveries ?? []).map((d) => d.resourceId),
|
|
164
|
+
...(inbox.questsAwaitingMe ?? []).map((q) => q.agreementId),
|
|
165
|
+
]),
|
|
166
|
+
].filter((id) => typeof id === 'string' && id.length > 0);
|
|
152
167
|
plan.push({
|
|
153
168
|
tool: 'ziggs_inbox',
|
|
154
|
-
args: {
|
|
155
|
-
|
|
169
|
+
args: {
|
|
170
|
+
ack: inbox.ackTo,
|
|
171
|
+
handledResourceIds,
|
|
172
|
+
},
|
|
173
|
+
why: 'reading does not clear the inbox — ack only after you have handled every step above; ' +
|
|
174
|
+
'handledResourceIds must list every delivery this envelope carried',
|
|
156
175
|
});
|
|
157
176
|
}
|
|
158
177
|
return { plan, truncated };
|
|
159
178
|
}
|
|
160
179
|
/**
|
|
161
|
-
*
|
|
180
|
+
* forward-continuation for a read_context page. Built only from fields
|
|
162
181
|
* already on the page (via, hasMore/nextCursor, latestSequence) plus the grant
|
|
163
182
|
* id the caller presented — echoed back, never discovered. Nothing new is read.
|
|
164
183
|
*
|
|
@@ -195,7 +214,7 @@ export function buildReadContextReadPlan(page, type, via, presentedGrantId) {
|
|
|
195
214
|
function toScopeGrantTag(g) {
|
|
196
215
|
return {
|
|
197
216
|
grantId: g.grantId,
|
|
198
|
-
// Context grants carry temporal/watermark as caveats
|
|
217
|
+
// Context grants carry temporal/watermark as caveats.
|
|
199
218
|
temporal: grantCaveat(g, 'temporal') ?? 'from-now',
|
|
200
219
|
watermarkAt: grantCaveat(g, 'watermark_at') ?? '',
|
|
201
220
|
expiresAt: g.expiresAt,
|
|
@@ -213,7 +232,7 @@ function isBroaderGrant(a, b) {
|
|
|
213
232
|
return a.watermarkAt < b.watermarkAt;
|
|
214
233
|
}
|
|
215
234
|
/**
|
|
216
|
-
*
|
|
235
|
+
* index the caller's own live reach descriptors by scope. The reach
|
|
217
236
|
* list is already the caller's non-expired grants (holderId == principalId),
|
|
218
237
|
* so this is grant metadata the caller already holds — no protected content.
|
|
219
238
|
*/
|
|
@@ -231,17 +250,17 @@ export function indexReachByScope(reach) {
|
|
|
231
250
|
return byScope;
|
|
232
251
|
}
|
|
233
252
|
/**
|
|
234
|
-
* Put humanAttention first so MCP hosts surface it before counts
|
|
253
|
+
* Put humanAttention first so MCP hosts surface it before counts,
|
|
235
254
|
* and append readPlan last so each inbox call self-narrates the follow-up
|
|
236
|
-
* calls
|
|
255
|
+
* calls without disturbing the leading humanAttention key.
|
|
237
256
|
*
|
|
238
257
|
* When `reach` (the caller's own live grants) is passed, the read plan pins
|
|
239
|
-
* each read's covering grant
|
|
258
|
+
* each read's covering grant so the agent can present
|
|
240
259
|
* X-Context-Grant-Id without a separate discover round-trip.
|
|
241
260
|
*/
|
|
242
261
|
export function formatInboxToolResult(inbox, ack, webOrigin, activeTasks, reach, activeTasksError,
|
|
243
262
|
/**
|
|
244
|
-
* The caller's own ids
|
|
263
|
+
* The caller's own ids. Optional here alone: this result carries
|
|
245
264
|
* the session-start COUNTS and a pointer to ziggs_pending_decisions, never
|
|
246
265
|
* the decision items themselves, and a count does not depend on which party
|
|
247
266
|
* may answer. Production callers pass it regardless — if this shape ever
|
|
@@ -251,10 +270,10 @@ self = { agentId: '' }) {
|
|
|
251
270
|
const byScope = reach?.length ? indexReachByScope(reach) : undefined;
|
|
252
271
|
const { plan: readPlan, truncated: readPlanTruncated } = buildReadPlan(inbox, byScope, self);
|
|
253
272
|
const origin = resolveWebAppOrigin(webOrigin);
|
|
254
|
-
//
|
|
273
|
+
// the inbox reports session-start counts and points to
|
|
255
274
|
// ziggs_pending_decisions for the sessionChatCard — it no longer re-emits the
|
|
256
275
|
// cards, so a session start doesn't ship the same card ~6× across tools.
|
|
257
|
-
//
|
|
276
|
+
// omit `activeTasks` so counts come from inbox.tasksAwaitingMe —
|
|
258
277
|
// callers that still pass an array (or []) keep the listTasks-derived path.
|
|
259
278
|
const pending = formatPendingDecisionsPayload(inbox, origin, self, {
|
|
260
279
|
...(activeTasks !== undefined ? { activeTasks, activeTasksError } : {}),
|
|
@@ -272,7 +291,7 @@ self = { agentId: '' }) {
|
|
|
272
291
|
: {};
|
|
273
292
|
const tail = {
|
|
274
293
|
...pendingTail,
|
|
275
|
-
//
|
|
294
|
+
// always surface a task-fetch failure, even when there is nothing
|
|
276
295
|
// else actionable, so hasActiveWork:false is not read as "no tasks".
|
|
277
296
|
...(pending.activeTasksFetchError
|
|
278
297
|
? {
|
package/dist/operatorKey.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface OperatorKeyClaims {
|
|
|
7
7
|
exp?: number;
|
|
8
8
|
}
|
|
9
9
|
declare const MINT_KEY_HELP: string;
|
|
10
|
-
/** Decode operator JWT payload without verifying signature (
|
|
10
|
+
/** Decode operator JWT payload without verifying signature (boundAgentId). */
|
|
11
11
|
export declare function decodeOperatorKeyClaims(token: string): OperatorKeyClaims | null;
|
|
12
12
|
export declare function isOperatorKeyExpired(claims: OperatorKeyClaims | null): boolean;
|
|
13
13
|
/**
|
package/dist/operatorKey.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const MINT_KEY_HELP = 'Mint a key in the Ziggs app: Developer Portal → Operator keys (fleet key + set ZIGGS_AGENT_ID), ' +
|
|
2
2
|
'or open your delegate agent → Issue operator key (agent-scoped — no ZIGGS_AGENT_ID needed). ' +
|
|
3
3
|
'Docs: https://ziggsai.com/docs (Claude Code MCP tier).';
|
|
4
|
-
/** Decode operator JWT payload without verifying signature (
|
|
4
|
+
/** Decode operator JWT payload without verifying signature (boundAgentId). */
|
|
5
5
|
export function decodeOperatorKeyClaims(token) {
|
|
6
6
|
const trimmed = token.trim();
|
|
7
7
|
const parts = trimmed.split('.');
|
package/dist/paymentTools.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { type Creds } from '@ziggs-ai/api-client';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* the wallet toolset on the MCP surface, same base names
|
|
5
5
|
* as the SDK's PAYMENT_TOOLS (payment_* → ziggs_payment_*), now registered
|
|
6
6
|
* from the shared capability definitions in api-client (one schema + handler,
|
|
7
7
|
* two thin surface adapters). Safety is unchanged: money-moving calls are
|
package/dist/paymentTools.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PAYMENT_CAPABILITIES } from '@ziggs-ai/api-client';
|
|
2
2
|
import { registerCapabilities } from './capabilityAdapter.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* the wallet toolset on the MCP surface, same base names
|
|
5
5
|
* as the SDK's PAYMENT_TOOLS (payment_* → ziggs_payment_*), now registered
|
|
6
6
|
* from the shared capability definitions in api-client (one schema + handler,
|
|
7
7
|
* two thin surface adapters). Safety is unchanged: money-moving calls are
|