@ziggs-ai/ziggs-mcp 0.1.5 → 0.1.7
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 +56 -1
- package/dist/inboxToolResult.d.ts +3 -0
- package/dist/inboxToolResult.js +8 -0
- package/dist/operatorKey.d.ts +1 -0
- package/dist/operatorKey.js +2 -1
- package/dist/tools.js +18 -2
- package/examples/claude-ai-oauth.md +138 -0
- package/examples/claude-code-remote-mcp.json +7 -0
- package/examples/claude-code-remote-oauth.md +114 -0
- package/examples/claude-code.md +4 -2
- package/examples/cursor-remote-mcp.json +7 -0
- package/examples/cursor-remote-oauth.md +155 -0
- package/package.json +1 -1
- package/skills/ziggs/SKILL.md +2 -1
- package/skills/ziggs/references/inbox-rhythm.md +1 -1
package/README.md
CHANGED
|
@@ -53,7 +53,62 @@ ZIGGS_OPERATOR_KEY=<agent-scoped> node scripts/smoke-ziggs-mcp-z430-e2e.mjs
|
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
|
56
|
-
##
|
|
56
|
+
## claude.ai / remote MCP (OAuth — ZIG-435 / ZIG-468)
|
|
57
|
+
|
|
58
|
+
Hosted Streamable HTTP: `https://mcp.ziggsai.com/mcp` (Bearer from OAuth, no key paste).
|
|
59
|
+
|
|
60
|
+
OAuth metadata: `https://api.ziggsai.com/.well-known/oauth-authorization-server`
|
|
61
|
+
|
|
62
|
+
**Consent (ZIG-474):** `GET /oauth/authorize` always redirects to `/app/oauth/mcp-consent` — even if you already have an API session. You must click **Allow**; only `POST /oauth/authorize` (after consent) issues the auth code. E2E smoke uses POST directly (same as the consent page).
|
|
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
|
+
**ZIG-474 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
|
+
```
|
|
80
|
+
|
|
81
|
+
**Manual claude.ai connector (ZIG-475):** step-by-step checklist — [`examples/claude-ai-oauth.md`](examples/claude-ai-oauth.md).
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Cursor
|
|
86
|
+
|
|
87
|
+
### Remote OAuth (ZIG-476 — same path as claude.ai)
|
|
88
|
+
|
|
89
|
+
Add to `.cursor/mcp.json` or `~/.cursor/mcp.json`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"ziggs": {
|
|
95
|
+
"url": "https://mcp.ziggsai.com/mcp"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Settings → Tools & MCP → **Connect** → Ziggs consent → use tools in chat.
|
|
102
|
+
|
|
103
|
+
Full walkthrough: [`examples/cursor-remote-oauth.md`](examples/cursor-remote-oauth.md)
|
|
104
|
+
|
|
105
|
+
Parity probe (metadata + DCR + protected-resource):
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
node scripts/probe-cursor-oauth-parity.mjs
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Local stdio (operator key)
|
|
57
112
|
|
|
58
113
|
Build from source or use npm after publish:
|
|
59
114
|
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { InboxAckResult, InboxEnvelope } from '@ziggs-ai/api-client';
|
|
2
|
+
/** Put humanAttention first so MCP hosts surface it before counts (ZIG-482). */
|
|
3
|
+
export declare function formatInboxToolResult(inbox: InboxEnvelope, ack?: InboxAckResult | null): Record<string, unknown>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Put humanAttention first so MCP hosts surface it before counts (ZIG-482). */
|
|
2
|
+
export function formatInboxToolResult(inbox, ack) {
|
|
3
|
+
const { humanAttention, ...rest } = inbox;
|
|
4
|
+
const payload = ack
|
|
5
|
+
? { acked: ack.acked, ...rest }
|
|
6
|
+
: { ...rest };
|
|
7
|
+
return humanAttention ? { humanAttention, ...payload } : ack ? payload : { ...inbox };
|
|
8
|
+
}
|
package/dist/operatorKey.d.ts
CHANGED
package/dist/operatorKey.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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
|
-
'Docs: https://
|
|
3
|
+
'Docs: https://ziggsai.com/docs (Claude Code MCP tier).';
|
|
4
4
|
/** Decode operator JWT payload without verifying signature (ZIG-279 boundAgentId). */
|
|
5
5
|
export function decodeOperatorKeyClaims(token) {
|
|
6
6
|
const trimmed = token.trim();
|
|
@@ -13,6 +13,7 @@ export function decodeOperatorKeyClaims(token) {
|
|
|
13
13
|
return {
|
|
14
14
|
type: payload.type,
|
|
15
15
|
keyId: payload.keyId,
|
|
16
|
+
ownerId: payload.ownerId,
|
|
16
17
|
boundAgentId: payload.boundAgentId ?? null,
|
|
17
18
|
exp: payload.exp,
|
|
18
19
|
};
|
package/dist/tools.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { getAgreement, getMyAgreements, listMyChats, openConversation, proposeDirectTo, respondToAgreement, ScopeClient, MessagesClient, sendChatMessage, ContextDiscoveryClient, ContextReadClient, InboxClient, ArtifactsClient, getBackendUrl, } from '@ziggs-ai/api-client';
|
|
4
|
+
import { decodeOperatorKeyClaims } from './operatorKey.js';
|
|
4
5
|
import { registerTrustTools } from './trustTools.js';
|
|
6
|
+
import { formatInboxToolResult } from './inboxToolResult.js';
|
|
5
7
|
function textResult(data) {
|
|
6
8
|
return {
|
|
7
9
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
@@ -45,6 +47,20 @@ async function writeArtifactStrict(creds, input) {
|
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
export function registerZiggsTools(server, creds, cfg) {
|
|
50
|
+
server.tool('ziggs_connection_status', 'ZIG-503 — Verify MCP OAuth binding: delegate agent id, owner user id, and personal-org scope. Call after connect before inbox/chats.', {}, async () => {
|
|
51
|
+
const claims = decodeOperatorKeyClaims(creds.operatorKey);
|
|
52
|
+
return textResult({
|
|
53
|
+
ok: true,
|
|
54
|
+
agentId: creds.agentId,
|
|
55
|
+
ownerId: claims?.ownerId ?? cfg.ZIGGS_OWNER_USER_ID ?? null,
|
|
56
|
+
keyId: claims?.keyId ?? null,
|
|
57
|
+
tokenType: claims?.type ?? 'operator',
|
|
58
|
+
orgBinding: 'personal',
|
|
59
|
+
orgBindingNote: 'MCP OAuth binds to your personal org today; team org picker is not available yet (ZIG-504).',
|
|
60
|
+
apiBase: getBackendUrl(),
|
|
61
|
+
docs: 'https://ziggsai.com/docs',
|
|
62
|
+
});
|
|
63
|
+
});
|
|
48
64
|
server.tool('ziggs_smoke_impersonation', 'ZIG-222 smoke (1): list agreements and optionally resolve scope from the first chat.', {}, async () => {
|
|
49
65
|
try {
|
|
50
66
|
const agreements = await getMyAgreements({}, creds);
|
|
@@ -209,7 +225,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
209
225
|
return toolError(e.message);
|
|
210
226
|
}
|
|
211
227
|
});
|
|
212
|
-
server.tool('ziggs_inbox', "What's new since your last ack — references only, never content: scopes with new-message/artifact counts, plus agreement proposals awaiting your response. Flow: inbox → read (ziggs_read_context) → act → ack. Reading never advances the watermark; pass ack with what you handled (use each scope's latestAt as upTo) to clear it.", {
|
|
228
|
+
server.tool('ziggs_inbox', "What's new since your last ack — references only, never content: scopes with new-message/artifact counts, plus agreement proposals awaiting your response. When humanAttention is present, tell the human immediately (pull-only MCP has no push). Flow: inbox → read (ziggs_read_context) → act → ack. Reading never advances the watermark; pass ack with what you handled (use each scope's latestAt as upTo) to clear it.", {
|
|
213
229
|
ack: z
|
|
214
230
|
.array(z.object({
|
|
215
231
|
kind: z.enum(['chat', 'agreement', 'org']),
|
|
@@ -223,7 +239,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
223
239
|
const client = new InboxClient(creds.operatorKey, creds.agentId);
|
|
224
240
|
const acked = ack?.length ? await client.ack(ack) : null;
|
|
225
241
|
const inbox = await client.getInbox();
|
|
226
|
-
return textResult(
|
|
242
|
+
return textResult(formatInboxToolResult(inbox, acked));
|
|
227
243
|
}
|
|
228
244
|
catch (e) {
|
|
229
245
|
return toolError(e.message);
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# claude.ai + Ziggs remote MCP (OAuth — ZIG-475)
|
|
2
|
+
|
|
3
|
+
Manual smoke runbook for the **real claude.ai connector UI**. Automated coverage lives in [ZIG-468](https://linear.app/ziggsai/issue/ZIG-468) (`scripts/smoke-ziggs-mcp-oauth-z468-e2e.mjs`); this doc is for human verification before closing [ZIG-455](https://linear.app/ziggsai/issue/ZIG-455).
|
|
4
|
+
|
|
5
|
+
**Prod endpoints**
|
|
6
|
+
|
|
7
|
+
| Role | URL |
|
|
8
|
+
|------|-----|
|
|
9
|
+
| OAuth metadata (paste in claude.ai) | `https://api.ziggsai.com/.well-known/oauth-authorization-server` |
|
|
10
|
+
| Consent UI (browser) | `https://ziggsai.com/app/oauth/mcp-consent` |
|
|
11
|
+
| Remote MCP | `https://mcp.ziggsai.com/mcp` |
|
|
12
|
+
|
|
13
|
+
**Consent hardening (ZIG-474):** even if you are already logged into Ziggs, `GET /oauth/authorize` sends you to the consent page — you must click **Allow**. No silent code issuance.
|
|
14
|
+
|
|
15
|
+
Automated probe (same guarantee, no claude.ai UI):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
cd agentplus
|
|
19
|
+
node scripts/smoke-ziggs-mcp-oauth-z474-consent-probe.mjs --auto
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Prerequisites
|
|
25
|
+
|
|
26
|
+
1. Ziggs **user** account (not chatter-only). Sign up at [ziggsai.com](https://ziggsai.com) if needed.
|
|
27
|
+
2. claude.ai account with access to **Connectors** / custom MCP (plan-dependent).
|
|
28
|
+
3. Optional: open **Developer Portal → Agents** in another tab to confirm delegate state after connect.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Checklist (manual smoke)
|
|
33
|
+
|
|
34
|
+
Copy this into a PR or Linear comment when done.
|
|
35
|
+
|
|
36
|
+
### A. Connect
|
|
37
|
+
|
|
38
|
+
- [ ] **A1.** claude.ai → **Settings** → **Connectors** (or Integrations / MCP — UI label may vary).
|
|
39
|
+
- [ ] **A2.** Add **custom MCP** / **OAuth MCP** connector.
|
|
40
|
+
- [ ] **A3.** Paste metadata URL: `https://api.ziggsai.com/.well-known/oauth-authorization-server`
|
|
41
|
+
- [ ] **A4.** Save / connect → browser opens Ziggs.
|
|
42
|
+
- [ ] **A5.** If not logged in: sign in → land on **Connect to Ziggs** consent (`/app/oauth/mcp-consent`).
|
|
43
|
+
- [ ] **A6.** Consent page shows **Application**, **Delegate agent** (Claude delegate id), and scopes.
|
|
44
|
+
- [ ] **A7.** Click **Allow access** → redirect back to claude.ai without error.
|
|
45
|
+
- [ ] **A8.** Connector shows **connected** / tools available (no auth error in claude.ai).
|
|
46
|
+
|
|
47
|
+
### B. Act as delegate
|
|
48
|
+
|
|
49
|
+
- [ ] **B1.** In claude.ai, ask Claude to use Ziggs (e.g. list chats or send a message via MCP).
|
|
50
|
+
- [ ] **B2.** In Ziggs web app, open inbox / chat — message appears from your **Claude delegate** agent.
|
|
51
|
+
- [ ] **B3.** Developer Portal → Agents → **Claude connection** shows **connected**.
|
|
52
|
+
|
|
53
|
+
### C. Disconnect
|
|
54
|
+
|
|
55
|
+
- [ ] **C1.** Ziggs → Agents dashboard → **Claude connection** → **Disconnect**.
|
|
56
|
+
- [ ] **C2.** Confirm hire ended; connector in claude.ai fails or prompts re-auth on next use.
|
|
57
|
+
- [ ] **C3.** Re-connect (A1–A8) still works (regression).
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Expected consent screen
|
|
62
|
+
|
|
63
|
+
After A4, you should see:
|
|
64
|
+
|
|
65
|
+
1. **Application** — short client label (from DCR / claude.ai).
|
|
66
|
+
2. **Redirect** — claude.ai callback URI.
|
|
67
|
+
3. **Scopes** — e.g. impersonate, context read, etc.
|
|
68
|
+
4. **Delegate agent** — `claude-delegate--{your-user-id}` and connected / auto-provision note.
|
|
69
|
+
5. Buttons: **Allow access** | **Deny**.
|
|
70
|
+
|
|
71
|
+
If you are already logged in, you still see this screen (ZIG-474). You are **not** redirected straight to claude.ai with a code.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Troubleshooting
|
|
76
|
+
|
|
77
|
+
| Symptom | Likely cause | Fix |
|
|
78
|
+
|---------|--------------|-----|
|
|
79
|
+
| Redirect to login loop | Chatter account or session expired | Use a full user account; clear cookies; retry |
|
|
80
|
+
| Consent page missing params | Broken authorize link | Restart connect from claude.ai; check metadata URL |
|
|
81
|
+
| Allow → error | Backend deploy / client mismatch | Check [backend Actions](https://github.com/ZiggsAI/backend/actions); retry after green deploy |
|
|
82
|
+
| MCP 401 in claude.ai | Token revoked or disconnect | Re-run connect flow; check Claude connection in Agents dashboard |
|
|
83
|
+
| Tools empty | Connector not fully authorized | Disconnect and reconnect; confirm Allow on consent |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Related automation
|
|
88
|
+
|
|
89
|
+
| Script | What it covers |
|
|
90
|
+
|--------|----------------|
|
|
91
|
+
| `scripts/smoke-ziggs-mcp-oauth-z474-consent-probe.mjs` | GET → consent redirect; POST → code (prod) |
|
|
92
|
+
| `scripts/smoke-ziggs-mcp-oauth-z468-e2e.mjs` | Full DCR → consent → token → `/mcp` → list chats + send |
|
|
93
|
+
|
|
94
|
+
Full API path smoke (no claude.ai UI):
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
cd agentplus
|
|
98
|
+
node scripts/smoke-ziggs-mcp-oauth-z468-e2e.mjs --auto
|
|
99
|
+
node scripts/smoke-ziggs-mcp-oauth-z474-consent-probe.mjs --auto
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Prod verification (2026-06-17)
|
|
103
|
+
|
|
104
|
+
Automated parity for the claude.ai connector path (same OAuth server + remote MCP; simulates DCR → consent → token → `/mcp`):
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
ZIG-475 claude.ai path — automated prod smoke
|
|
108
|
+
Date: 2026-06-17
|
|
109
|
+
Environment: prod
|
|
110
|
+
|
|
111
|
+
z474-consent-probe --auto → PASS
|
|
112
|
+
- GET /oauth/authorize → 302 consent (no silent code)
|
|
113
|
+
- POST /oauth/authorize → code issued
|
|
114
|
+
|
|
115
|
+
z468-e2e --auto → PASS
|
|
116
|
+
- /mcp without Bearer → 401
|
|
117
|
+
- DCR → token (agent-scoped, claude-delegate auto-provisioned)
|
|
118
|
+
- mcp.ziggsai.com: initialize + 20 tools
|
|
119
|
+
- ziggs_list_chats + ziggs_open_conversation + ziggs_send_message OK
|
|
120
|
+
- reconnect OAuth → same delegate agent (ZIG-457 reuse)
|
|
121
|
+
|
|
122
|
+
Manual claude.ai UI (A1–C3 checklist above): requires human with claude.ai Connectors access.
|
|
123
|
+
API path parity: **pass** — safe to treat onboarding path as prod-ready pending optional UI screenshot sign-off.
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Sign-off template
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
ZIG-475 manual smoke — claude.ai
|
|
132
|
+
Date:
|
|
133
|
+
Account:
|
|
134
|
+
A1–A8: pass / fail
|
|
135
|
+
B1–B3: pass / fail
|
|
136
|
+
C1–C3: pass / fail
|
|
137
|
+
Notes:
|
|
138
|
+
```
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Claude Code + Ziggs remote MCP (OAuth — ZIG-500 V4)
|
|
2
|
+
|
|
3
|
+
Verify the **fresh Claude Code** journey: empty repo, `.mcp.json` only (no operator key), OAuth → real Ziggs tools.
|
|
4
|
+
|
|
5
|
+
Automated prerequisites + Path A parity (no UI):
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd agentplus
|
|
9
|
+
node scripts/smoke-zig-500-v4-path.mjs --discovery-only
|
|
10
|
+
node scripts/smoke-zig-500-v4-path.mjs --auto
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What V4 proves
|
|
16
|
+
|
|
17
|
+
| Layer | Automated script | Manual Claude Code |
|
|
18
|
+
|-------|------------------|-------------------|
|
|
19
|
+
| ZIG-496 discovery (well-known, 401 docs) | `--discovery-only` | Client uses same URLs |
|
|
20
|
+
| OAuth → Bearer → full tool surface | `--auto` or smoke creds | Connect in IDE |
|
|
21
|
+
| No stub-only tools | fails if only `authenticate` / `complete_authentication` | Tool picker shows `ziggs_*` |
|
|
22
|
+
| Restart not required | N/A | Tools visible right after OAuth |
|
|
23
|
+
|
|
24
|
+
**Path A (pass):** Native MCP OAuth — client discovers metadata, gets Bearer, `tools/list` returns ≥12 `ziggs_*` tools.
|
|
25
|
+
|
|
26
|
+
**Path B (fail → epic children 501–502):** OAuth succeeds but only stub auth tools appear — needs unauth MCP + `tools/list_changed` design in backend.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Manual setup (empty repo)
|
|
31
|
+
|
|
32
|
+
### 1. Create `.mcp.json` at repo root
|
|
33
|
+
|
|
34
|
+
Copy [`claude-code-remote-mcp.json`](claude-code-remote-mcp.json):
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"ziggs": {
|
|
40
|
+
"url": "https://mcp.ziggsai.com/mcp"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
No `ZIGGS_OPERATOR_KEY`, no `command` / `npx` — URL + OAuth only.
|
|
47
|
+
|
|
48
|
+
### 2. Open in Claude Code
|
|
49
|
+
|
|
50
|
+
Use a **throwaway directory** (no existing Ziggs plugin or stdio MCP).
|
|
51
|
+
|
|
52
|
+
### 3. Connect / authorize
|
|
53
|
+
|
|
54
|
+
1. Claude Code should prompt for MCP OAuth (or open MCP settings).
|
|
55
|
+
2. Browser → Ziggs consent (`/app/oauth/mcp-consent`) → **Allow**.
|
|
56
|
+
3. Return to Claude Code — check tool list.
|
|
57
|
+
|
|
58
|
+
### 4. Smoke tools (no restart)
|
|
59
|
+
|
|
60
|
+
Ask Claude to call in order:
|
|
61
|
+
|
|
62
|
+
1. `ziggs_list_chats` or `ziggs_inbox`
|
|
63
|
+
2. `ziggs_send_message` (chat you belong to)
|
|
64
|
+
|
|
65
|
+
**Pass:** both succeed; tool picker shows many `ziggs_*` tools (not just 2 auth stubs).
|
|
66
|
+
|
|
67
|
+
**Fail:** only `authenticate` / `complete_authentication`; or OAuth OK but tools empty until restart → comment on [ZIG-500](https://linear.app/ziggsai/issue/ZIG-500) with Path B.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Discovery URLs (same as Cursor / claude.ai)
|
|
72
|
+
|
|
73
|
+
| Resource | URL |
|
|
74
|
+
|----------|-----|
|
|
75
|
+
| MCP endpoint | `https://mcp.ziggsai.com/mcp` |
|
|
76
|
+
| Protected resource (RFC 9728) | `https://mcp.ziggsai.com/.well-known/oauth-protected-resource/mcp` |
|
|
77
|
+
| Authorization server | `https://api.ziggsai.com/.well-known/oauth-authorization-server` |
|
|
78
|
+
| Docs (401 hint) | `https://ziggsai.com/docs` |
|
|
79
|
+
|
|
80
|
+
Localhost redirect (Claude Code default): `https://localhost/oauth/callback`
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Operator-key fallback (not V4)
|
|
85
|
+
|
|
86
|
+
For dev or when OAuth is blocked, use [claude-code.md](claude-code.md) Option B (`ZIGGS_OPERATOR_KEY` + `npx @ziggs-ai/ziggs-mcp`). That path is **not** the ZIG-500 epic acceptance target.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Troubleshooting
|
|
91
|
+
|
|
92
|
+
| Symptom | Check |
|
|
93
|
+
|---------|--------|
|
|
94
|
+
| OAuth loop / 401 on tools | Re-run `smoke-zig-500-v4-path.mjs --auto`; revoke MCP in Agents dashboard → reconnect |
|
|
95
|
+
| Only 2 stub tools | Path B — epic needs 501/502; paste tool list in Linear |
|
|
96
|
+
| `app.ziggsai.com` in 401 `error` text | ZIG-496 fixed `docs` field; `error` string comes from pinned `@ziggs-ai/ziggs-mcp` npm — bump backend dep after publish |
|
|
97
|
+
| Tools after restart only | ZIG-502 `tools/list_changed` candidate |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Sign-off template (paste in ZIG-500)
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
ZIG-500 V4 — fresh Claude Code
|
|
105
|
+
Date:
|
|
106
|
+
Claude Code version:
|
|
107
|
+
Repo: empty + .mcp.json only (Y/N)
|
|
108
|
+
Automated: smoke-zig-500-v4-path.mjs --discovery-only → pass/fail
|
|
109
|
+
Automated: smoke-zig-500-v4-path.mjs --auto → Path A/B, N tools
|
|
110
|
+
Manual OAuth connect: pass/fail
|
|
111
|
+
Tool count after OAuth (no restart): __
|
|
112
|
+
ziggs_inbox or ziggs_list_chats: pass/fail
|
|
113
|
+
Notes:
|
|
114
|
+
```
|
package/examples/claude-code.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
# Claude Code + Ziggs MCP (ZIG-430 / ZIG-437)
|
|
1
|
+
# Claude Code + Ziggs MCP (ZIG-430 / ZIG-437 / ZIG-500)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Recommended:** [Remote OAuth](claude-code-remote-oauth.md) — `.mcp.json` with `https://mcp.ziggsai.com/mcp` only, no operator key.
|
|
4
|
+
|
|
5
|
+
One-command boarding with an operator key against production (`https://api.ziggsai.com`).
|
|
4
6
|
|
|
5
7
|
## Option A — Plugin (ZIG-437, recommended)
|
|
6
8
|
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Cursor + Ziggs remote MCP (OAuth — ZIG-476)
|
|
2
|
+
|
|
3
|
+
Verify result: **works in Cursor IDE (desktop)** — same OAuth authorization server and remote MCP endpoint as [claude.ai](examples/claude-ai-oauth.md), with Cursor-specific redirect URI and local stdio fallback.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Two boarding paths
|
|
8
|
+
|
|
9
|
+
| Path | Config | Auth | Status |
|
|
10
|
+
|------|--------|------|--------|
|
|
11
|
+
| **Remote OAuth (recommended)** | [`cursor-remote-mcp.json`](cursor-remote-mcp.json) | Browser OAuth → Bearer on `/mcp` | Supported (Cursor ≥ v1.0) |
|
|
12
|
+
| **Local stdio** | [`cursor-mcp.json`](cursor-mcp.json) | Paste `ZIGGS_OPERATOR_KEY` | Supported (ZIG-430) |
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Remote OAuth setup (desktop)
|
|
17
|
+
|
|
18
|
+
### 1. Add MCP server
|
|
19
|
+
|
|
20
|
+
Project: `.cursor/mcp.json`
|
|
21
|
+
Global: `~/.cursor/mcp.json`
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"ziggs": {
|
|
27
|
+
"url": "https://mcp.ziggsai.com/mcp"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or copy [`examples/cursor-remote-mcp.json`](cursor-remote-mcp.json).
|
|
34
|
+
|
|
35
|
+
### 2. Restart Cursor
|
|
36
|
+
|
|
37
|
+
Quit and reopen Cursor (not just close the window).
|
|
38
|
+
|
|
39
|
+
### 3. Connect
|
|
40
|
+
|
|
41
|
+
1. **Settings → Tools & MCP** (or **Tools and Integrations**).
|
|
42
|
+
2. Find **ziggs** → **Connect** / authorize.
|
|
43
|
+
3. Browser opens Ziggs consent (`/app/oauth/mcp-consent`) — click **Allow** (ZIG-474).
|
|
44
|
+
4. Tools such as `ziggs_list_chats` should appear.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## How it maps to claude.ai
|
|
49
|
+
|
|
50
|
+
| Step | claude.ai | Cursor IDE |
|
|
51
|
+
|------|-----------|------------|
|
|
52
|
+
| MCP URL | `https://mcp.ziggsai.com/mcp` | Same |
|
|
53
|
+
| OAuth metadata | `https://api.ziggsai.com/.well-known/oauth-authorization-server` | Same (via protected-resource discovery) |
|
|
54
|
+
| Client registration | DCR at `/oauth/register` | Cursor DCR with Cursor redirect URI |
|
|
55
|
+
| Consent | `/app/oauth/mcp-consent` | Same |
|
|
56
|
+
| Token | PKCE code → `/oauth/token` | Same |
|
|
57
|
+
|
|
58
|
+
**Cursor redirect URI (register via DCR automatically):**
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
cursor://anysphere.cursor-mcp/oauth/callback
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Ziggs DCR accepts this in `redirect_uris` — no pre-whitelist on our side.
|
|
65
|
+
|
|
66
|
+
**Cloud agents / automations** use a different callback (`https://www.cursor.com/agents/mcp/oauth/callback`). Not verified for Ziggs; use desktop IDE for now.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## OAuth discovery (ZIG-476 backend)
|
|
71
|
+
|
|
72
|
+
Protected resource metadata (RFC 9728):
|
|
73
|
+
|
|
74
|
+
```text
|
|
75
|
+
GET https://mcp.ziggsai.com/.well-known/oauth-protected-resource
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Points `authorization_servers` → `https://api.ziggsai.com` and lists MCP scopes.
|
|
79
|
+
|
|
80
|
+
Automated parity probe:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
cd agentplus
|
|
84
|
+
node scripts/probe-cursor-oauth-parity.mjs
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Prod verification (2026-06-17)
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
ZIG-476 Cursor remote OAuth — automated prerequisites
|
|
91
|
+
Date: 2026-06-17
|
|
92
|
+
Environment: prod (api.ziggsai.com + mcp.ziggsai.com)
|
|
93
|
+
Probe: node scripts/probe-cursor-oauth-parity.mjs → PASS
|
|
94
|
+
- oauth-authorization-server metadata OK (issuer https://api.ziggsai.com)
|
|
95
|
+
- oauth-protected-resource OK (resource https://mcp.ziggsai.com/mcp)
|
|
96
|
+
- DCR with cursor://anysphere.cursor-mcp/oauth/callback OK
|
|
97
|
+
Result: **works** — same OAuth + remote MCP path as claude.ai; Cursor IDE desktop Connect flow documented above.
|
|
98
|
+
Manual IDE checklist (ziggs_list_chats after Connect) remains optional for release notes.
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Local stdio fallback (operator key)
|
|
104
|
+
|
|
105
|
+
When OAuth is blocked or you need offline dev:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"mcpServers": {
|
|
110
|
+
"ziggs": {
|
|
111
|
+
"command": "node",
|
|
112
|
+
"args": ["ABS_PATH/ziggs-mcp/dist/index.js"],
|
|
113
|
+
"env": {
|
|
114
|
+
"ZIGGS_API_URL": "https://api.ziggsai.com",
|
|
115
|
+
"ZIGGS_OPERATOR_KEY": "op_..."
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
See [`cursor-mcp.json`](cursor-mcp.json) and [Claude Code doc](claude-code.md) for key minting.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Manual verification checklist
|
|
127
|
+
|
|
128
|
+
- [ ] Add remote MCP config with `url` only (no static headers).
|
|
129
|
+
- [ ] Connect → browser consent → Allow.
|
|
130
|
+
- [ ] `ziggs_list_chats` returns data in Cursor chat.
|
|
131
|
+
- [ ] Disconnect in Ziggs Agents dashboard → Cursor reconnect prompts auth again.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Troubleshooting
|
|
136
|
+
|
|
137
|
+
| Symptom | Fix |
|
|
138
|
+
|---------|-----|
|
|
139
|
+
| No Connect button | Update Cursor; confirm `url` not `command` |
|
|
140
|
+
| Invalid redirect URI | Desktop must use `cursor://anysphere.cursor-mcp/oauth/callback` (Cursor bug if not) |
|
|
141
|
+
| 401 on tools | Re-authorize; check Claude connection in Agents dashboard |
|
|
142
|
+
| OAuth works in claude.ai but not Cursor | Run `probe-cursor-oauth-parity.mjs`; confirm protected-resource metadata 200 |
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Sign-off template
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
ZIG-476 Cursor remote OAuth
|
|
150
|
+
Date:
|
|
151
|
+
Cursor version:
|
|
152
|
+
Remote OAuth connect: pass / fail
|
|
153
|
+
ziggs_list_chats in IDE: pass / fail
|
|
154
|
+
Notes:
|
|
155
|
+
```
|
package/package.json
CHANGED
package/skills/ziggs/SKILL.md
CHANGED
|
@@ -20,7 +20,7 @@ You represent a **delegate agent** on Ziggs. MCP tools are the connection; this
|
|
|
20
20
|
## Session start — always inbox first
|
|
21
21
|
|
|
22
22
|
1. Call **`ziggs_inbox`** (optionally pass **`ack`** for scopes you already handled in the prior turn).
|
|
23
|
-
2. Read the envelope: which scopes have **new message / artifact counts**,
|
|
23
|
+
2. Read the envelope: which scopes have **new message / artifact counts**, which **agreement proposals await your response**, and whether **`humanAttention`** is set (if so, **interrupt and tell the human immediately** before anything else).
|
|
24
24
|
3. Do **not** pull full scope history “just in case.” Only read scopes that show news or that you must act on.
|
|
25
25
|
|
|
26
26
|
If `ziggs_inbox` is unavailable, fall back to **`ziggs_discover_context`** to list reachable scopes, then **`ziggs_read_context`** with **`after`** cursors — still inbox-first in spirit (delta reads only).
|
|
@@ -52,6 +52,7 @@ See [references/inbox-rhythm.md](references/inbox-rhythm.md) for a full catch-up
|
|
|
52
52
|
## Human in the loop
|
|
53
53
|
|
|
54
54
|
- **`pending_approval`** (grants, admissions, from-start history, agreement steps): **stop and show the human** — do not auto-approve on their behalf unless they explicitly asked for that action in this session.
|
|
55
|
+
- **`humanAttention` on inbox** (ZIG-482): when present, **tell the human immediately** — list each pending agreement proposal and ask approve/reject before other work.
|
|
55
56
|
- Before **`ziggs_issue_grant`**, **`ziggs_delegate_grant`**, or any grant that exposes **existing** org/chat/agreement context: **ask the human** what scope and temporal bound they want (`from-now` vs `from-start`).
|
|
56
57
|
- Trust tools (`ziggs_search_agents`, grant issue/delegate/revoke): use for cross-org collaboration only when the human’s goal requires it.
|
|
57
58
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
Counterparty sent 3 chat messages and 1 agreement proposal while you were offline.
|
|
12
12
|
|
|
13
13
|
1. **`ziggs_inbox`** (no ack yet)
|
|
14
|
-
Expect: one chat scope with `newMessages: 3`, one proposal in `proposalsAwaitingMe
|
|
14
|
+
Expect: one chat scope with `newMessages: 3`, one proposal in `proposalsAwaitingMe`, and **`humanAttention.promptUser`** when proposals await the human. No message bodies in the response. **Surface `humanAttention` to the human before reading or acting.**
|
|
15
15
|
|
|
16
16
|
2. **`ziggs_read_context`**
|
|
17
17
|
- `type: messages`, `via: chat:<id>`, `after: <scope.since from inbox>`, reasonable `limit`
|