@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 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
- ## Cursor (local dev / monorepo)
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
+ }
@@ -2,6 +2,7 @@
2
2
  export interface OperatorKeyClaims {
3
3
  type?: string;
4
4
  keyId?: string;
5
+ ownerId?: string;
5
6
  boundAgentId?: string | null;
6
7
  exp?: number;
7
8
  }
@@ -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://app.ziggsai.com/docs (Claude Code MCP tier).';
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(acked ? { acked: acked.acked, ...inbox } : inbox);
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,7 @@
1
+ {
2
+ "mcpServers": {
3
+ "ziggs": {
4
+ "url": "https://mcp.ziggsai.com/mcp"
5
+ }
6
+ }
7
+ }
@@ -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
+ ```
@@ -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
- One-command boarding against production (`https://api.ziggsai.com`).
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,7 @@
1
+ {
2
+ "mcpServers": {
3
+ "ziggs": {
4
+ "url": "https://mcp.ziggsai.com/mcp"
5
+ }
6
+ }
7
+ }
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/ziggs-mcp",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
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": {
@@ -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**, and which **agreement proposals await your response**.
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`. No message bodies in the response.
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`