@ziggs-ai/ziggs-mcp 0.1.4 → 0.1.6
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/connectionCreds.d.ts +8 -0
- package/dist/connectionCreds.js +31 -0
- package/dist/inboxToolResult.d.ts +3 -0
- package/dist/inboxToolResult.js +8 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +8 -3
- package/dist/tools.js +3 -2
- package/examples/claude-ai-oauth.md +138 -0
- package/examples/cursor-remote-mcp.json +7 -0
- package/examples/cursor-remote-oauth.md +155 -0
- package/package.json +18 -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,8 @@
|
|
|
1
|
+
import type { Creds } from '@ziggs-ai/api-client';
|
|
2
|
+
import type { ZiggsMcpConfig } from './config.js';
|
|
3
|
+
export declare function parseBearerAuthorization(header: string | string[] | undefined): string;
|
|
4
|
+
/** Per-connection credentials from HTTP Authorization (ZIG-431 / ZIG-466). */
|
|
5
|
+
export declare function connectionFromBearer(bearer: string, httpBaseUrl: string, ownerUserId?: string): {
|
|
6
|
+
creds: Creds;
|
|
7
|
+
cfg: ZiggsMcpConfig;
|
|
8
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { resolveDelegateAgentId, MINT_KEY_HELP } from './operatorKey.js';
|
|
2
|
+
export function parseBearerAuthorization(header) {
|
|
3
|
+
const raw = Array.isArray(header) ? header[0] : header;
|
|
4
|
+
if (!raw?.startsWith('Bearer ')) {
|
|
5
|
+
throw new Error(`Authorization: Bearer <operator-key> required. ${MINT_KEY_HELP}`);
|
|
6
|
+
}
|
|
7
|
+
const token = raw.slice('Bearer '.length).trim();
|
|
8
|
+
if (!token) {
|
|
9
|
+
throw new Error(`empty bearer token. ${MINT_KEY_HELP}`);
|
|
10
|
+
}
|
|
11
|
+
return token;
|
|
12
|
+
}
|
|
13
|
+
/** Per-connection credentials from HTTP Authorization (ZIG-431 / ZIG-466). */
|
|
14
|
+
export function connectionFromBearer(bearer, httpBaseUrl, ownerUserId) {
|
|
15
|
+
const resolvedAgentId = resolveDelegateAgentId(bearer, undefined);
|
|
16
|
+
if (httpBaseUrl) {
|
|
17
|
+
process.env.HTTP_URL = httpBaseUrl;
|
|
18
|
+
}
|
|
19
|
+
const cfg = {
|
|
20
|
+
ZIGGS_OPERATOR_KEY: bearer,
|
|
21
|
+
ZIGGS_API_URL: httpBaseUrl,
|
|
22
|
+
HTTP_URL: httpBaseUrl,
|
|
23
|
+
ZIGGS_AGENT_ID: undefined,
|
|
24
|
+
ZIGGS_OWNER_USER_ID: ownerUserId,
|
|
25
|
+
resolvedAgentId,
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
creds: { operatorKey: bearer, agentId: resolvedAgentId },
|
|
29
|
+
cfg,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -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/server.d.ts
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { Creds } from '@ziggs-ai/api-client';
|
|
3
|
+
import type { ZiggsMcpConfig } from './config.js';
|
|
4
|
+
/** Shared MCP server factory — stdio (local) and remote HTTP (backend) reuse this. */
|
|
5
|
+
export declare function createZiggsMcpServer(creds: Creds, cfg: ZiggsMcpConfig): McpServer;
|
|
1
6
|
export declare function startStdioServer(): Promise<void>;
|
package/dist/server.js
CHANGED
|
@@ -6,14 +6,19 @@ import { credsFromConfig } from './creds.js';
|
|
|
6
6
|
import { registerZiggsTools } from './tools.js';
|
|
7
7
|
const require = createRequire(import.meta.url);
|
|
8
8
|
const { version } = require('../package.json');
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const creds = credsFromConfig(cfg);
|
|
9
|
+
/** Shared MCP server factory — stdio (local) and remote HTTP (backend) reuse this. */
|
|
10
|
+
export function createZiggsMcpServer(creds, cfg) {
|
|
12
11
|
const server = new McpServer({
|
|
13
12
|
name: 'ziggs-mcp',
|
|
14
13
|
version,
|
|
15
14
|
});
|
|
16
15
|
registerZiggsTools(server, creds, cfg);
|
|
16
|
+
return server;
|
|
17
|
+
}
|
|
18
|
+
export async function startStdioServer() {
|
|
19
|
+
const cfg = loadConfig();
|
|
20
|
+
const creds = credsFromConfig(cfg);
|
|
21
|
+
const server = createZiggsMcpServer(creds, cfg);
|
|
17
22
|
const transport = new StdioServerTransport();
|
|
18
23
|
await server.connect(transport);
|
|
19
24
|
}
|
package/dist/tools.js
CHANGED
|
@@ -2,6 +2,7 @@ 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
4
|
import { registerTrustTools } from './trustTools.js';
|
|
5
|
+
import { formatInboxToolResult } from './inboxToolResult.js';
|
|
5
6
|
function textResult(data) {
|
|
6
7
|
return {
|
|
7
8
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
@@ -209,7 +210,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
209
210
|
return toolError(e.message);
|
|
210
211
|
}
|
|
211
212
|
});
|
|
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.", {
|
|
213
|
+
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
214
|
ack: z
|
|
214
215
|
.array(z.object({
|
|
215
216
|
kind: z.enum(['chat', 'agreement', 'org']),
|
|
@@ -223,7 +224,7 @@ export function registerZiggsTools(server, creds, cfg) {
|
|
|
223
224
|
const client = new InboxClient(creds.operatorKey, creds.agentId);
|
|
224
225
|
const acked = ack?.length ? await client.ack(ack) : null;
|
|
225
226
|
const inbox = await client.getInbox();
|
|
226
|
-
return textResult(
|
|
227
|
+
return textResult(formatInboxToolResult(inbox, acked));
|
|
227
228
|
}
|
|
228
229
|
catch (e) {
|
|
229
230
|
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,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.
|
|
3
|
+
"version": "0.1.6",
|
|
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": {
|
|
@@ -8,6 +8,23 @@
|
|
|
8
8
|
},
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"types": "dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./server": {
|
|
18
|
+
"types": "./dist/server.d.ts",
|
|
19
|
+
"import": "./dist/server.js",
|
|
20
|
+
"default": "./dist/server.js"
|
|
21
|
+
},
|
|
22
|
+
"./connection-creds": {
|
|
23
|
+
"types": "./dist/connectionCreds.d.ts",
|
|
24
|
+
"import": "./dist/connectionCreds.js",
|
|
25
|
+
"default": "./dist/connectionCreds.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
11
28
|
"scripts": {
|
|
12
29
|
"build": "tsc -p tsconfig.json",
|
|
13
30
|
"prepack": "npm run build",
|
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`
|